From 749cd0c6262404f02b29123763d9c44229406d36 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Dec 2023 20:48:21 -0500 Subject: [PATCH 01/43] Imported Delegate and Indexer contracts and Fixed Delegate code to allow compilation --- source/delegate/LICENSE | 19 + source/delegate/README.md | 37 ++ source/delegate/contracts/Delegate.sol | 481 ++++++++++++++++++ source/delegate/contracts/DelegateFactory.sol | 89 ++++ .../contracts/interfaces/IDelegate.sol | 82 +++ .../contracts/interfaces/IDelegateFactory.sol | 36 ++ source/delegate/deploys-blocks.js | 21 + source/delegate/deploys.js | 21 + source/delegate/deploys.js.d.ts | 2 + source/delegate/hardhat.config.js | 6 + source/delegate/package.json | 43 ++ source/delegate/scripts/balances.js | 71 +++ source/delegate/scripts/deploy.js | 74 +++ source/delegate/scripts/migrate-abis/4-1-1.js | 416 +++++++++++++++ source/delegate/scripts/migrate.js | 76 +++ source/delegate/scripts/owner.js | 14 + source/delegate/scripts/verify.js | 27 + source/delegate/test/Delegate.js | 44 ++ source/delegate/tsconfig.json | 7 + source/indexer/LICENSE | 19 + source/indexer/README.md | 37 ++ source/indexer/contracts/Index.sol | 266 ++++++++++ source/indexer/contracts/Indexer.sol | 337 ++++++++++++ .../indexer/contracts/interfaces/IIndexer.sol | 96 ++++ .../interfaces/ILocatorWhitelist.sol | 21 + source/indexer/deploys-blocks.js | 21 + source/indexer/deploys.js | 21 + source/indexer/deploys.js.d.ts | 2 + source/indexer/hardhat.config.js | 6 + source/indexer/package.json | 43 ++ source/indexer/scripts/balances.js | 71 +++ source/indexer/scripts/deploy.js | 74 +++ source/indexer/scripts/migrate-abis/4-1-1.js | 416 +++++++++++++++ source/indexer/scripts/migrate.js | 76 +++ source/indexer/scripts/owner.js | 14 + source/indexer/scripts/verify.js | 27 + source/indexer/test/Indexer.js | 40 ++ source/indexer/tsconfig.json | 7 + 38 files changed, 3160 insertions(+) create mode 100644 source/delegate/LICENSE create mode 100644 source/delegate/README.md create mode 100644 source/delegate/contracts/Delegate.sol create mode 100644 source/delegate/contracts/DelegateFactory.sol create mode 100644 source/delegate/contracts/interfaces/IDelegate.sol create mode 100644 source/delegate/contracts/interfaces/IDelegateFactory.sol create mode 100644 source/delegate/deploys-blocks.js create mode 100644 source/delegate/deploys.js create mode 100644 source/delegate/deploys.js.d.ts create mode 100644 source/delegate/hardhat.config.js create mode 100644 source/delegate/package.json create mode 100644 source/delegate/scripts/balances.js create mode 100644 source/delegate/scripts/deploy.js create mode 100644 source/delegate/scripts/migrate-abis/4-1-1.js create mode 100644 source/delegate/scripts/migrate.js create mode 100644 source/delegate/scripts/owner.js create mode 100644 source/delegate/scripts/verify.js create mode 100644 source/delegate/test/Delegate.js create mode 100644 source/delegate/tsconfig.json create mode 100644 source/indexer/LICENSE create mode 100644 source/indexer/README.md create mode 100644 source/indexer/contracts/Index.sol create mode 100644 source/indexer/contracts/Indexer.sol create mode 100644 source/indexer/contracts/interfaces/IIndexer.sol create mode 100644 source/indexer/contracts/interfaces/ILocatorWhitelist.sol create mode 100644 source/indexer/deploys-blocks.js create mode 100644 source/indexer/deploys.js create mode 100644 source/indexer/deploys.js.d.ts create mode 100644 source/indexer/hardhat.config.js create mode 100644 source/indexer/package.json create mode 100644 source/indexer/scripts/balances.js create mode 100644 source/indexer/scripts/deploy.js create mode 100644 source/indexer/scripts/migrate-abis/4-1-1.js create mode 100644 source/indexer/scripts/migrate.js create mode 100644 source/indexer/scripts/owner.js create mode 100644 source/indexer/scripts/verify.js create mode 100644 source/indexer/test/Indexer.js create mode 100644 source/indexer/tsconfig.json diff --git a/source/delegate/LICENSE b/source/delegate/LICENSE new file mode 100644 index 000000000..25fb212c5 --- /dev/null +++ b/source/delegate/LICENSE @@ -0,0 +1,19 @@ +Copyright 2023 AirSwap + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/source/delegate/README.md b/source/delegate/README.md new file mode 100644 index 000000000..37de1296a --- /dev/null +++ b/source/delegate/README.md @@ -0,0 +1,37 @@ +# Pool + +[AirSwap](https://www.airswap.io/) is an open-source peer-to-peer trading network. + +[![Discord](https://img.shields.io/discord/590643190281928738.svg)](https://discord.gg/ecQbV7H) +[![License](https://img.shields.io/badge/License-MIT-blue)](https://opensource.org/licenses/MIT) +![Twitter Follow](https://img.shields.io/twitter/follow/airswap?style=social) + +## Resources + +- About → https://about.airswap.io/ +- Website → https://www.airswap.io/ +- Twitter → https://twitter.com/airswap +- Chat → https://chat.airswap.io/ + +## Usage + +:warning: This package may contain unaudited code. For all AirSwap contract deployments see [Deployed Contracts](https://about.airswap.io/technology/deployments). + +## Commands + +Environment variables are set in an `.env` file in the repository root. + +| Command | Description | +| :--------------- | :--------------------------------------- | +| `yarn` | Install dependencies | +| `yarn clean` | Delete the contract `build` folder | +| `yarn compile` | Compile all contracts to `build` folder | +| `yarn coverage` | Report test coverage | +| `yarn test` | Run all tests in `test` folder | +| `yarn test:ci` | Run CI tests in `test` folder | +| `yarn deploy` | Deploy on a network using --network flag | +| `yarn verify` | Verify on a network using --network flag | + +## Running Tests + +:bulb: Prior to testing locally, run `yarn compile` in the `airswap-protocols` project root to build required artifacts. diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol new file mode 100644 index 000000000..de37acb55 --- /dev/null +++ b/source/delegate/contracts/Delegate.sol @@ -0,0 +1,481 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +import "./interfaces/IDelegate.sol"; +import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; +import "@airswap/indexer/contracts/interfaces/IIndexer.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/** + * @title Delegate: Deployable Trading Rules for the AirSwap Network + * @notice Supports fungible tokens (ERC-20) + * @dev inherits IDelegate, Ownable uses SafeMath library + */ +contract Delegate is IDelegate, Ownable { + using SafeMath for uint256; + + // The Swap contract to be used to settle trades + ISwapERC20 public swapContract; + + // The Indexer to stake intent to trade on + IIndexer public indexer; + + // Maximum integer for token transfer approval + uint256 internal constant MAX_INT = 2 ** 256 - 1; + + // Address holding tokens that will be trading through this delegate + address public tradeWallet; + + // Mapping of senderToken to signerToken for rule lookup + mapping(address => mapping(address => Rule)) public rules; + + // ERC-20 (fungible token) interface identifier (ERC-165) + bytes4 internal constant ERC20_INTERFACE_ID = 0x36372b07; + + // The protocol identifier for setting intents on an Index + bytes2 public protocol; + + /** + * @notice Contract Constructor + * @dev owner defaults to msg.sender if delegateContractOwner is provided as address(0) + * @param delegateSwap address Swap contract the delegate will deploy with + * @param delegateIndexer address Indexer contract the delegate will deploy with + * @param delegateContractOwner address Owner of the delegate + * @param delegateTradeWallet address Wallet the delegate will trade from + * @param delegateProtocol bytes2 The protocol identifier for Delegate contracts + */ + constructor( + ISwapERC20 delegateSwap, + IIndexer delegateIndexer, + address delegateContractOwner, + address delegateTradeWallet, + bytes2 delegateProtocol + ) public { + swapContract = delegateSwap; + indexer = delegateIndexer; + protocol = delegateProtocol; + + // If no delegate owner is provided, the deploying address is the owner. + if (delegateContractOwner != address(0)) { + transferOwnership(delegateContractOwner); + } + + // If no trade wallet is provided, the owner's wallet is the trade wallet. + if (delegateTradeWallet != address(0)) { + tradeWallet = delegateTradeWallet; + } else { + tradeWallet = owner(); + } + + // Ensure that the indexer can pull funds from delegate account. + require( + IERC20(indexer.stakingToken()).approve(address(indexer), MAX_INT), + "STAKING_APPROVAL_FAILED" + ); + } + + /** + * @notice Set a Trading Rule + * @dev only callable by the owner of the contract + * @dev 1 senderToken = priceCoef * 10^(-priceExp) * signerToken + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + * @param maxSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param priceCoef uint256 Whole number that will be multiplied by 10^(-priceExp) - the price coefficient + * @param priceExp uint256 Exponent of the price to indicate location of the decimal priceCoef * 10^(-priceExp) + */ + function setRule( + address senderToken, + address signerToken, + uint256 maxSenderAmount, + uint256 priceCoef, + uint256 priceExp + ) external onlyOwner { + _setRule(senderToken, signerToken, maxSenderAmount, priceCoef, priceExp); + } + + /** + * @notice Unset a Trading Rule + * @dev only callable by the owner of the contract, removes from a mapping + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + */ + function unsetRule( + address senderToken, + address signerToken + ) external onlyOwner { + _unsetRule(senderToken, signerToken); + } + + /** + * @notice sets a rule on the delegate and an intent on the indexer + * @dev only callable by owner + * @dev delegate needs to be given allowance from msg.sender for the newStakeAmount + * @dev swap needs to be given permission to move funds from the delegate + * @param senderToken address Token the delgeate will send + * @param signerToken address Token the delegate will receive + * @param rule Rule Rule to set on a delegate + * @param newStakeAmount uint256 Amount to stake for an intent + */ + function setRuleAndIntent( + address senderToken, + address signerToken, + Rule calldata rule, + uint256 newStakeAmount + ) external onlyOwner { + _setRule( + senderToken, + signerToken, + rule.maxSenderAmount, + rule.priceCoef, + rule.priceExp + ); + + // get currentAmount staked or 0 if never staked + uint256 oldStakeAmount = indexer.getStakedAmount( + address(this), + signerToken, + senderToken, + protocol + ); + if (oldStakeAmount == newStakeAmount && oldStakeAmount > 0) { + return; // forgo trying to reset intent with non-zero same stake amount + } else if (oldStakeAmount < newStakeAmount) { + // transfer only the difference from the sender to the Delegate. + require( + IERC20(indexer.stakingToken()).transferFrom( + msg.sender, + address(this), + newStakeAmount - oldStakeAmount + ), + "STAKING_TRANSFER_FAILED" + ); + } + + indexer.setIntent( + signerToken, + senderToken, + protocol, + newStakeAmount, + bytes32(uint256(uint160(address(this))) << 96) //NOTE: this will pad 0's to the right + ); + + if (oldStakeAmount > newStakeAmount) { + // return excess stake back + require( + IERC20(indexer.stakingToken()).transfer( + msg.sender, + oldStakeAmount - newStakeAmount + ), + "STAKING_RETURN_FAILED" + ); + } + } + + /** + * @notice unsets a rule on the delegate and removes an intent on the indexer + * @dev only callable by owner + * @param senderToken address Maker token in the token pair for rules and intents + * @param signerToken address Taker token in the token pair for rules and intents + */ + function unsetRuleAndIntent( + address senderToken, + address signerToken + ) external onlyOwner { + _unsetRule(senderToken, signerToken); + + // Query the indexer for the amount staked. + uint256 stakedAmount = indexer.getStakedAmount( + address(this), + signerToken, + senderToken, + protocol + ); + indexer.unsetIntent(signerToken, senderToken, protocol); + + // Upon unstaking, the Delegate will be given the staking amount. + // This is returned to the msg.sender. + if (stakedAmount > 0) { + require( + IERC20(indexer.stakingToken()).transfer(msg.sender, stakedAmount), + "STAKING_RETURN_FAILED" + ); + } + } + + /** + * @notice Provide an Order + * @dev Rules get reset with new maxSenderAmount + * @param order Types.Order Order a user wants to submit to Swap. + */ + function provideOrder(ISwapERC20.OrderERC20 calldata order) external { + Rule memory rule = rules[order.senderToken][order.signerToken]; + + require(order.v != 0, "SIGNATURE_MUST_BE_SENT"); + + // Ensure the order is for the trade wallet. + require(order.senderWallet == tradeWallet, "SENDER_WALLET_INVALID"); + + // Ensure the tokens are valid ERC20 tokens. + // require( + // order.signer.kind == ERC20_INTERFACE_ID, + // "SIGNER_KIND_MUST_BE_ERC20" + // ); + + // require( + // order.sender.kind == ERC20_INTERFACE_ID, + // "SENDER_KIND_MUST_BE_ERC20" + // ); + + // Ensure that a rule exists. + require(rule.maxSenderAmount != 0, "TOKEN_PAIR_INACTIVE"); + + // Ensure the order does not exceed the maximum amount. + require(order.senderAmount <= rule.maxSenderAmount, "AMOUNT_EXCEEDS_MAX"); + + // Ensure the order is priced according to the rule. + require( + order.senderAmount <= + _calculateSenderAmount( + order.signerAmount, + rule.priceCoef, + rule.priceExp + ), + "PRICE_INVALID" + ); + + // Overwrite the rule with a decremented maxSenderAmount. + rules[order.senderToken][order.signerToken] = Rule({ + maxSenderAmount: (rule.maxSenderAmount).sub(order.senderAmount), + priceCoef: rule.priceCoef, + priceExp: rule.priceExp + }); + + // Perform the swap. + swapContract.swap( + order.senderWallet, + order.nonce, + order.expiry, + order.signerWallet, + order.signerToken, + order.signerAmount, + order.senderToken, + order.senderAmount, + order.v, + order.r, + order.s + ); + + emit ProvideOrder( + owner(), + tradeWallet, + order.senderToken, + order.signerToken, + order.senderAmount, + rule.priceCoef, + rule.priceExp + ); + } + + /** + * @notice Set a new trade wallet + * @param newTradeWallet address Address of the new trade wallet + */ + function setTradeWallet(address newTradeWallet) external onlyOwner { + require(newTradeWallet != address(0), "TRADE_WALLET_REQUIRED"); + tradeWallet = newTradeWallet; + } + + /** + * @notice Get a Signer-Side Quote from the Delegate + * @param senderAmount uint256 Amount of ERC-20 token the delegate would send + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + * @return signerAmount uint256 signerAmount Amount of ERC-20 token the consumer would send + */ + function getSignerSideQuote( + uint256 senderAmount, + address senderToken, + address signerToken + ) external view returns (uint256 signerAmount) { + Rule memory rule = rules[senderToken][signerToken]; + + // Ensure that a rule exists. + if (rule.maxSenderAmount > 0) { + // Ensure the senderAmount does not exceed maximum for the rule. + if (senderAmount <= rule.maxSenderAmount) { + signerAmount = _calculateSignerAmount( + senderAmount, + rule.priceCoef, + rule.priceExp + ); + + // Return the quote. + return signerAmount; + } + } + return 0; + } + + /** + * @notice Get a Sender-Side Quote from the Delegate + * @param signerAmount uint256 Amount of ERC-20 token the consumer would send + * @param signerToken address Address of an ERC-20 token the consumer would send + * @param senderToken address Address of an ERC-20 token the delegate would send + * @return senderAmount uint256 Amount of ERC-20 token the delegate would send + */ + function getSenderSideQuote( + uint256 signerAmount, + address signerToken, + address senderToken + ) external view returns (uint256 senderAmount) { + Rule memory rule = rules[senderToken][signerToken]; + + // Ensure that a rule exists. + if (rule.maxSenderAmount > 0) { + // Calculate the senderAmount. + senderAmount = _calculateSenderAmount( + signerAmount, + rule.priceCoef, + rule.priceExp + ); + + // Ensure the senderAmount does not exceed the maximum trade amount. + if (senderAmount <= rule.maxSenderAmount) { + return senderAmount; + } + } + return 0; + } + + /** + * @notice Get a Maximum Quote from the Delegate + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + * @return senderAmount uint256 Amount the delegate would send + * @return signerAmount uint256 Amount the consumer would send + */ + function getMaxQuote( + address senderToken, + address signerToken + ) external view returns (uint256 senderAmount, uint256 signerAmount) { + Rule memory rule = rules[senderToken][signerToken]; + + senderAmount = rule.maxSenderAmount; + + // Ensure that a rule exists. + if (senderAmount > 0) { + // calculate the signerAmount + signerAmount = _calculateSignerAmount( + senderAmount, + rule.priceCoef, + rule.priceExp + ); + + // Return the maxSenderAmount and calculated signerAmount. + return (senderAmount, signerAmount); + } + return (0, 0); + } + + /** + * @notice Set a Trading Rule + * @dev only callable by the owner of the contract + * @dev 1 senderToken = priceCoef * 10^(-priceExp) * signerToken + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + * @param maxSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param priceCoef uint256 Whole number that will be multiplied by 10^(-priceExp) - the price coefficient + * @param priceExp uint256 Exponent of the price to indicate location of the decimal priceCoef * 10^(-priceExp) + */ + function _setRule( + address senderToken, + address signerToken, + uint256 maxSenderAmount, + uint256 priceCoef, + uint256 priceExp + ) internal { + require(priceCoef > 0, "PRICE_COEF_INVALID"); + rules[senderToken][signerToken] = Rule({ + maxSenderAmount: maxSenderAmount, + priceCoef: priceCoef, + priceExp: priceExp + }); + + emit SetRule( + owner(), + senderToken, + signerToken, + maxSenderAmount, + priceCoef, + priceExp + ); + } + + /** + * @notice Unset a Trading Rule + * @param senderToken address Address of an ERC-20 token the delegate would send + * @param signerToken address Address of an ERC-20 token the consumer would send + */ + function _unsetRule(address senderToken, address signerToken) internal { + // using non-zero rule.priceCoef for rule existence check + if (rules[senderToken][signerToken].priceCoef > 0) { + // Delete the rule. + delete rules[senderToken][signerToken]; + emit UnsetRule(owner(), senderToken, signerToken); + } + } + + /** + * @notice Calculate the signer amount for a given sender amount and price + * @param senderAmount uint256 The amount the delegate would send in the swap + * @param priceCoef uint256 Coefficient of the token price defined in the rule + * @param priceExp uint256 Exponent of the token price defined in the rule + */ + function _calculateSignerAmount( + uint256 senderAmount, + uint256 priceCoef, + uint256 priceExp + ) internal pure returns (uint256 signerAmount) { + // Calculate the signer amount using the price formula + uint256 multiplier = senderAmount.mul(priceCoef); + signerAmount = multiplier.div(10 ** priceExp); + + // If the div rounded down, round up + if (multiplier.mod(10 ** priceExp) > 0) { + signerAmount++; + } + } + + /** + * @notice Calculate the sender amount for a given signer amount and price + * @param signerAmount uint256 The amount the signer would send in the swap + * @param priceCoef uint256 Coefficient of the token price defined in the rule + * @param priceExp uint256 Exponent of the token price defined in the rule + */ + function _calculateSenderAmount( + uint256 signerAmount, + uint256 priceCoef, + uint256 priceExp + ) internal pure returns (uint256 senderAmount) { + // Calculate the sender anount using the price formula + senderAmount = signerAmount.mul(10 ** priceExp).div(priceCoef); + } +} diff --git a/source/delegate/contracts/DelegateFactory.sol b/source/delegate/contracts/DelegateFactory.sol new file mode 100644 index 000000000..a53570dd5 --- /dev/null +++ b/source/delegate/contracts/DelegateFactory.sol @@ -0,0 +1,89 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +import "./Delegate.sol"; +import "./interfaces/IDelegateFactory.sol"; +import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; +import "@airswap/indexer/contracts/interfaces/ILocatorWhitelist.sol"; +import "@airswap/indexer/contracts/interfaces/IIndexer.sol"; + +contract DelegateFactory is IDelegateFactory, ILocatorWhitelist { + // Mapping specifying whether an address was deployed by this factory + mapping(address => bool) internal _deployedAddresses; + + // The swap and indexer contracts to use in the deployment of Delegates + ISwapERC20 public swapContract; + IIndexer public indexerContract; + bytes2 public protocol; + + /** + * @notice Create a new DelegateFactory contract + * @dev swapContract is unable to be changed after the factory sets it + * @param factorySwapContract address Swap contract the delegate will deploy with + * @param factoryIndexerContract address Indexer contract the delegate will deploy with + * @param factoryProtocol bytes2 Protocol type of the delegates the factory deploys + */ + constructor( + ISwapERC20 factorySwapContract, + IIndexer factoryIndexerContract, + bytes2 factoryProtocol + ) public { + swapContract = factorySwapContract; + indexerContract = factoryIndexerContract; + protocol = factoryProtocol; + } + + /** + * @param delegateTradeWallet address Wallet the delegate will trade from + * @return delegateContractAddress address Address of the delegate contract created + */ + function createDelegate( + address delegateTradeWallet + ) external returns (address delegateContractAddress) { + delegateContractAddress = address( + new Delegate( + swapContract, + indexerContract, + msg.sender, + delegateTradeWallet, + protocol + ) + ); + _deployedAddresses[delegateContractAddress] = true; + + emit CreateDelegate( + delegateContractAddress, + address(swapContract), + address(indexerContract), + msg.sender, + delegateTradeWallet + ); + + return delegateContractAddress; + } + + /** + * @notice To check whether a locator was deployed + * @dev Implements ILocatorWhitelist.has + * @param locator bytes32 Locator of the delegate in question + * @return bool True if the delegate was deployed by this contract + */ + function has(bytes32 locator) external view returns (bool) { + return _deployedAddresses[address(bytes20(locator))]; + } +} diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol new file mode 100644 index 000000000..f4ab9f4f9 --- /dev/null +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -0,0 +1,82 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; + +pragma solidity 0.8.17; + +interface IDelegate { + struct Rule { + uint256 maxSenderAmount; // The maximum amount of ERC-20 token the delegate would send + uint256 priceCoef; // Number to be multiplied by 10^(-priceExp) - the price coefficient + uint256 priceExp; // Indicates location of the decimal priceCoef * 10^(-priceExp) + } + + event SetRule( + address indexed owner, + address indexed senderToken, + address indexed signerToken, + uint256 maxSenderAmount, + uint256 priceCoef, + uint256 priceExp + ); + + event UnsetRule( + address indexed owner, + address indexed senderToken, + address indexed signerToken + ); + + event ProvideOrder( + address indexed owner, + address tradeWallet, + address indexed senderToken, + address indexed signerToken, + uint256 senderAmount, + uint256 priceCoef, + uint256 priceExp + ); + + function setRule( + address senderToken, + address signerToken, + uint256 maxSenderAmount, + uint256 priceCoef, + uint256 priceExp + ) external; + + function unsetRule(address senderToken, address signerToken) external; + + function provideOrder(ISwapERC20.OrderERC20 calldata order) external; + + function getSignerSideQuote( + uint256 senderAmount, + address senderToken, + address signerToken + ) external view returns (uint256 signerAmount); + + function getSenderSideQuote( + uint256 signerAmount, + address signerToken, + address senderToken + ) external view returns (uint256 senderAmount); + + function getMaxQuote( + address senderToken, + address signerToken + ) external view returns (uint256 senderAmount, uint256 signerAmount); + + function tradeWallet() external view returns (address); +} diff --git a/source/delegate/contracts/interfaces/IDelegateFactory.sol b/source/delegate/contracts/interfaces/IDelegateFactory.sol new file mode 100644 index 000000000..1558d9987 --- /dev/null +++ b/source/delegate/contracts/interfaces/IDelegateFactory.sol @@ -0,0 +1,36 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +interface IDelegateFactory { + event CreateDelegate( + address indexed delegateContract, + address swapContract, + address indexerContract, + address indexed delegateContractOwner, + address delegateTradeWallet + ); + + /** + * @notice Deploy a trusted delegate contract + * @param delegateTradeWallet the wallet the delegate will trade from + * @return delegateContractAddress address of the delegate contract created + */ + function createDelegate( + address delegateTradeWallet + ) external returns (address delegateContractAddress); +} diff --git a/source/delegate/deploys-blocks.js b/source/delegate/deploys-blocks.js new file mode 100644 index 000000000..490b26825 --- /dev/null +++ b/source/delegate/deploys-blocks.js @@ -0,0 +1,21 @@ +module.exports = { + 1: 18337329, + 5: 9854680, + 30: 5717948, + 31: 4378661, + 40: 305834078, + 41: 262335361, + 56: 32550529, + 97: 34150670, + 137: 48645401, + 8453: 5180096, + 42161: 140046382, + 43113: 26720218, + 43114: 36367783, + 59140: 1711053, + 59144: 619127, + 80001: 41133390, + 84531: 10978032, + 421613: 47402006, + 11155111: 4509265, +} diff --git a/source/delegate/deploys.js b/source/delegate/deploys.js new file mode 100644 index 000000000..e7896c009 --- /dev/null +++ b/source/delegate/deploys.js @@ -0,0 +1,21 @@ +module.exports = { + 1: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 5: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 30: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 31: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 40: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 41: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 56: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 97: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 137: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 8453: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 42161: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 43113: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 43114: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 59140: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 59144: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 80001: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 84531: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 421613: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 11155111: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', +} diff --git a/source/delegate/deploys.js.d.ts b/source/delegate/deploys.js.d.ts new file mode 100644 index 000000000..31683c18a --- /dev/null +++ b/source/delegate/deploys.js.d.ts @@ -0,0 +1,2 @@ +declare module '@airswap/pool/deploys.js' +declare module '@airswap/pool/deploys-blocks.js' diff --git a/source/delegate/hardhat.config.js b/source/delegate/hardhat.config.js new file mode 100644 index 000000000..4b553c55b --- /dev/null +++ b/source/delegate/hardhat.config.js @@ -0,0 +1,6 @@ +module.exports = { + typechain: { + outDir: 'typechain', + }, + ...require('../../hardhat.config.js'), +} diff --git a/source/delegate/package.json b/source/delegate/package.json new file mode 100644 index 000000000..5fa515b23 --- /dev/null +++ b/source/delegate/package.json @@ -0,0 +1,43 @@ +{ + "name": "@airswap/delegate", + "version": "4.1.4", + "description": "AirSwap: Trade intent delegates", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/airswap/airswap-protocols" + }, + "files": [ + "./build", + "./typechain", + "./deploys.js", + "./deploys-blocks.js", + "./deploys.js.d.ts" + ], + "scripts": { + "clean": "rm -rf ./cache && rm -rf ./build && rm -rf ./typechain", + "compile": "hardhat compile; yarn typechain", + "typechain": "tsc -b", + "coverage": "hardhat coverage", + "test": "hardhat test", + "test:ci": "hardhat test", + "deploy": "hardhat run ./scripts/deploy.js", + "verify": "hardhat run ./scripts/verify.js", + "owners": "hardhat run ./scripts/owner.js", + "migrate": "hardhat run ./scripts/migrate.js", + "balances": "hardhat run ./scripts/balances.js" + }, + "dependencies": { + "@openzeppelin/contracts": "^4.8.3" + }, + "devDependencies": { + "@airswap/constants": "4.1.6", + "@airswap/metadata": "4.1.12", + "@airswap/types": "4.1.1", + "@airswap/utils": "4.1.8", + "prompt-confirm": "^2.0.4" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/source/delegate/scripts/balances.js b/source/delegate/scripts/balances.js new file mode 100644 index 000000000..f1bd5ad48 --- /dev/null +++ b/source/delegate/scripts/balances.js @@ -0,0 +1,71 @@ +const { ethers } = require('hardhat') +const { getKnownTokens } = require('@airswap/metadata') +const { chainNames, ChainIds } = require('@airswap/constants') +const BalanceChecker = require('@airswap/balances/build/contracts/BalanceChecker.sol/BalanceChecker.json') +const balancesDeploys = require('@airswap/balances/deploys.js') +const poolDeploys = require('../deploys.js') + +async function main() { + const [account] = await ethers.getSigners() + const chainId = await account.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log('Account:', account.address) + console.log('Network:', chainNames[chainId].toUpperCase()) + console.log('\nPool:', poolDeploys[chainId]) + + if (!balancesDeploys[chainId]) { + throw new Error('Unable to check balances on this chain.') + } + + const tokens = (await getKnownTokens(Number(chainId))).tokens + + let count = tokens.length + const addresses = [] + while (count--) { + if (ethers.utils.isAddress(tokens[count].address)) { + addresses.push(tokens[count].address.toLowerCase()) + } + } + + console.log(`\nScanning non-zero balances for ${tokens.length} tokens...\n`) + + const balancesContract = new ethers.Contract( + balancesDeploys[chainId], + BalanceChecker.abi, + account.provider + ) + + const chunk = 750 + let balances = [] + let index = 0 + count = addresses.length + while (index < count) { + balances = balances.concat( + await balancesContract.walletBalances( + poolDeploys[chainId], + addresses.slice(index, index + chunk) + ) + ) + index += chunk + } + + const result = [] + for (let i = 0; i < balances.length; i++) { + if (!balances[i].eq(0)) { + result.push(addresses[i]) + } + } + + console.log('Non-zero balances in', result.length, 'tokens:\n') + console.log(JSON.stringify(result)) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/delegate/scripts/deploy.js b/source/delegate/scripts/deploy.js new file mode 100644 index 000000000..abfe460a4 --- /dev/null +++ b/source/delegate/scripts/deploy.js @@ -0,0 +1,74 @@ +/* eslint-disable no-console */ +const fs = require('fs') +const prettier = require('prettier') +const Confirm = require('prompt-confirm') +const { ethers, run } = require('hardhat') +const { chainLabels, chainNames, ChainIds } = require('@airswap/constants') +const { getReceiptUrl } = require('@airswap/utils') +const poolDeploys = require('../deploys.js') +const poolBlocks = require('../deploys-blocks.js') + +async function main() { + await run('compile') + const config = await prettier.resolveConfig('../deploys.js') + + const [deployer] = await ethers.getSigners() + const gasPrice = await deployer.getGasPrice() + const chainId = await deployer.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log(`Deployer: ${deployer.address}`) + console.log(`Network: ${chainNames[chainId].toUpperCase()}`) + console.log(`Gas price: ${gasPrice / 10 ** 9} gwei\n`) + + const scale = 10 + const max = 100 + + const prompt = new Confirm('Proceed to deploy?') + if (await prompt.run()) { + const poolFactory = await ethers.getContractFactory('Pool') + const poolContract = await poolFactory.deploy(scale, max, { + gasPrice, + }) + console.log( + 'Deploying...', + getReceiptUrl(chainId, poolContract.deployTransaction.hash) + ) + await poolContract.deployed() + + poolDeploys[chainId] = poolContract.address + fs.writeFileSync( + './deploys.js', + prettier.format( + `module.exports = ${JSON.stringify(poolDeploys, null, '\t')}`, + { ...config, parser: 'babel' } + ) + ) + poolBlocks[chainId] = ( + await poolContract.deployTransaction.wait() + ).blockNumber + fs.writeFileSync( + './deploys-blocks.js', + prettier.format( + `module.exports = ${JSON.stringify(poolBlocks, null, '\t')}`, + { ...config, parser: 'babel' } + ) + ) + console.log(`Deployed: ${poolDeploys[chainId]} @ ${poolBlocks[chainId]}`) + + console.log( + `\nVerify with "yarn verify --network ${chainLabels[ + chainId + ].toLowerCase()}"\n` + ) + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/delegate/scripts/migrate-abis/4-1-1.js b/source/delegate/scripts/migrate-abis/4-1-1.js new file mode 100644 index 000000000..27293305e --- /dev/null +++ b/source/delegate/scripts/migrate-abis/4-1-1.js @@ -0,0 +1,416 @@ +module.exports = { + abi: [ + { + inputs: [ + { internalType: 'uint256', name: '_scale', type: 'uint256' }, + { internalType: 'uint256', name: '_max', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'AddressInvalid', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'AdminNotSet', + type: 'error', + }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'AmountInsufficient', + type: 'error', + }, + { inputs: [], name: 'ClaimAlreadyUsed', type: 'error' }, + { inputs: [], name: 'ClaimsNotProvided', type: 'error' }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'MaxTooHigh', + type: 'error', + }, + { + inputs: [ + { internalType: 'bytes32', name: '', type: 'bytes32' }, + { internalType: 'bytes32', name: '', type: 'bytes32' }, + ], + name: 'ProofInvalid', + type: 'error', + }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'ScaleTooHigh', + type: 'error', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'TreeNotEnabled', + type: 'error', + }, + { inputs: [], name: 'Unauthorized', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address[]', + name: 'tokens', + type: 'address[]', + }, + { + indexed: false, + internalType: 'address', + name: 'dest', + type: 'address', + }, + ], + name: 'DrainTo', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bytes32', + name: 'tree', + type: 'bytes32', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'root', + type: 'bytes32', + }, + ], + name: 'Enable', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferStarted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'admin', + type: 'address', + }, + ], + name: 'SetAdmin', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'max', + type: 'uint256', + }, + ], + name: 'SetMax', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'scale', + type: 'uint256', + }, + ], + name: 'SetScale', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'admin', + type: 'address', + }, + ], + name: 'UnsetAdmin', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'tree', + type: 'bytes32', + }, + ], + name: 'UseClaim', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'Withdraw', + type: 'event', + }, + { + inputs: [], + name: 'acceptOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'admins', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: '_value', type: 'uint256' }, + { internalType: 'address', name: '_token', type: 'address' }, + ], + name: 'calculate', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '', type: 'bytes32' }, + { internalType: 'address', name: '', type: 'address' }, + ], + name: 'claimed', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address[]', name: '_tokens', type: 'address[]' }, + { internalType: 'address', name: '_dest', type: 'address' }, + ], + name: 'drainTo', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + ], + name: 'enable', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + { internalType: 'address[]', name: '_accounts', type: 'address[]' }, + ], + name: 'enableAndSetClaimed', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '_account', type: 'address' }, + { internalType: 'bytes32[]', name: '_trees', type: 'bytes32[]' }, + ], + name: 'getStatus', + outputs: [{ internalType: 'bool[]', name: '', type: 'bool[]' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'max', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'pendingOwner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'rootsByTree', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'scale', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], + name: 'setAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: '_max', type: 'uint256' }], + name: 'setMax', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: '_scale', type: 'uint256' }], + name: 'setScale', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], + name: 'unsetAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '_claimant', type: 'address' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + { internalType: 'uint256', name: '_value', type: 'uint256' }, + { internalType: 'bytes32[]', name: '_proof', type: 'bytes32[]' }, + ], + name: 'verify', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'bytes32', name: 'tree', type: 'bytes32' }, + { internalType: 'uint256', name: 'value', type: 'uint256' }, + { internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' }, + ], + internalType: 'struct IPool.Claim[]', + name: '_claims', + type: 'tuple[]', + }, + { internalType: 'address', name: '_token', type: 'address' }, + { internalType: 'uint256', name: '_minimum', type: 'uint256' }, + { internalType: 'address', name: '_recipient', type: 'address' }, + ], + name: 'withdraw', + outputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], +} diff --git a/source/delegate/scripts/migrate.js b/source/delegate/scripts/migrate.js new file mode 100644 index 000000000..0bc28adcb --- /dev/null +++ b/source/delegate/scripts/migrate.js @@ -0,0 +1,76 @@ +const Confirm = require('prompt-confirm') +const { ethers } = require('hardhat') +const { chainNames, ChainIds } = require('@airswap/constants') +const { getReceiptUrl } = require('@airswap/utils') + +const { Pool__factory } = require('../typechain/factories/contracts') +const { abi } = require('./migrate-abis/4-1-1.js') +const deploys = require('../deploys.js') + +const CONFIRMATIONS = 2 +const PREVIOUS_POOL = '0xEEcD248D977Fd4D392915b4AdeF8154BA3aE9c02' +const NEW_POOL = '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11' + +async function main() { + const [account] = await ethers.getSigners() + const chainId = await account.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log(`Account: ${account.address}`) + console.log(`Network: ${chainNames[chainId].toUpperCase()}\n`) + console.log(`From-pool: ${PREVIOUS_POOL}`) + console.log(`To-pool: ${NEW_POOL}`) + + const previousPool = new ethers.Contract(PREVIOUS_POOL, abi, account.provider) + const logs = await previousPool.queryFilter(previousPool.filters.UseClaim()) + + if (!logs.length) { + console.log('\n✘ No claim events found on from-pool.\n') + return + } + + const trees = {} + let i = logs.length + while (i--) { + const e = logs[i].decode(logs[i].data) + if (!trees[e.tree]) { + trees[e.tree] = [e.account] + } else { + trees[e.tree].push(e.account) + } + } + + const newPool = Pool__factory.connect(deploys[chainId], account) + const isAdmin = await newPool.admins(account.address) + if (!isAdmin) { + console.log('\n✘ Current account must be admin on to-pool.\n') + return + } + + for (const tree in trees) { + const root = await previousPool.rootsByTree(tree) + console.log('\nTree:', tree) + console.log('Root:', root) + console.log('Claims', trees[tree]) + + const gasPrice = await account.getGasPrice() + console.log(`\nGas price: ${gasPrice / 10 ** 9} gwei\n`) + + const prompt = new Confirm(`Enable and set above as claimed on to-pool?`) + if (await prompt.run()) { + const tx = await newPool.enableAndSetClaimed(tree, root, trees[tree]) + console.log('Updating...', getReceiptUrl(chainId, tx.hash), '\n') + await tx.wait(CONFIRMATIONS) + console.log(`✔ Completed for tree ${tree}`) + } + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/delegate/scripts/owner.js b/source/delegate/scripts/owner.js new file mode 100644 index 000000000..bc2fc6a1b --- /dev/null +++ b/source/delegate/scripts/owner.js @@ -0,0 +1,14 @@ +const { check } = require('../../../scripts/owners-update') +const { Pool__factory } = require('@airswap/pool/typechain/factories/contracts') +const poolDeploys = require('../deploys.js') + +async function main() { + await check('Pool', Pool__factory, poolDeploys) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/delegate/scripts/verify.js b/source/delegate/scripts/verify.js new file mode 100644 index 000000000..4613111b2 --- /dev/null +++ b/source/delegate/scripts/verify.js @@ -0,0 +1,27 @@ +/* eslint-disable no-console */ +const { ethers, run } = require('hardhat') +const poolDeploys = require('../deploys.js') +const { chainNames } = require('@airswap/constants') + +async function main() { + await run('compile') + const [deployer] = await ethers.getSigners() + console.log(`Deployer: ${deployer.address}`) + + const chainId = await deployer.getChainId() + const scale = 10 + const max = 100 + + console.log(`Verifying on ${chainNames[chainId].toUpperCase()}`) + await run('verify:verify', { + address: poolDeploys[chainId], + constructorArguments: [scale, max], + }) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js new file mode 100644 index 000000000..5bc84ae24 --- /dev/null +++ b/source/delegate/test/Delegate.js @@ -0,0 +1,44 @@ +const { expect } = require('chai') +const { toAtomicString } = require('@airswap/utils') +const { generateTreeFromData, getRoot, getProof } = require('@airswap/merkle') +const { soliditySha3 } = require('web3-utils') + +const { ethers, waffle } = require('hardhat') +const { deployMockContract } = waffle +const IERC20 = require('@openzeppelin/contracts/build/contracts/IERC20.json') +const STAKING = require('@airswap/staking/build/contracts/Staking.sol/Staking.json') +const { ADDRESS_ZERO } = require('@airswap/constants') + +function toWei(value, places) { + return toAtomicString(value, places || 18) +} + +describe('Pool Unit', () => { + let deployer + let alice + let bob + + let delegate + let delegateFactory + let snapshotId + + beforeEach(async () => { + snapshotId = await ethers.provider.send('evm_snapshot') + }) + + afterEach(async () => { + await ethers.provider.send('evm_revert', [snapshotId]) + }) + + before(async () => { + ;[deployer, alice, bob, carol] = await ethers.getSigners() + + delegate = await (await ethers.getContractFactory('Delegate')).deploy() + await delegate.deployed() + + delegateFactory = await ( + await ethers.getContractFactory('DelegateFactory') + ).deploy() + await delegateFactory.deployed() + }) +}) diff --git a/source/delegate/tsconfig.json b/source/delegate/tsconfig.json new file mode 100644 index 000000000..ce170734c --- /dev/null +++ b/source/delegate/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./typechain" + }, + "files": ["./typechain/index.ts"] +} diff --git a/source/indexer/LICENSE b/source/indexer/LICENSE new file mode 100644 index 000000000..25fb212c5 --- /dev/null +++ b/source/indexer/LICENSE @@ -0,0 +1,19 @@ +Copyright 2023 AirSwap + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/source/indexer/README.md b/source/indexer/README.md new file mode 100644 index 000000000..37de1296a --- /dev/null +++ b/source/indexer/README.md @@ -0,0 +1,37 @@ +# Pool + +[AirSwap](https://www.airswap.io/) is an open-source peer-to-peer trading network. + +[![Discord](https://img.shields.io/discord/590643190281928738.svg)](https://discord.gg/ecQbV7H) +[![License](https://img.shields.io/badge/License-MIT-blue)](https://opensource.org/licenses/MIT) +![Twitter Follow](https://img.shields.io/twitter/follow/airswap?style=social) + +## Resources + +- About → https://about.airswap.io/ +- Website → https://www.airswap.io/ +- Twitter → https://twitter.com/airswap +- Chat → https://chat.airswap.io/ + +## Usage + +:warning: This package may contain unaudited code. For all AirSwap contract deployments see [Deployed Contracts](https://about.airswap.io/technology/deployments). + +## Commands + +Environment variables are set in an `.env` file in the repository root. + +| Command | Description | +| :--------------- | :--------------------------------------- | +| `yarn` | Install dependencies | +| `yarn clean` | Delete the contract `build` folder | +| `yarn compile` | Compile all contracts to `build` folder | +| `yarn coverage` | Report test coverage | +| `yarn test` | Run all tests in `test` folder | +| `yarn test:ci` | Run CI tests in `test` folder | +| `yarn deploy` | Deploy on a network using --network flag | +| `yarn verify` | Verify on a network using --network flag | + +## Running Tests + +:bulb: Prior to testing locally, run `yarn compile` in the `airswap-protocols` project root to build required artifacts. diff --git a/source/indexer/contracts/Index.sol b/source/indexer/contracts/Index.sol new file mode 100644 index 000000000..dcee3a999 --- /dev/null +++ b/source/indexer/contracts/Index.sol @@ -0,0 +1,266 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +pragma solidity 0.8.17; + +import "@openzeppelin/contracts/access/Ownable.sol"; + +/** + * @title Index: A List of Locators + * @notice The Locators are sorted in reverse order based on the score + * meaning that the first element in the list has the largest score + * and final element has the smallest + * @dev A mapping is used to mimic a circular linked list structure + * where every mapping Entry contains a pointer to the next + * and the previous + */ +contract Index is Ownable { + /** + * @notice Index Entry + * @param score uint256 + * @param locator bytes32 + * @param prev address Previous address in the linked list + * @param next address Next address in the linked list + */ + struct Entry { + bytes32 locator; + uint256 score; + address prev; + address next; + } + + // The number of entries in the index + uint256 public length; + + // Identifier to use for the head of the list + address internal constant HEAD = address(uint160(2 ** 160 - 1)); + + // Mapping of an identifier to its entry + mapping(address => Entry) public entries; + + /** + * @notice Contract Events + */ + event SetLocator( + address indexed identifier, + uint256 score, + bytes32 indexed locator + ); + + event UnsetLocator(address indexed identifier); + + /** + * @notice Contract Constructor + */ + constructor() public { + // Create initial entry. + entries[HEAD] = Entry(bytes32(0), 0, HEAD, HEAD); + } + + /** + * @notice Set a Locator + * @param identifier address On-chain address identifying the owner of a locator + * @param score uint256 Score for the locator being set + * @param locator bytes32 Locator + */ + function setLocator( + address identifier, + uint256 score, + bytes32 locator + ) external onlyOwner { + // Ensure the entry does not already exist. + require(!_hasEntry(identifier), "ENTRY_ALREADY_EXISTS"); + + _setLocator(identifier, score, locator); + + // Increment the index length. + length = length + 1; + emit SetLocator(identifier, score, locator); + } + + /** + * @notice Unset a Locator + * @param identifier address On-chain address identifying the owner of a locator + */ + function unsetLocator(address identifier) external onlyOwner { + _unsetLocator(identifier); + + // Decrement the index length. + length = length - 1; + emit UnsetLocator(identifier); + } + + /** + * @notice Update a Locator + * @dev score and/or locator do not need to be different from old values + * @param identifier address On-chain address identifying the owner of a locator + * @param score uint256 Score for the locator being set + * @param locator bytes32 Locator + */ + function updateLocator( + address identifier, + uint256 score, + bytes32 locator + ) external onlyOwner { + // Don't need to update length as it is not used in set/unset logic + _unsetLocator(identifier); + _setLocator(identifier, score, locator); + + emit SetLocator(identifier, score, locator); + } + + /** + * @notice Get a Score + * @param identifier address On-chain address identifying the owner of a locator + * @return uint256 Score corresponding to the identifier + */ + function getScore(address identifier) external view returns (uint256) { + return entries[identifier].score; + } + + /** + * @notice Get a Locator + * @param identifier address On-chain address identifying the owner of a locator + * @return bytes32 Locator information + */ + function getLocator(address identifier) external view returns (bytes32) { + return entries[identifier].locator; + } + + /** + * @notice Get a Range of Locators + * @dev start value of 0x0 starts at the head + * @param cursor address Cursor to start with + * @param limit uint256 Maximum number of locators to return + * @return bytes32[] List of locators + * @return uint256[] List of scores corresponding to locators + * @return address The next cursor to provide for pagination + */ + function getLocators( + address cursor, + uint256 limit + ) + external + view + returns ( + bytes32[] memory locators, + uint256[] memory scores, + address nextCursor + ) + { + address identifier; + + // If a valid cursor is provided, start there. + if (cursor != address(0) && cursor != HEAD) { + // Check that the provided cursor exists. + if (!_hasEntry(cursor)) { + return (new bytes32[](0), new uint256[](0), address(0)); + } + // Set the starting identifier to the provided cursor. + identifier = cursor; + } else { + identifier = entries[HEAD].next; + } + + // Although it's not known how many entries are between `cursor` and the end + // We know that it is no more than `length` + uint256 size = (length < limit) ? length : limit; + + locators = new bytes32[](size); + scores = new uint256[](size); + + // Iterate over the list until the end or size. + uint256 i; + while (i < size && identifier != HEAD) { + locators[i] = entries[identifier].locator; + scores[i] = entries[identifier].score; + i = i + 1; + identifier = entries[identifier].next; + } + + return (locators, scores, identifier); + } + + /** + * @notice Internal function to set a Locator + * @param identifier address On-chain address identifying the owner of a locator + * @param score uint256 Score for the locator being set + * @param locator bytes32 Locator + */ + function _setLocator( + address identifier, + uint256 score, + bytes32 locator + ) internal { + // Disallow locator set to 0x0 to ensure list integrity. + require(locator != bytes32(0), "LOCATOR_MUST_BE_SENT"); + + // Find the first entry with a lower score. + address nextEntry = _getEntryLowerThan(score); + + // Link the new entry between previous and next. + address prevEntry = entries[nextEntry].prev; + entries[prevEntry].next = identifier; + entries[nextEntry].prev = identifier; + entries[identifier] = Entry(locator, score, prevEntry, nextEntry); + } + + /** + * @notice Internal function to unset a Locator + * @param identifier address On-chain address identifying the owner of a locator + */ + function _unsetLocator(address identifier) internal { + // Ensure the entry exists. + require(_hasEntry(identifier), "ENTRY_DOES_NOT_EXIST"); + + // Link the previous and next entries together. + address prevUser = entries[identifier].prev; + address nextUser = entries[identifier].next; + entries[prevUser].next = nextUser; + entries[nextUser].prev = prevUser; + + // Delete entry from the index. + delete entries[identifier]; + } + + /** + * @notice Check if the Index has an Entry + * @param identifier address On-chain address identifying the owner of a locator + * @return bool True if the identifier corresponds to an Entry in the list + */ + function _hasEntry(address identifier) internal view returns (bool) { + return entries[identifier].locator != bytes32(0); + } + + /** + * @notice Returns the largest scoring Entry Lower than a Score + * @param score uint256 Score in question + * @return address Identifier of the largest score lower than score + */ + function _getEntryLowerThan(uint256 score) internal view returns (address) { + address identifier = entries[HEAD].next; + + // Head indicates last because the list is circular. + if (score == 0) { + return HEAD; + } + + // Iterate until a lower score is found. + while (score <= entries[identifier].score) { + identifier = entries[identifier].next; + } + return identifier; + } +} diff --git a/source/indexer/contracts/Indexer.sol b/source/indexer/contracts/Indexer.sol new file mode 100644 index 000000000..88de1215f --- /dev/null +++ b/source/indexer/contracts/Indexer.sol @@ -0,0 +1,337 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +import "./Index.sol"; +import "./interfaces/IIndexer.sol"; +import "./interfaces/ILocatorWhitelist.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +/** + * @title Indexer: A Collection of Index contracts by Token Pair + */ +contract Indexer is IIndexer, Ownable { + // Token to be used for staking (ERC-20) + IERC20 public stakingToken; + + // Mapping of signer token to sender token to protocol type to index + mapping(address => mapping(address => mapping(bytes2 => Index))) + public indexes; + + // The whitelist contract for checking whether a peer is whitelisted per peer type + mapping(bytes2 => address) public locatorWhitelists; + + // Mapping of token address to boolean + mapping(address => bool) public tokenBlacklist; + + /** + * @notice Contract Constructor + * @param indexerStakingToken address + */ + constructor(address indexerStakingToken) public { + stakingToken = IERC20(indexerStakingToken); + } + + /** + * @notice Modifier to check an index exists + */ + modifier indexExists( + address signerToken, + address senderToken, + bytes2 protocol + ) { + require( + indexes[signerToken][senderToken][protocol] != Index(0), + "INDEX_DOES_NOT_EXIST" + ); + _; + } + + /** + * @notice Set the address of an ILocatorWhitelist to use + * @dev Allows removal of locatorWhitelist by passing 0x0 + * @param protocol bytes2 Protocol type for locators + * @param newLocatorWhitelist address Locator whitelist + */ + function setLocatorWhitelist( + bytes2 protocol, + address newLocatorWhitelist + ) external onlyOwner { + locatorWhitelists[protocol] = newLocatorWhitelist; + } + + /** + * @notice Create an Index (List of Locators for a Token Pair) + * @dev Deploys a new Index contract and stores the address. If the Index already + * @dev exists, returns its address, and does not emit a CreateIndex event + * @param signerToken address Signer token for the Index + * @param senderToken address Sender token for the Index + * @param protocol bytes2 Protocol type for locators in Index + */ + function createIndex( + address signerToken, + address senderToken, + bytes2 protocol + ) external returns (address) { + // If the Index does not exist, create it. + if (indexes[signerToken][senderToken][protocol] == Index(0)) { + // Create a new Index contract for the token pair. + indexes[signerToken][senderToken][protocol] = new Index(); + + emit CreateIndex( + signerToken, + senderToken, + protocol, + address(indexes[signerToken][senderToken][protocol]) + ); + } + + // Return the address of the Index contract. + return address(indexes[signerToken][senderToken][protocol]); + } + + /** + * @notice Add a Token to the Blacklist + * @param token address Token to blacklist + */ + function addTokenToBlacklist(address token) external onlyOwner { + if (!tokenBlacklist[token]) { + tokenBlacklist[token] = true; + emit AddTokenToBlacklist(token); + } + } + + /** + * @notice Remove a Token from the Blacklist + * @param token address Token to remove from the blacklist + */ + function removeTokenFromBlacklist(address token) external onlyOwner { + if (tokenBlacklist[token]) { + tokenBlacklist[token] = false; + emit RemoveTokenFromBlacklist(token); + } + } + + /** + * @notice Set an Intent to Trade + * @dev Requires approval to transfer staking token for sender + * + * @param signerToken address Signer token of the Index being staked + * @param senderToken address Sender token of the Index being staked + * @param protocol bytes2 Protocol type for locator in Intent + * @param stakingAmount uint256 Amount being staked + * @param locator bytes32 Locator of the staker + */ + function setIntent( + address signerToken, + address senderToken, + bytes2 protocol, + uint256 stakingAmount, + bytes32 locator + ) external indexExists(signerToken, senderToken, protocol) { + // If whitelist set, ensure the locator is valid. + if (locatorWhitelists[protocol] != address(0)) { + require( + ILocatorWhitelist(locatorWhitelists[protocol]).has(locator), + "LOCATOR_NOT_WHITELISTED" + ); + } + + // Ensure neither of the tokens are blacklisted. + require( + !tokenBlacklist[signerToken] && !tokenBlacklist[senderToken], + "PAIR_IS_BLACKLISTED" + ); + + bool notPreviouslySet = (indexes[signerToken][senderToken][protocol] + .getLocator(msg.sender) == bytes32(0)); + + if (notPreviouslySet) { + // Only transfer for staking if stakingAmount is set. + if (stakingAmount > 0) { + // Transfer the stakingAmount for staking. + require( + stakingToken.transferFrom(msg.sender, address(this), stakingAmount), + "STAKING_FAILED" + ); + } + // Set the locator on the index. + indexes[signerToken][senderToken][protocol].setLocator( + msg.sender, + stakingAmount, + locator + ); + + emit Stake(msg.sender, signerToken, senderToken, protocol, stakingAmount); + } else { + uint256 oldStake = indexes[signerToken][senderToken][protocol].getScore( + msg.sender + ); + + _updateIntent( + msg.sender, + signerToken, + senderToken, + protocol, + stakingAmount, + locator, + oldStake + ); + } + } + + /** + * @notice Unset an Intent to Trade + * @dev Users are allowed to unstake from blacklisted indexes + * + * @param signerToken address Signer token of the Index being unstaked + * @param senderToken address Sender token of the Index being staked + * @param protocol bytes2 Protocol type for locators in Intent + */ + function unsetIntent( + address signerToken, + address senderToken, + bytes2 protocol + ) external { + _unsetIntent(msg.sender, signerToken, senderToken, protocol); + } + + /** + * @notice Get the locators of those trading a token pair + * @dev Users are allowed to unstake from blacklisted indexes + * + * @param signerToken address Signer token of the trading pair + * @param senderToken address Sender token of the trading pair + * @param protocol bytes2 Protocol type for locators in Intent + * @param cursor address Address to start from + * @param limit uint256 Total number of locators to return + * @return bytes32[] List of locators + * @return uint256[] List of scores corresponding to locators + * @return address The next cursor to provide for pagination + */ + function getLocators( + address signerToken, + address senderToken, + bytes2 protocol, + address cursor, + uint256 limit + ) + external + view + returns ( + bytes32[] memory locators, + uint256[] memory scores, + address nextCursor + ) + { + // Ensure neither token is blacklisted. + if (tokenBlacklist[signerToken] || tokenBlacklist[senderToken]) { + return (new bytes32[](0), new uint256[](0), address(0)); + } + + // Ensure the index exists. + if (indexes[signerToken][senderToken][protocol] == Index(0)) { + return (new bytes32[](0), new uint256[](0), address(0)); + } + + return + indexes[signerToken][senderToken][protocol].getLocators(cursor, limit); + } + + /** + * @notice Gets the Stake Amount for a User + * @param user address User who staked + * @param signerToken address Signer token the user staked on + * @param senderToken address Sender token the user staked on + * @param protocol bytes2 Protocol type for locators in Intent + * @return uint256 Amount the user staked + */ + function getStakedAmount( + address user, + address signerToken, + address senderToken, + bytes2 protocol + ) public view returns (uint256 stakedAmount) { + if (indexes[signerToken][senderToken][protocol] == Index(0)) { + return 0; + } + // Return the score, equivalent to the stake amount. + return indexes[signerToken][senderToken][protocol].getScore(user); + } + + function _updateIntent( + address user, + address signerToken, + address senderToken, + bytes2 protocol, + uint256 newAmount, + bytes32 newLocator, + uint256 oldAmount + ) internal { + // If the new stake is bigger, collect the difference. + if (oldAmount < newAmount) { + // Note: SafeMath not required due to the inequality check above + require( + stakingToken.transferFrom(user, address(this), newAmount - oldAmount), + "STAKING_FAILED" + ); + } + + // If the old stake is bigger, return the excess. + if (newAmount < oldAmount) { + // Note: SafeMath not required due to the inequality check above + require(stakingToken.transfer(user, oldAmount - newAmount)); + } + + // Update their intent. + indexes[signerToken][senderToken][protocol].updateLocator( + user, + newAmount, + newLocator + ); + + emit Stake(user, signerToken, senderToken, protocol, newAmount); + } + + /** + * @notice Unset intents and return staked tokens + * @param user address Address of the user who staked + * @param signerToken address Signer token of the trading pair + * @param senderToken address Sender token of the trading pair + * @param protocol bytes2 Protocol type for locators in Intent + */ + function _unsetIntent( + address user, + address signerToken, + address senderToken, + bytes2 protocol + ) internal indexExists(signerToken, senderToken, protocol) { + // Get the score for the user. + uint256 score = indexes[signerToken][senderToken][protocol].getScore(user); + + // Unset the locator on the index. + indexes[signerToken][senderToken][protocol].unsetLocator(user); + + if (score > 0) { + // Return the staked tokens. Reverts on failure. + require(stakingToken.transfer(user, score)); + } + + emit Unstake(user, signerToken, senderToken, protocol, score); + } +} diff --git a/source/indexer/contracts/interfaces/IIndexer.sol b/source/indexer/contracts/interfaces/IIndexer.sol new file mode 100644 index 000000000..3d09855d8 --- /dev/null +++ b/source/indexer/contracts/interfaces/IIndexer.sol @@ -0,0 +1,96 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +interface IIndexer { + event CreateIndex( + address indexed signerToken, + address indexed senderToken, + bytes2 protocol, + address indexAddress + ); + + event Stake( + address indexed staker, + address indexed signerToken, + address indexed senderToken, + bytes2 protocol, + uint256 stakeAmount + ); + + event Unstake( + address indexed staker, + address indexed signerToken, + address indexed senderToken, + bytes2 protocol, + uint256 stakeAmount + ); + + event AddTokenToBlacklist(address token); + + event RemoveTokenFromBlacklist(address token); + + function setLocatorWhitelist( + bytes2 protocol, + address newLocatorWhitelist + ) external; + + function createIndex( + address signerToken, + address senderToken, + bytes2 protocol + ) external returns (address); + + function addTokenToBlacklist(address token) external; + + function removeTokenFromBlacklist(address token) external; + + function setIntent( + address signerToken, + address senderToken, + bytes2 protocol, + uint256 stakingAmount, + bytes32 locator + ) external; + + function unsetIntent( + address signerToken, + address senderToken, + bytes2 protocol + ) external; + + function stakingToken() external view returns (address); + + function indexes(address, address, bytes2) external view returns (address); + + function tokenBlacklist(address) external view returns (bool); + + function getStakedAmount( + address user, + address signerToken, + address senderToken, + bytes2 protocol + ) external view returns (uint256); + + function getLocators( + address signerToken, + address senderToken, + bytes2 protocol, + address cursor, + uint256 limit + ) external view returns (bytes32[] memory, uint256[] memory, address); +} diff --git a/source/indexer/contracts/interfaces/ILocatorWhitelist.sol b/source/indexer/contracts/interfaces/ILocatorWhitelist.sol new file mode 100644 index 000000000..4208c62d1 --- /dev/null +++ b/source/indexer/contracts/interfaces/ILocatorWhitelist.sol @@ -0,0 +1,21 @@ +/* + Copyright 2020 Swap Holdings Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity 0.8.17; + +interface ILocatorWhitelist { + function has(bytes32 locator) external view returns (bool); +} diff --git a/source/indexer/deploys-blocks.js b/source/indexer/deploys-blocks.js new file mode 100644 index 000000000..490b26825 --- /dev/null +++ b/source/indexer/deploys-blocks.js @@ -0,0 +1,21 @@ +module.exports = { + 1: 18337329, + 5: 9854680, + 30: 5717948, + 31: 4378661, + 40: 305834078, + 41: 262335361, + 56: 32550529, + 97: 34150670, + 137: 48645401, + 8453: 5180096, + 42161: 140046382, + 43113: 26720218, + 43114: 36367783, + 59140: 1711053, + 59144: 619127, + 80001: 41133390, + 84531: 10978032, + 421613: 47402006, + 11155111: 4509265, +} diff --git a/source/indexer/deploys.js b/source/indexer/deploys.js new file mode 100644 index 000000000..e7896c009 --- /dev/null +++ b/source/indexer/deploys.js @@ -0,0 +1,21 @@ +module.exports = { + 1: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 5: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 30: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 31: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 40: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 41: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 56: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 97: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 137: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 8453: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 42161: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 43113: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 43114: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 59140: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 59144: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 80001: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 84531: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 421613: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', + 11155111: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', +} diff --git a/source/indexer/deploys.js.d.ts b/source/indexer/deploys.js.d.ts new file mode 100644 index 000000000..31683c18a --- /dev/null +++ b/source/indexer/deploys.js.d.ts @@ -0,0 +1,2 @@ +declare module '@airswap/pool/deploys.js' +declare module '@airswap/pool/deploys-blocks.js' diff --git a/source/indexer/hardhat.config.js b/source/indexer/hardhat.config.js new file mode 100644 index 000000000..4b553c55b --- /dev/null +++ b/source/indexer/hardhat.config.js @@ -0,0 +1,6 @@ +module.exports = { + typechain: { + outDir: 'typechain', + }, + ...require('../../hardhat.config.js'), +} diff --git a/source/indexer/package.json b/source/indexer/package.json new file mode 100644 index 000000000..30dd0d999 --- /dev/null +++ b/source/indexer/package.json @@ -0,0 +1,43 @@ +{ + "name": "@airswap/indexer", + "version": "4.1.4", + "description": "AirSwap: Trade Indexer", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/airswap/airswap-protocols" + }, + "files": [ + "./build", + "./typechain", + "./deploys.js", + "./deploys-blocks.js", + "./deploys.js.d.ts" + ], + "scripts": { + "clean": "rm -rf ./cache && rm -rf ./build && rm -rf ./typechain", + "compile": "hardhat compile; yarn typechain", + "typechain": "tsc -b", + "coverage": "hardhat coverage", + "test": "hardhat test", + "test:ci": "hardhat test", + "deploy": "hardhat run ./scripts/deploy.js", + "verify": "hardhat run ./scripts/verify.js", + "owners": "hardhat run ./scripts/owner.js", + "migrate": "hardhat run ./scripts/migrate.js", + "balances": "hardhat run ./scripts/balances.js" + }, + "dependencies": { + "@openzeppelin/contracts": "^4.8.3" + }, + "devDependencies": { + "@airswap/constants": "4.1.6", + "@airswap/metadata": "4.1.12", + "@airswap/types": "4.1.1", + "@airswap/utils": "4.1.8", + "prompt-confirm": "^2.0.4" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/source/indexer/scripts/balances.js b/source/indexer/scripts/balances.js new file mode 100644 index 000000000..f1bd5ad48 --- /dev/null +++ b/source/indexer/scripts/balances.js @@ -0,0 +1,71 @@ +const { ethers } = require('hardhat') +const { getKnownTokens } = require('@airswap/metadata') +const { chainNames, ChainIds } = require('@airswap/constants') +const BalanceChecker = require('@airswap/balances/build/contracts/BalanceChecker.sol/BalanceChecker.json') +const balancesDeploys = require('@airswap/balances/deploys.js') +const poolDeploys = require('../deploys.js') + +async function main() { + const [account] = await ethers.getSigners() + const chainId = await account.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log('Account:', account.address) + console.log('Network:', chainNames[chainId].toUpperCase()) + console.log('\nPool:', poolDeploys[chainId]) + + if (!balancesDeploys[chainId]) { + throw new Error('Unable to check balances on this chain.') + } + + const tokens = (await getKnownTokens(Number(chainId))).tokens + + let count = tokens.length + const addresses = [] + while (count--) { + if (ethers.utils.isAddress(tokens[count].address)) { + addresses.push(tokens[count].address.toLowerCase()) + } + } + + console.log(`\nScanning non-zero balances for ${tokens.length} tokens...\n`) + + const balancesContract = new ethers.Contract( + balancesDeploys[chainId], + BalanceChecker.abi, + account.provider + ) + + const chunk = 750 + let balances = [] + let index = 0 + count = addresses.length + while (index < count) { + balances = balances.concat( + await balancesContract.walletBalances( + poolDeploys[chainId], + addresses.slice(index, index + chunk) + ) + ) + index += chunk + } + + const result = [] + for (let i = 0; i < balances.length; i++) { + if (!balances[i].eq(0)) { + result.push(addresses[i]) + } + } + + console.log('Non-zero balances in', result.length, 'tokens:\n') + console.log(JSON.stringify(result)) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/indexer/scripts/deploy.js b/source/indexer/scripts/deploy.js new file mode 100644 index 000000000..abfe460a4 --- /dev/null +++ b/source/indexer/scripts/deploy.js @@ -0,0 +1,74 @@ +/* eslint-disable no-console */ +const fs = require('fs') +const prettier = require('prettier') +const Confirm = require('prompt-confirm') +const { ethers, run } = require('hardhat') +const { chainLabels, chainNames, ChainIds } = require('@airswap/constants') +const { getReceiptUrl } = require('@airswap/utils') +const poolDeploys = require('../deploys.js') +const poolBlocks = require('../deploys-blocks.js') + +async function main() { + await run('compile') + const config = await prettier.resolveConfig('../deploys.js') + + const [deployer] = await ethers.getSigners() + const gasPrice = await deployer.getGasPrice() + const chainId = await deployer.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log(`Deployer: ${deployer.address}`) + console.log(`Network: ${chainNames[chainId].toUpperCase()}`) + console.log(`Gas price: ${gasPrice / 10 ** 9} gwei\n`) + + const scale = 10 + const max = 100 + + const prompt = new Confirm('Proceed to deploy?') + if (await prompt.run()) { + const poolFactory = await ethers.getContractFactory('Pool') + const poolContract = await poolFactory.deploy(scale, max, { + gasPrice, + }) + console.log( + 'Deploying...', + getReceiptUrl(chainId, poolContract.deployTransaction.hash) + ) + await poolContract.deployed() + + poolDeploys[chainId] = poolContract.address + fs.writeFileSync( + './deploys.js', + prettier.format( + `module.exports = ${JSON.stringify(poolDeploys, null, '\t')}`, + { ...config, parser: 'babel' } + ) + ) + poolBlocks[chainId] = ( + await poolContract.deployTransaction.wait() + ).blockNumber + fs.writeFileSync( + './deploys-blocks.js', + prettier.format( + `module.exports = ${JSON.stringify(poolBlocks, null, '\t')}`, + { ...config, parser: 'babel' } + ) + ) + console.log(`Deployed: ${poolDeploys[chainId]} @ ${poolBlocks[chainId]}`) + + console.log( + `\nVerify with "yarn verify --network ${chainLabels[ + chainId + ].toLowerCase()}"\n` + ) + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/indexer/scripts/migrate-abis/4-1-1.js b/source/indexer/scripts/migrate-abis/4-1-1.js new file mode 100644 index 000000000..27293305e --- /dev/null +++ b/source/indexer/scripts/migrate-abis/4-1-1.js @@ -0,0 +1,416 @@ +module.exports = { + abi: [ + { + inputs: [ + { internalType: 'uint256', name: '_scale', type: 'uint256' }, + { internalType: 'uint256', name: '_max', type: 'uint256' }, + ], + stateMutability: 'nonpayable', + type: 'constructor', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'AddressInvalid', + type: 'error', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'AdminNotSet', + type: 'error', + }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'AmountInsufficient', + type: 'error', + }, + { inputs: [], name: 'ClaimAlreadyUsed', type: 'error' }, + { inputs: [], name: 'ClaimsNotProvided', type: 'error' }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'MaxTooHigh', + type: 'error', + }, + { + inputs: [ + { internalType: 'bytes32', name: '', type: 'bytes32' }, + { internalType: 'bytes32', name: '', type: 'bytes32' }, + ], + name: 'ProofInvalid', + type: 'error', + }, + { + inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + name: 'ScaleTooHigh', + type: 'error', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'TreeNotEnabled', + type: 'error', + }, + { inputs: [], name: 'Unauthorized', type: 'error' }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address[]', + name: 'tokens', + type: 'address[]', + }, + { + indexed: false, + internalType: 'address', + name: 'dest', + type: 'address', + }, + ], + name: 'DrainTo', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bytes32', + name: 'tree', + type: 'bytes32', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'root', + type: 'bytes32', + }, + ], + name: 'Enable', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferStarted', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'previousOwner', + type: 'address', + }, + { + indexed: true, + internalType: 'address', + name: 'newOwner', + type: 'address', + }, + ], + name: 'OwnershipTransferred', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'admin', + type: 'address', + }, + ], + name: 'SetAdmin', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'max', + type: 'uint256', + }, + ], + name: 'SetMax', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'scale', + type: 'uint256', + }, + ], + name: 'SetScale', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'admin', + type: 'address', + }, + ], + name: 'UnsetAdmin', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'tree', + type: 'bytes32', + }, + ], + name: 'UseClaim', + type: 'event', + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'account', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'recipient', + type: 'address', + }, + { + indexed: false, + internalType: 'address', + name: 'token', + type: 'address', + }, + { + indexed: false, + internalType: 'uint256', + name: 'amount', + type: 'uint256', + }, + ], + name: 'Withdraw', + type: 'event', + }, + { + inputs: [], + name: 'acceptOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '', type: 'address' }], + name: 'admins', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'uint256', name: '_value', type: 'uint256' }, + { internalType: 'address', name: '_token', type: 'address' }, + ], + name: 'calculate', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '', type: 'bytes32' }, + { internalType: 'address', name: '', type: 'address' }, + ], + name: 'claimed', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address[]', name: '_tokens', type: 'address[]' }, + { internalType: 'address', name: '_dest', type: 'address' }, + ], + name: 'drainTo', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + ], + name: 'enable', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + { internalType: 'address[]', name: '_accounts', type: 'address[]' }, + ], + name: 'enableAndSetClaimed', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '_account', type: 'address' }, + { internalType: 'bytes32[]', name: '_trees', type: 'bytes32[]' }, + ], + name: 'getStatus', + outputs: [{ internalType: 'bool[]', name: '', type: 'bool[]' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'max', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'owner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'pendingOwner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'renounceOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + name: 'rootsByTree', + outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'scale', + outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], + name: 'setAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: '_max', type: 'uint256' }], + name: 'setMax', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'uint256', name: '_scale', type: 'uint256' }], + name: 'setScale', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], + name: 'unsetAdmin', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: '_claimant', type: 'address' }, + { internalType: 'bytes32', name: '_root', type: 'bytes32' }, + { internalType: 'uint256', name: '_value', type: 'uint256' }, + { internalType: 'bytes32[]', name: '_proof', type: 'bytes32[]' }, + ], + name: 'verify', + outputs: [{ internalType: 'bool', name: '', type: 'bool' }], + stateMutability: 'pure', + type: 'function', + }, + { + inputs: [ + { + components: [ + { internalType: 'bytes32', name: 'tree', type: 'bytes32' }, + { internalType: 'uint256', name: 'value', type: 'uint256' }, + { internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' }, + ], + internalType: 'struct IPool.Claim[]', + name: '_claims', + type: 'tuple[]', + }, + { internalType: 'address', name: '_token', type: 'address' }, + { internalType: 'uint256', name: '_minimum', type: 'uint256' }, + { internalType: 'address', name: '_recipient', type: 'address' }, + ], + name: 'withdraw', + outputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }], + stateMutability: 'nonpayable', + type: 'function', + }, + ], +} diff --git a/source/indexer/scripts/migrate.js b/source/indexer/scripts/migrate.js new file mode 100644 index 000000000..0bc28adcb --- /dev/null +++ b/source/indexer/scripts/migrate.js @@ -0,0 +1,76 @@ +const Confirm = require('prompt-confirm') +const { ethers } = require('hardhat') +const { chainNames, ChainIds } = require('@airswap/constants') +const { getReceiptUrl } = require('@airswap/utils') + +const { Pool__factory } = require('../typechain/factories/contracts') +const { abi } = require('./migrate-abis/4-1-1.js') +const deploys = require('../deploys.js') + +const CONFIRMATIONS = 2 +const PREVIOUS_POOL = '0xEEcD248D977Fd4D392915b4AdeF8154BA3aE9c02' +const NEW_POOL = '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11' + +async function main() { + const [account] = await ethers.getSigners() + const chainId = await account.getChainId() + if (chainId === ChainIds.HARDHAT) { + console.log('Value for --network flag is required') + return + } + console.log(`Account: ${account.address}`) + console.log(`Network: ${chainNames[chainId].toUpperCase()}\n`) + console.log(`From-pool: ${PREVIOUS_POOL}`) + console.log(`To-pool: ${NEW_POOL}`) + + const previousPool = new ethers.Contract(PREVIOUS_POOL, abi, account.provider) + const logs = await previousPool.queryFilter(previousPool.filters.UseClaim()) + + if (!logs.length) { + console.log('\n✘ No claim events found on from-pool.\n') + return + } + + const trees = {} + let i = logs.length + while (i--) { + const e = logs[i].decode(logs[i].data) + if (!trees[e.tree]) { + trees[e.tree] = [e.account] + } else { + trees[e.tree].push(e.account) + } + } + + const newPool = Pool__factory.connect(deploys[chainId], account) + const isAdmin = await newPool.admins(account.address) + if (!isAdmin) { + console.log('\n✘ Current account must be admin on to-pool.\n') + return + } + + for (const tree in trees) { + const root = await previousPool.rootsByTree(tree) + console.log('\nTree:', tree) + console.log('Root:', root) + console.log('Claims', trees[tree]) + + const gasPrice = await account.getGasPrice() + console.log(`\nGas price: ${gasPrice / 10 ** 9} gwei\n`) + + const prompt = new Confirm(`Enable and set above as claimed on to-pool?`) + if (await prompt.run()) { + const tx = await newPool.enableAndSetClaimed(tree, root, trees[tree]) + console.log('Updating...', getReceiptUrl(chainId, tx.hash), '\n') + await tx.wait(CONFIRMATIONS) + console.log(`✔ Completed for tree ${tree}`) + } + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/indexer/scripts/owner.js b/source/indexer/scripts/owner.js new file mode 100644 index 000000000..bc2fc6a1b --- /dev/null +++ b/source/indexer/scripts/owner.js @@ -0,0 +1,14 @@ +const { check } = require('../../../scripts/owners-update') +const { Pool__factory } = require('@airswap/pool/typechain/factories/contracts') +const poolDeploys = require('../deploys.js') + +async function main() { + await check('Pool', Pool__factory, poolDeploys) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/indexer/scripts/verify.js b/source/indexer/scripts/verify.js new file mode 100644 index 000000000..4613111b2 --- /dev/null +++ b/source/indexer/scripts/verify.js @@ -0,0 +1,27 @@ +/* eslint-disable no-console */ +const { ethers, run } = require('hardhat') +const poolDeploys = require('../deploys.js') +const { chainNames } = require('@airswap/constants') + +async function main() { + await run('compile') + const [deployer] = await ethers.getSigners() + console.log(`Deployer: ${deployer.address}`) + + const chainId = await deployer.getChainId() + const scale = 10 + const max = 100 + + console.log(`Verifying on ${chainNames[chainId].toUpperCase()}`) + await run('verify:verify', { + address: poolDeploys[chainId], + constructorArguments: [scale, max], + }) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/source/indexer/test/Indexer.js b/source/indexer/test/Indexer.js new file mode 100644 index 000000000..85135f1a9 --- /dev/null +++ b/source/indexer/test/Indexer.js @@ -0,0 +1,40 @@ +const { expect } = require('chai') +const { toAtomicString } = require('@airswap/utils') +const { generateTreeFromData, getRoot, getProof } = require('@airswap/merkle') +const { soliditySha3 } = require('web3-utils') + +const { ethers, waffle } = require('hardhat') +const { deployMockContract } = waffle +const IERC20 = require('@openzeppelin/contracts/build/contracts/IERC20.json') +const STAKING = require('@airswap/staking/build/contracts/Staking.sol/Staking.json') +const { ADDRESS_ZERO } = require('@airswap/constants') + +function toWei(value, places) { + return toAtomicString(value, places || 18) +} + +describe('Pool Unit', () => { + let deployer + let alice + let bob + + let pool + let snapshotId + + beforeEach(async () => { + snapshotId = await ethers.provider.send('evm_snapshot') + }) + + afterEach(async () => { + await ethers.provider.send('evm_revert', [snapshotId]) + }) + + before(async () => { + ;[deployer, alice, bob, carol] = await ethers.getSigners() + + pool = await ( + await ethers.getContractFactory('Pool') + ).deploy(CLAIM_SCALE, CLAIM_MAX) + await pool.deployed() + }) +}) diff --git a/source/indexer/tsconfig.json b/source/indexer/tsconfig.json new file mode 100644 index 000000000..ce170734c --- /dev/null +++ b/source/indexer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./typechain" + }, + "files": ["./typechain/index.ts"] +} From 13bd57b1e64041812540c371b89ab7115f3b7a10 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Dec 2023 21:06:53 -0500 Subject: [PATCH 02/43] Updated Indexer code to compile with Solidity 0.8.17 --- source/indexer/contracts/Index.sol | 6 +-- source/indexer/contracts/Indexer.sol | 46 +++++++++++-------- .../indexer/contracts/interfaces/IIndexer.sol | 4 -- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/source/indexer/contracts/Index.sol b/source/indexer/contracts/Index.sol index dcee3a999..fbbda2871 100644 --- a/source/indexer/contracts/Index.sol +++ b/source/indexer/contracts/Index.sol @@ -144,9 +144,9 @@ contract Index is Ownable { * @dev start value of 0x0 starts at the head * @param cursor address Cursor to start with * @param limit uint256 Maximum number of locators to return - * @return bytes32[] List of locators - * @return uint256[] List of scores corresponding to locators - * @return address The next cursor to provide for pagination + * @return locators bytes32[] List of locators + * @return scores uint256[] List of scores corresponding to locators + * @return nextCursor address The next cursor to provide for pagination */ function getLocators( address cursor, diff --git a/source/indexer/contracts/Indexer.sol b/source/indexer/contracts/Indexer.sol index 88de1215f..7c58c406c 100644 --- a/source/indexer/contracts/Indexer.sol +++ b/source/indexer/contracts/Indexer.sol @@ -30,7 +30,8 @@ contract Indexer is IIndexer, Ownable { IERC20 public stakingToken; // Mapping of signer token to sender token to protocol type to index - mapping(address => mapping(address => mapping(bytes2 => Index))) + // Index is referenced by address + mapping(address => mapping(address => mapping(bytes2 => address))) public indexes; // The whitelist contract for checking whether a peer is whitelisted per peer type @@ -56,7 +57,7 @@ contract Indexer is IIndexer, Ownable { bytes2 protocol ) { require( - indexes[signerToken][senderToken][protocol] != Index(0), + indexes[signerToken][senderToken][protocol] != address(0), "INDEX_DOES_NOT_EXIST" ); _; @@ -89,9 +90,10 @@ contract Indexer is IIndexer, Ownable { bytes2 protocol ) external returns (address) { // If the Index does not exist, create it. - if (indexes[signerToken][senderToken][protocol] == Index(0)) { + if (indexes[signerToken][senderToken][protocol] == address(0)) { // Create a new Index contract for the token pair. - indexes[signerToken][senderToken][protocol] = new Index(); + Index index = new Index(); + indexes[signerToken][senderToken][protocol] = address(index); emit CreateIndex( signerToken, @@ -158,7 +160,7 @@ contract Indexer is IIndexer, Ownable { "PAIR_IS_BLACKLISTED" ); - bool notPreviouslySet = (indexes[signerToken][senderToken][protocol] + bool notPreviouslySet = (Index(indexes[signerToken][senderToken][protocol]) .getLocator(msg.sender) == bytes32(0)); if (notPreviouslySet) { @@ -171,7 +173,7 @@ contract Indexer is IIndexer, Ownable { ); } // Set the locator on the index. - indexes[signerToken][senderToken][protocol].setLocator( + Index(indexes[signerToken][senderToken][protocol]).setLocator( msg.sender, stakingAmount, locator @@ -179,9 +181,8 @@ contract Indexer is IIndexer, Ownable { emit Stake(msg.sender, signerToken, senderToken, protocol, stakingAmount); } else { - uint256 oldStake = indexes[signerToken][senderToken][protocol].getScore( - msg.sender - ); + uint256 oldStake = Index(indexes[signerToken][senderToken][protocol]) + .getScore(msg.sender); _updateIntent( msg.sender, @@ -220,9 +221,9 @@ contract Indexer is IIndexer, Ownable { * @param protocol bytes2 Protocol type for locators in Intent * @param cursor address Address to start from * @param limit uint256 Total number of locators to return - * @return bytes32[] List of locators - * @return uint256[] List of scores corresponding to locators - * @return address The next cursor to provide for pagination + * @return locators bytes32[] List of locators + * @return scores uint256[] List of scores corresponding to locators + * @return nextCursor address The next cursor to provide for pagination */ function getLocators( address signerToken, @@ -245,12 +246,15 @@ contract Indexer is IIndexer, Ownable { } // Ensure the index exists. - if (indexes[signerToken][senderToken][protocol] == Index(0)) { + if (indexes[signerToken][senderToken][protocol] == address(0)) { return (new bytes32[](0), new uint256[](0), address(0)); } return - indexes[signerToken][senderToken][protocol].getLocators(cursor, limit); + Index(indexes[signerToken][senderToken][protocol]).getLocators( + cursor, + limit + ); } /** @@ -259,7 +263,7 @@ contract Indexer is IIndexer, Ownable { * @param signerToken address Signer token the user staked on * @param senderToken address Sender token the user staked on * @param protocol bytes2 Protocol type for locators in Intent - * @return uint256 Amount the user staked + * @return stakedAmount uint256 Amount the user staked */ function getStakedAmount( address user, @@ -267,11 +271,11 @@ contract Indexer is IIndexer, Ownable { address senderToken, bytes2 protocol ) public view returns (uint256 stakedAmount) { - if (indexes[signerToken][senderToken][protocol] == Index(0)) { + if (indexes[signerToken][senderToken][protocol] == address(0)) { return 0; } // Return the score, equivalent to the stake amount. - return indexes[signerToken][senderToken][protocol].getScore(user); + return Index(indexes[signerToken][senderToken][protocol]).getScore(user); } function _updateIntent( @@ -299,7 +303,7 @@ contract Indexer is IIndexer, Ownable { } // Update their intent. - indexes[signerToken][senderToken][protocol].updateLocator( + Index(indexes[signerToken][senderToken][protocol]).updateLocator( user, newAmount, newLocator @@ -322,10 +326,12 @@ contract Indexer is IIndexer, Ownable { bytes2 protocol ) internal indexExists(signerToken, senderToken, protocol) { // Get the score for the user. - uint256 score = indexes[signerToken][senderToken][protocol].getScore(user); + uint256 score = Index(indexes[signerToken][senderToken][protocol]).getScore( + user + ); // Unset the locator on the index. - indexes[signerToken][senderToken][protocol].unsetLocator(user); + Index(indexes[signerToken][senderToken][protocol]).unsetLocator(user); if (score > 0) { // Return the staked tokens. Reverts on failure. diff --git a/source/indexer/contracts/interfaces/IIndexer.sol b/source/indexer/contracts/interfaces/IIndexer.sol index 3d09855d8..9868fa138 100644 --- a/source/indexer/contracts/interfaces/IIndexer.sol +++ b/source/indexer/contracts/interfaces/IIndexer.sol @@ -73,10 +73,6 @@ interface IIndexer { bytes2 protocol ) external; - function stakingToken() external view returns (address); - - function indexes(address, address, bytes2) external view returns (address); - function tokenBlacklist(address) external view returns (bool); function getStakedAmount( From 2de8b8cbd33e08d729d85696c0cf2334c400a9b1 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Dec 2023 21:09:33 -0500 Subject: [PATCH 03/43] Updated licenses for Delegates and Indexer contracts --- source/delegate/contracts/Delegate.sol | 16 +--------------- source/delegate/contracts/DelegateFactory.sol | 16 +--------------- .../delegate/contracts/interfaces/IDelegate.sol | 15 +-------------- .../contracts/interfaces/IDelegateFactory.sol | 16 +--------------- source/indexer/contracts/Index.sol | 15 +-------------- source/indexer/contracts/Indexer.sol | 16 +--------------- source/indexer/contracts/interfaces/IIndexer.sol | 16 +--------------- .../contracts/interfaces/ILocatorWhitelist.sol | 16 +--------------- 8 files changed, 8 insertions(+), 118 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index de37acb55..583ded6f4 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; diff --git a/source/delegate/contracts/DelegateFactory.sol b/source/delegate/contracts/DelegateFactory.sol index a53570dd5..4f23b4314 100644 --- a/source/delegate/contracts/DelegateFactory.sol +++ b/source/delegate/contracts/DelegateFactory.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index f4ab9f4f9..c3020d2e3 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -1,18 +1,5 @@ -/* - Copyright 2020 Swap Holdings Ltd. +// SPDX-License-Identifier: MIT - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; pragma solidity 0.8.17; diff --git a/source/delegate/contracts/interfaces/IDelegateFactory.sol b/source/delegate/contracts/interfaces/IDelegateFactory.sol index 1558d9987..5f321fede 100644 --- a/source/delegate/contracts/interfaces/IDelegateFactory.sol +++ b/source/delegate/contracts/interfaces/IDelegateFactory.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; diff --git a/source/indexer/contracts/Index.sol b/source/indexer/contracts/Index.sol index fbbda2871..7d5519a79 100644 --- a/source/indexer/contracts/Index.sol +++ b/source/indexer/contracts/Index.sol @@ -1,18 +1,5 @@ -/* - Copyright 2020 Swap Holdings Ltd. +// SPDX-License-Identifier: MIT - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ pragma solidity 0.8.17; import "@openzeppelin/contracts/access/Ownable.sol"; diff --git a/source/indexer/contracts/Indexer.sol b/source/indexer/contracts/Indexer.sol index 7c58c406c..774e1423d 100644 --- a/source/indexer/contracts/Indexer.sol +++ b/source/indexer/contracts/Indexer.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; diff --git a/source/indexer/contracts/interfaces/IIndexer.sol b/source/indexer/contracts/interfaces/IIndexer.sol index 9868fa138..c3b61a973 100644 --- a/source/indexer/contracts/interfaces/IIndexer.sol +++ b/source/indexer/contracts/interfaces/IIndexer.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; diff --git a/source/indexer/contracts/interfaces/ILocatorWhitelist.sol b/source/indexer/contracts/interfaces/ILocatorWhitelist.sol index 4208c62d1..7d9a257a1 100644 --- a/source/indexer/contracts/interfaces/ILocatorWhitelist.sol +++ b/source/indexer/contracts/interfaces/ILocatorWhitelist.sol @@ -1,18 +1,4 @@ -/* - Copyright 2020 Swap Holdings Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +// SPDX-License-Identifier: MIT pragma solidity 0.8.17; From e3a4552f160da0f87f9df74df781a62f26498879 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Dec 2023 21:30:35 -0500 Subject: [PATCH 04/43] Removed constructor visibility and updated Delegate/Indexer interactions to ensure both contracts compile simultaneously --- source/delegate/contracts/Delegate.sol | 16 +++++++++++----- source/delegate/contracts/DelegateFactory.sol | 2 +- source/indexer/contracts/Index.sol | 2 +- source/indexer/contracts/Indexer.sol | 6 +++++- source/indexer/contracts/interfaces/IIndexer.sol | 2 ++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 583ded6f4..a93aab4ce 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -53,7 +53,7 @@ contract Delegate is IDelegate, Ownable { address delegateContractOwner, address delegateTradeWallet, bytes2 delegateProtocol - ) public { + ) { swapContract = delegateSwap; indexer = delegateIndexer; protocol = delegateProtocol; @@ -72,7 +72,10 @@ contract Delegate is IDelegate, Ownable { // Ensure that the indexer can pull funds from delegate account. require( - IERC20(indexer.stakingToken()).approve(address(indexer), MAX_INT), + IERC20(address(indexer.getStakingToken())).approve( + address(indexer), + MAX_INT + ), "STAKING_APPROVAL_FAILED" ); } @@ -146,7 +149,7 @@ contract Delegate is IDelegate, Ownable { } else if (oldStakeAmount < newStakeAmount) { // transfer only the difference from the sender to the Delegate. require( - IERC20(indexer.stakingToken()).transferFrom( + IERC20(address(indexer.getStakingToken())).transferFrom( msg.sender, address(this), newStakeAmount - oldStakeAmount @@ -166,7 +169,7 @@ contract Delegate is IDelegate, Ownable { if (oldStakeAmount > newStakeAmount) { // return excess stake back require( - IERC20(indexer.stakingToken()).transfer( + IERC20(address(indexer.getStakingToken())).transfer( msg.sender, oldStakeAmount - newStakeAmount ), @@ -200,7 +203,10 @@ contract Delegate is IDelegate, Ownable { // This is returned to the msg.sender. if (stakedAmount > 0) { require( - IERC20(indexer.stakingToken()).transfer(msg.sender, stakedAmount), + IERC20(address(indexer.getStakingToken())).transfer( + msg.sender, + stakedAmount + ), "STAKING_RETURN_FAILED" ); } diff --git a/source/delegate/contracts/DelegateFactory.sol b/source/delegate/contracts/DelegateFactory.sol index 4f23b4314..7b1061832 100644 --- a/source/delegate/contracts/DelegateFactory.sol +++ b/source/delegate/contracts/DelegateFactory.sol @@ -28,7 +28,7 @@ contract DelegateFactory is IDelegateFactory, ILocatorWhitelist { ISwapERC20 factorySwapContract, IIndexer factoryIndexerContract, bytes2 factoryProtocol - ) public { + ) { swapContract = factorySwapContract; indexerContract = factoryIndexerContract; protocol = factoryProtocol; diff --git a/source/indexer/contracts/Index.sol b/source/indexer/contracts/Index.sol index 7d5519a79..dc0277813 100644 --- a/source/indexer/contracts/Index.sol +++ b/source/indexer/contracts/Index.sol @@ -51,7 +51,7 @@ contract Index is Ownable { /** * @notice Contract Constructor */ - constructor() public { + constructor() { // Create initial entry. entries[HEAD] = Entry(bytes32(0), 0, HEAD, HEAD); } diff --git a/source/indexer/contracts/Indexer.sol b/source/indexer/contracts/Indexer.sol index 774e1423d..3b1d91c6a 100644 --- a/source/indexer/contracts/Indexer.sol +++ b/source/indexer/contracts/Indexer.sol @@ -30,7 +30,7 @@ contract Indexer is IIndexer, Ownable { * @notice Contract Constructor * @param indexerStakingToken address */ - constructor(address indexerStakingToken) public { + constructor(address indexerStakingToken) { stakingToken = IERC20(indexerStakingToken); } @@ -326,4 +326,8 @@ contract Indexer is IIndexer, Ownable { emit Unstake(user, signerToken, senderToken, protocol, score); } + + function getStakingToken() public view returns (address) { + return address(stakingToken); + } } diff --git a/source/indexer/contracts/interfaces/IIndexer.sol b/source/indexer/contracts/interfaces/IIndexer.sol index c3b61a973..47e0df773 100644 --- a/source/indexer/contracts/interfaces/IIndexer.sol +++ b/source/indexer/contracts/interfaces/IIndexer.sol @@ -59,6 +59,8 @@ interface IIndexer { bytes2 protocol ) external; + function getStakingToken() external view returns (address); + function tokenBlacklist(address) external view returns (bool); function getStakedAmount( From 7cdb24de4d90df6cb4f12536c18106423102c54d Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 8 Jan 2024 20:25:13 -0500 Subject: [PATCH 05/43] Removed the indexer boilerplate and adjusted the delegate placeholder contract accordingly. Removed the delegateFactory contract --- source/delegate/contracts/Delegate.sol | 115 ------------------ source/delegate/contracts/DelegateFactory.sol | 75 ------------ source/delegate/deploys-blocks.js | 22 +--- source/delegate/deploys.js | 22 +--- source/delegate/test/Delegate.js | 7 +- 5 files changed, 3 insertions(+), 238 deletions(-) delete mode 100644 source/delegate/contracts/DelegateFactory.sol diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index a93aab4ce..6381f0794 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -4,7 +4,6 @@ pragma solidity 0.8.17; import "./interfaces/IDelegate.sol"; import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; -import "@airswap/indexer/contracts/interfaces/IIndexer.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -20,9 +19,6 @@ contract Delegate is IDelegate, Ownable { // The Swap contract to be used to settle trades ISwapERC20 public swapContract; - // The Indexer to stake intent to trade on - IIndexer public indexer; - // Maximum integer for token transfer approval uint256 internal constant MAX_INT = 2 ** 256 - 1; @@ -42,20 +38,17 @@ contract Delegate is IDelegate, Ownable { * @notice Contract Constructor * @dev owner defaults to msg.sender if delegateContractOwner is provided as address(0) * @param delegateSwap address Swap contract the delegate will deploy with - * @param delegateIndexer address Indexer contract the delegate will deploy with * @param delegateContractOwner address Owner of the delegate * @param delegateTradeWallet address Wallet the delegate will trade from * @param delegateProtocol bytes2 The protocol identifier for Delegate contracts */ constructor( ISwapERC20 delegateSwap, - IIndexer delegateIndexer, address delegateContractOwner, address delegateTradeWallet, bytes2 delegateProtocol ) { swapContract = delegateSwap; - indexer = delegateIndexer; protocol = delegateProtocol; // If no delegate owner is provided, the deploying address is the owner. @@ -69,15 +62,6 @@ contract Delegate is IDelegate, Ownable { } else { tradeWallet = owner(); } - - // Ensure that the indexer can pull funds from delegate account. - require( - IERC20(address(indexer.getStakingToken())).approve( - address(indexer), - MAX_INT - ), - "STAKING_APPROVAL_FAILED" - ); } /** @@ -113,105 +97,6 @@ contract Delegate is IDelegate, Ownable { _unsetRule(senderToken, signerToken); } - /** - * @notice sets a rule on the delegate and an intent on the indexer - * @dev only callable by owner - * @dev delegate needs to be given allowance from msg.sender for the newStakeAmount - * @dev swap needs to be given permission to move funds from the delegate - * @param senderToken address Token the delgeate will send - * @param signerToken address Token the delegate will receive - * @param rule Rule Rule to set on a delegate - * @param newStakeAmount uint256 Amount to stake for an intent - */ - function setRuleAndIntent( - address senderToken, - address signerToken, - Rule calldata rule, - uint256 newStakeAmount - ) external onlyOwner { - _setRule( - senderToken, - signerToken, - rule.maxSenderAmount, - rule.priceCoef, - rule.priceExp - ); - - // get currentAmount staked or 0 if never staked - uint256 oldStakeAmount = indexer.getStakedAmount( - address(this), - signerToken, - senderToken, - protocol - ); - if (oldStakeAmount == newStakeAmount && oldStakeAmount > 0) { - return; // forgo trying to reset intent with non-zero same stake amount - } else if (oldStakeAmount < newStakeAmount) { - // transfer only the difference from the sender to the Delegate. - require( - IERC20(address(indexer.getStakingToken())).transferFrom( - msg.sender, - address(this), - newStakeAmount - oldStakeAmount - ), - "STAKING_TRANSFER_FAILED" - ); - } - - indexer.setIntent( - signerToken, - senderToken, - protocol, - newStakeAmount, - bytes32(uint256(uint160(address(this))) << 96) //NOTE: this will pad 0's to the right - ); - - if (oldStakeAmount > newStakeAmount) { - // return excess stake back - require( - IERC20(address(indexer.getStakingToken())).transfer( - msg.sender, - oldStakeAmount - newStakeAmount - ), - "STAKING_RETURN_FAILED" - ); - } - } - - /** - * @notice unsets a rule on the delegate and removes an intent on the indexer - * @dev only callable by owner - * @param senderToken address Maker token in the token pair for rules and intents - * @param signerToken address Taker token in the token pair for rules and intents - */ - function unsetRuleAndIntent( - address senderToken, - address signerToken - ) external onlyOwner { - _unsetRule(senderToken, signerToken); - - // Query the indexer for the amount staked. - uint256 stakedAmount = indexer.getStakedAmount( - address(this), - signerToken, - senderToken, - protocol - ); - indexer.unsetIntent(signerToken, senderToken, protocol); - - // Upon unstaking, the Delegate will be given the staking amount. - // This is returned to the msg.sender. - if (stakedAmount > 0) { - require( - IERC20(address(indexer.getStakingToken())).transfer( - msg.sender, - stakedAmount - ), - "STAKING_RETURN_FAILED" - ); - } - } - /** * @notice Provide an Order * @dev Rules get reset with new maxSenderAmount diff --git a/source/delegate/contracts/DelegateFactory.sol b/source/delegate/contracts/DelegateFactory.sol deleted file mode 100644 index 7b1061832..000000000 --- a/source/delegate/contracts/DelegateFactory.sol +++ /dev/null @@ -1,75 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -import "./Delegate.sol"; -import "./interfaces/IDelegateFactory.sol"; -import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; -import "@airswap/indexer/contracts/interfaces/ILocatorWhitelist.sol"; -import "@airswap/indexer/contracts/interfaces/IIndexer.sol"; - -contract DelegateFactory is IDelegateFactory, ILocatorWhitelist { - // Mapping specifying whether an address was deployed by this factory - mapping(address => bool) internal _deployedAddresses; - - // The swap and indexer contracts to use in the deployment of Delegates - ISwapERC20 public swapContract; - IIndexer public indexerContract; - bytes2 public protocol; - - /** - * @notice Create a new DelegateFactory contract - * @dev swapContract is unable to be changed after the factory sets it - * @param factorySwapContract address Swap contract the delegate will deploy with - * @param factoryIndexerContract address Indexer contract the delegate will deploy with - * @param factoryProtocol bytes2 Protocol type of the delegates the factory deploys - */ - constructor( - ISwapERC20 factorySwapContract, - IIndexer factoryIndexerContract, - bytes2 factoryProtocol - ) { - swapContract = factorySwapContract; - indexerContract = factoryIndexerContract; - protocol = factoryProtocol; - } - - /** - * @param delegateTradeWallet address Wallet the delegate will trade from - * @return delegateContractAddress address Address of the delegate contract created - */ - function createDelegate( - address delegateTradeWallet - ) external returns (address delegateContractAddress) { - delegateContractAddress = address( - new Delegate( - swapContract, - indexerContract, - msg.sender, - delegateTradeWallet, - protocol - ) - ); - _deployedAddresses[delegateContractAddress] = true; - - emit CreateDelegate( - delegateContractAddress, - address(swapContract), - address(indexerContract), - msg.sender, - delegateTradeWallet - ); - - return delegateContractAddress; - } - - /** - * @notice To check whether a locator was deployed - * @dev Implements ILocatorWhitelist.has - * @param locator bytes32 Locator of the delegate in question - * @return bool True if the delegate was deployed by this contract - */ - function has(bytes32 locator) external view returns (bool) { - return _deployedAddresses[address(bytes20(locator))]; - } -} diff --git a/source/delegate/deploys-blocks.js b/source/delegate/deploys-blocks.js index 490b26825..4ba52ba2c 100644 --- a/source/delegate/deploys-blocks.js +++ b/source/delegate/deploys-blocks.js @@ -1,21 +1 @@ -module.exports = { - 1: 18337329, - 5: 9854680, - 30: 5717948, - 31: 4378661, - 40: 305834078, - 41: 262335361, - 56: 32550529, - 97: 34150670, - 137: 48645401, - 8453: 5180096, - 42161: 140046382, - 43113: 26720218, - 43114: 36367783, - 59140: 1711053, - 59144: 619127, - 80001: 41133390, - 84531: 10978032, - 421613: 47402006, - 11155111: 4509265, -} +module.exports = {} diff --git a/source/delegate/deploys.js b/source/delegate/deploys.js index e7896c009..4ba52ba2c 100644 --- a/source/delegate/deploys.js +++ b/source/delegate/deploys.js @@ -1,21 +1 @@ -module.exports = { - 1: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 5: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 30: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 31: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 40: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 41: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 56: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 97: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 137: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 8453: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 42161: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 43113: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 43114: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 59140: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 59144: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 80001: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 84531: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 421613: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 11155111: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', -} +module.exports = {} diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 5bc84ae24..d7eccc595 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -13,7 +13,7 @@ function toWei(value, places) { return toAtomicString(value, places || 18) } -describe('Pool Unit', () => { +describe('Delefate Unit', () => { let deployer let alice let bob @@ -35,10 +35,5 @@ describe('Pool Unit', () => { delegate = await (await ethers.getContractFactory('Delegate')).deploy() await delegate.deployed() - - delegateFactory = await ( - await ethers.getContractFactory('DelegateFactory') - ).deploy() - await delegateFactory.deployed() }) }) From c3881350d65849557df3b401c13d4ede3f4fb486 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 8 Jan 2024 20:25:50 -0500 Subject: [PATCH 06/43] Removed the indexer boilerplate and adjusted the delegate placeholder contract accordingly. Removed the delegateFactory contract --- source/indexer/LICENSE | 19 - source/indexer/README.md | 37 -- source/indexer/contracts/Index.sol | 253 ----------- source/indexer/contracts/Indexer.sol | 333 -------------- .../indexer/contracts/interfaces/IIndexer.sol | 80 ---- .../interfaces/ILocatorWhitelist.sol | 7 - source/indexer/deploys-blocks.js | 21 - source/indexer/deploys.js | 21 - source/indexer/deploys.js.d.ts | 2 - source/indexer/hardhat.config.js | 6 - source/indexer/package.json | 43 -- source/indexer/scripts/balances.js | 71 --- source/indexer/scripts/deploy.js | 74 ---- source/indexer/scripts/migrate-abis/4-1-1.js | 416 ------------------ source/indexer/scripts/migrate.js | 76 ---- source/indexer/scripts/owner.js | 14 - source/indexer/scripts/verify.js | 27 -- source/indexer/test/Indexer.js | 40 -- source/indexer/tsconfig.json | 7 - 19 files changed, 1547 deletions(-) delete mode 100644 source/indexer/LICENSE delete mode 100644 source/indexer/README.md delete mode 100644 source/indexer/contracts/Index.sol delete mode 100644 source/indexer/contracts/Indexer.sol delete mode 100644 source/indexer/contracts/interfaces/IIndexer.sol delete mode 100644 source/indexer/contracts/interfaces/ILocatorWhitelist.sol delete mode 100644 source/indexer/deploys-blocks.js delete mode 100644 source/indexer/deploys.js delete mode 100644 source/indexer/deploys.js.d.ts delete mode 100644 source/indexer/hardhat.config.js delete mode 100644 source/indexer/package.json delete mode 100644 source/indexer/scripts/balances.js delete mode 100644 source/indexer/scripts/deploy.js delete mode 100644 source/indexer/scripts/migrate-abis/4-1-1.js delete mode 100644 source/indexer/scripts/migrate.js delete mode 100644 source/indexer/scripts/owner.js delete mode 100644 source/indexer/scripts/verify.js delete mode 100644 source/indexer/test/Indexer.js delete mode 100644 source/indexer/tsconfig.json diff --git a/source/indexer/LICENSE b/source/indexer/LICENSE deleted file mode 100644 index 25fb212c5..000000000 --- a/source/indexer/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2023 AirSwap - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/source/indexer/README.md b/source/indexer/README.md deleted file mode 100644 index 37de1296a..000000000 --- a/source/indexer/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# Pool - -[AirSwap](https://www.airswap.io/) is an open-source peer-to-peer trading network. - -[![Discord](https://img.shields.io/discord/590643190281928738.svg)](https://discord.gg/ecQbV7H) -[![License](https://img.shields.io/badge/License-MIT-blue)](https://opensource.org/licenses/MIT) -![Twitter Follow](https://img.shields.io/twitter/follow/airswap?style=social) - -## Resources - -- About → https://about.airswap.io/ -- Website → https://www.airswap.io/ -- Twitter → https://twitter.com/airswap -- Chat → https://chat.airswap.io/ - -## Usage - -:warning: This package may contain unaudited code. For all AirSwap contract deployments see [Deployed Contracts](https://about.airswap.io/technology/deployments). - -## Commands - -Environment variables are set in an `.env` file in the repository root. - -| Command | Description | -| :--------------- | :--------------------------------------- | -| `yarn` | Install dependencies | -| `yarn clean` | Delete the contract `build` folder | -| `yarn compile` | Compile all contracts to `build` folder | -| `yarn coverage` | Report test coverage | -| `yarn test` | Run all tests in `test` folder | -| `yarn test:ci` | Run CI tests in `test` folder | -| `yarn deploy` | Deploy on a network using --network flag | -| `yarn verify` | Verify on a network using --network flag | - -## Running Tests - -:bulb: Prior to testing locally, run `yarn compile` in the `airswap-protocols` project root to build required artifacts. diff --git a/source/indexer/contracts/Index.sol b/source/indexer/contracts/Index.sol deleted file mode 100644 index dc0277813..000000000 --- a/source/indexer/contracts/Index.sol +++ /dev/null @@ -1,253 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -import "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @title Index: A List of Locators - * @notice The Locators are sorted in reverse order based on the score - * meaning that the first element in the list has the largest score - * and final element has the smallest - * @dev A mapping is used to mimic a circular linked list structure - * where every mapping Entry contains a pointer to the next - * and the previous - */ -contract Index is Ownable { - /** - * @notice Index Entry - * @param score uint256 - * @param locator bytes32 - * @param prev address Previous address in the linked list - * @param next address Next address in the linked list - */ - struct Entry { - bytes32 locator; - uint256 score; - address prev; - address next; - } - - // The number of entries in the index - uint256 public length; - - // Identifier to use for the head of the list - address internal constant HEAD = address(uint160(2 ** 160 - 1)); - - // Mapping of an identifier to its entry - mapping(address => Entry) public entries; - - /** - * @notice Contract Events - */ - event SetLocator( - address indexed identifier, - uint256 score, - bytes32 indexed locator - ); - - event UnsetLocator(address indexed identifier); - - /** - * @notice Contract Constructor - */ - constructor() { - // Create initial entry. - entries[HEAD] = Entry(bytes32(0), 0, HEAD, HEAD); - } - - /** - * @notice Set a Locator - * @param identifier address On-chain address identifying the owner of a locator - * @param score uint256 Score for the locator being set - * @param locator bytes32 Locator - */ - function setLocator( - address identifier, - uint256 score, - bytes32 locator - ) external onlyOwner { - // Ensure the entry does not already exist. - require(!_hasEntry(identifier), "ENTRY_ALREADY_EXISTS"); - - _setLocator(identifier, score, locator); - - // Increment the index length. - length = length + 1; - emit SetLocator(identifier, score, locator); - } - - /** - * @notice Unset a Locator - * @param identifier address On-chain address identifying the owner of a locator - */ - function unsetLocator(address identifier) external onlyOwner { - _unsetLocator(identifier); - - // Decrement the index length. - length = length - 1; - emit UnsetLocator(identifier); - } - - /** - * @notice Update a Locator - * @dev score and/or locator do not need to be different from old values - * @param identifier address On-chain address identifying the owner of a locator - * @param score uint256 Score for the locator being set - * @param locator bytes32 Locator - */ - function updateLocator( - address identifier, - uint256 score, - bytes32 locator - ) external onlyOwner { - // Don't need to update length as it is not used in set/unset logic - _unsetLocator(identifier); - _setLocator(identifier, score, locator); - - emit SetLocator(identifier, score, locator); - } - - /** - * @notice Get a Score - * @param identifier address On-chain address identifying the owner of a locator - * @return uint256 Score corresponding to the identifier - */ - function getScore(address identifier) external view returns (uint256) { - return entries[identifier].score; - } - - /** - * @notice Get a Locator - * @param identifier address On-chain address identifying the owner of a locator - * @return bytes32 Locator information - */ - function getLocator(address identifier) external view returns (bytes32) { - return entries[identifier].locator; - } - - /** - * @notice Get a Range of Locators - * @dev start value of 0x0 starts at the head - * @param cursor address Cursor to start with - * @param limit uint256 Maximum number of locators to return - * @return locators bytes32[] List of locators - * @return scores uint256[] List of scores corresponding to locators - * @return nextCursor address The next cursor to provide for pagination - */ - function getLocators( - address cursor, - uint256 limit - ) - external - view - returns ( - bytes32[] memory locators, - uint256[] memory scores, - address nextCursor - ) - { - address identifier; - - // If a valid cursor is provided, start there. - if (cursor != address(0) && cursor != HEAD) { - // Check that the provided cursor exists. - if (!_hasEntry(cursor)) { - return (new bytes32[](0), new uint256[](0), address(0)); - } - // Set the starting identifier to the provided cursor. - identifier = cursor; - } else { - identifier = entries[HEAD].next; - } - - // Although it's not known how many entries are between `cursor` and the end - // We know that it is no more than `length` - uint256 size = (length < limit) ? length : limit; - - locators = new bytes32[](size); - scores = new uint256[](size); - - // Iterate over the list until the end or size. - uint256 i; - while (i < size && identifier != HEAD) { - locators[i] = entries[identifier].locator; - scores[i] = entries[identifier].score; - i = i + 1; - identifier = entries[identifier].next; - } - - return (locators, scores, identifier); - } - - /** - * @notice Internal function to set a Locator - * @param identifier address On-chain address identifying the owner of a locator - * @param score uint256 Score for the locator being set - * @param locator bytes32 Locator - */ - function _setLocator( - address identifier, - uint256 score, - bytes32 locator - ) internal { - // Disallow locator set to 0x0 to ensure list integrity. - require(locator != bytes32(0), "LOCATOR_MUST_BE_SENT"); - - // Find the first entry with a lower score. - address nextEntry = _getEntryLowerThan(score); - - // Link the new entry between previous and next. - address prevEntry = entries[nextEntry].prev; - entries[prevEntry].next = identifier; - entries[nextEntry].prev = identifier; - entries[identifier] = Entry(locator, score, prevEntry, nextEntry); - } - - /** - * @notice Internal function to unset a Locator - * @param identifier address On-chain address identifying the owner of a locator - */ - function _unsetLocator(address identifier) internal { - // Ensure the entry exists. - require(_hasEntry(identifier), "ENTRY_DOES_NOT_EXIST"); - - // Link the previous and next entries together. - address prevUser = entries[identifier].prev; - address nextUser = entries[identifier].next; - entries[prevUser].next = nextUser; - entries[nextUser].prev = prevUser; - - // Delete entry from the index. - delete entries[identifier]; - } - - /** - * @notice Check if the Index has an Entry - * @param identifier address On-chain address identifying the owner of a locator - * @return bool True if the identifier corresponds to an Entry in the list - */ - function _hasEntry(address identifier) internal view returns (bool) { - return entries[identifier].locator != bytes32(0); - } - - /** - * @notice Returns the largest scoring Entry Lower than a Score - * @param score uint256 Score in question - * @return address Identifier of the largest score lower than score - */ - function _getEntryLowerThan(uint256 score) internal view returns (address) { - address identifier = entries[HEAD].next; - - // Head indicates last because the list is circular. - if (score == 0) { - return HEAD; - } - - // Iterate until a lower score is found. - while (score <= entries[identifier].score) { - identifier = entries[identifier].next; - } - return identifier; - } -} diff --git a/source/indexer/contracts/Indexer.sol b/source/indexer/contracts/Indexer.sol deleted file mode 100644 index 3b1d91c6a..000000000 --- a/source/indexer/contracts/Indexer.sol +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -import "./Index.sol"; -import "./interfaces/IIndexer.sol"; -import "./interfaces/ILocatorWhitelist.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @title Indexer: A Collection of Index contracts by Token Pair - */ -contract Indexer is IIndexer, Ownable { - // Token to be used for staking (ERC-20) - IERC20 public stakingToken; - - // Mapping of signer token to sender token to protocol type to index - // Index is referenced by address - mapping(address => mapping(address => mapping(bytes2 => address))) - public indexes; - - // The whitelist contract for checking whether a peer is whitelisted per peer type - mapping(bytes2 => address) public locatorWhitelists; - - // Mapping of token address to boolean - mapping(address => bool) public tokenBlacklist; - - /** - * @notice Contract Constructor - * @param indexerStakingToken address - */ - constructor(address indexerStakingToken) { - stakingToken = IERC20(indexerStakingToken); - } - - /** - * @notice Modifier to check an index exists - */ - modifier indexExists( - address signerToken, - address senderToken, - bytes2 protocol - ) { - require( - indexes[signerToken][senderToken][protocol] != address(0), - "INDEX_DOES_NOT_EXIST" - ); - _; - } - - /** - * @notice Set the address of an ILocatorWhitelist to use - * @dev Allows removal of locatorWhitelist by passing 0x0 - * @param protocol bytes2 Protocol type for locators - * @param newLocatorWhitelist address Locator whitelist - */ - function setLocatorWhitelist( - bytes2 protocol, - address newLocatorWhitelist - ) external onlyOwner { - locatorWhitelists[protocol] = newLocatorWhitelist; - } - - /** - * @notice Create an Index (List of Locators for a Token Pair) - * @dev Deploys a new Index contract and stores the address. If the Index already - * @dev exists, returns its address, and does not emit a CreateIndex event - * @param signerToken address Signer token for the Index - * @param senderToken address Sender token for the Index - * @param protocol bytes2 Protocol type for locators in Index - */ - function createIndex( - address signerToken, - address senderToken, - bytes2 protocol - ) external returns (address) { - // If the Index does not exist, create it. - if (indexes[signerToken][senderToken][protocol] == address(0)) { - // Create a new Index contract for the token pair. - Index index = new Index(); - indexes[signerToken][senderToken][protocol] = address(index); - - emit CreateIndex( - signerToken, - senderToken, - protocol, - address(indexes[signerToken][senderToken][protocol]) - ); - } - - // Return the address of the Index contract. - return address(indexes[signerToken][senderToken][protocol]); - } - - /** - * @notice Add a Token to the Blacklist - * @param token address Token to blacklist - */ - function addTokenToBlacklist(address token) external onlyOwner { - if (!tokenBlacklist[token]) { - tokenBlacklist[token] = true; - emit AddTokenToBlacklist(token); - } - } - - /** - * @notice Remove a Token from the Blacklist - * @param token address Token to remove from the blacklist - */ - function removeTokenFromBlacklist(address token) external onlyOwner { - if (tokenBlacklist[token]) { - tokenBlacklist[token] = false; - emit RemoveTokenFromBlacklist(token); - } - } - - /** - * @notice Set an Intent to Trade - * @dev Requires approval to transfer staking token for sender - * - * @param signerToken address Signer token of the Index being staked - * @param senderToken address Sender token of the Index being staked - * @param protocol bytes2 Protocol type for locator in Intent - * @param stakingAmount uint256 Amount being staked - * @param locator bytes32 Locator of the staker - */ - function setIntent( - address signerToken, - address senderToken, - bytes2 protocol, - uint256 stakingAmount, - bytes32 locator - ) external indexExists(signerToken, senderToken, protocol) { - // If whitelist set, ensure the locator is valid. - if (locatorWhitelists[protocol] != address(0)) { - require( - ILocatorWhitelist(locatorWhitelists[protocol]).has(locator), - "LOCATOR_NOT_WHITELISTED" - ); - } - - // Ensure neither of the tokens are blacklisted. - require( - !tokenBlacklist[signerToken] && !tokenBlacklist[senderToken], - "PAIR_IS_BLACKLISTED" - ); - - bool notPreviouslySet = (Index(indexes[signerToken][senderToken][protocol]) - .getLocator(msg.sender) == bytes32(0)); - - if (notPreviouslySet) { - // Only transfer for staking if stakingAmount is set. - if (stakingAmount > 0) { - // Transfer the stakingAmount for staking. - require( - stakingToken.transferFrom(msg.sender, address(this), stakingAmount), - "STAKING_FAILED" - ); - } - // Set the locator on the index. - Index(indexes[signerToken][senderToken][protocol]).setLocator( - msg.sender, - stakingAmount, - locator - ); - - emit Stake(msg.sender, signerToken, senderToken, protocol, stakingAmount); - } else { - uint256 oldStake = Index(indexes[signerToken][senderToken][protocol]) - .getScore(msg.sender); - - _updateIntent( - msg.sender, - signerToken, - senderToken, - protocol, - stakingAmount, - locator, - oldStake - ); - } - } - - /** - * @notice Unset an Intent to Trade - * @dev Users are allowed to unstake from blacklisted indexes - * - * @param signerToken address Signer token of the Index being unstaked - * @param senderToken address Sender token of the Index being staked - * @param protocol bytes2 Protocol type for locators in Intent - */ - function unsetIntent( - address signerToken, - address senderToken, - bytes2 protocol - ) external { - _unsetIntent(msg.sender, signerToken, senderToken, protocol); - } - - /** - * @notice Get the locators of those trading a token pair - * @dev Users are allowed to unstake from blacklisted indexes - * - * @param signerToken address Signer token of the trading pair - * @param senderToken address Sender token of the trading pair - * @param protocol bytes2 Protocol type for locators in Intent - * @param cursor address Address to start from - * @param limit uint256 Total number of locators to return - * @return locators bytes32[] List of locators - * @return scores uint256[] List of scores corresponding to locators - * @return nextCursor address The next cursor to provide for pagination - */ - function getLocators( - address signerToken, - address senderToken, - bytes2 protocol, - address cursor, - uint256 limit - ) - external - view - returns ( - bytes32[] memory locators, - uint256[] memory scores, - address nextCursor - ) - { - // Ensure neither token is blacklisted. - if (tokenBlacklist[signerToken] || tokenBlacklist[senderToken]) { - return (new bytes32[](0), new uint256[](0), address(0)); - } - - // Ensure the index exists. - if (indexes[signerToken][senderToken][protocol] == address(0)) { - return (new bytes32[](0), new uint256[](0), address(0)); - } - - return - Index(indexes[signerToken][senderToken][protocol]).getLocators( - cursor, - limit - ); - } - - /** - * @notice Gets the Stake Amount for a User - * @param user address User who staked - * @param signerToken address Signer token the user staked on - * @param senderToken address Sender token the user staked on - * @param protocol bytes2 Protocol type for locators in Intent - * @return stakedAmount uint256 Amount the user staked - */ - function getStakedAmount( - address user, - address signerToken, - address senderToken, - bytes2 protocol - ) public view returns (uint256 stakedAmount) { - if (indexes[signerToken][senderToken][protocol] == address(0)) { - return 0; - } - // Return the score, equivalent to the stake amount. - return Index(indexes[signerToken][senderToken][protocol]).getScore(user); - } - - function _updateIntent( - address user, - address signerToken, - address senderToken, - bytes2 protocol, - uint256 newAmount, - bytes32 newLocator, - uint256 oldAmount - ) internal { - // If the new stake is bigger, collect the difference. - if (oldAmount < newAmount) { - // Note: SafeMath not required due to the inequality check above - require( - stakingToken.transferFrom(user, address(this), newAmount - oldAmount), - "STAKING_FAILED" - ); - } - - // If the old stake is bigger, return the excess. - if (newAmount < oldAmount) { - // Note: SafeMath not required due to the inequality check above - require(stakingToken.transfer(user, oldAmount - newAmount)); - } - - // Update their intent. - Index(indexes[signerToken][senderToken][protocol]).updateLocator( - user, - newAmount, - newLocator - ); - - emit Stake(user, signerToken, senderToken, protocol, newAmount); - } - - /** - * @notice Unset intents and return staked tokens - * @param user address Address of the user who staked - * @param signerToken address Signer token of the trading pair - * @param senderToken address Sender token of the trading pair - * @param protocol bytes2 Protocol type for locators in Intent - */ - function _unsetIntent( - address user, - address signerToken, - address senderToken, - bytes2 protocol - ) internal indexExists(signerToken, senderToken, protocol) { - // Get the score for the user. - uint256 score = Index(indexes[signerToken][senderToken][protocol]).getScore( - user - ); - - // Unset the locator on the index. - Index(indexes[signerToken][senderToken][protocol]).unsetLocator(user); - - if (score > 0) { - // Return the staked tokens. Reverts on failure. - require(stakingToken.transfer(user, score)); - } - - emit Unstake(user, signerToken, senderToken, protocol, score); - } - - function getStakingToken() public view returns (address) { - return address(stakingToken); - } -} diff --git a/source/indexer/contracts/interfaces/IIndexer.sol b/source/indexer/contracts/interfaces/IIndexer.sol deleted file mode 100644 index 47e0df773..000000000 --- a/source/indexer/contracts/interfaces/IIndexer.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -interface IIndexer { - event CreateIndex( - address indexed signerToken, - address indexed senderToken, - bytes2 protocol, - address indexAddress - ); - - event Stake( - address indexed staker, - address indexed signerToken, - address indexed senderToken, - bytes2 protocol, - uint256 stakeAmount - ); - - event Unstake( - address indexed staker, - address indexed signerToken, - address indexed senderToken, - bytes2 protocol, - uint256 stakeAmount - ); - - event AddTokenToBlacklist(address token); - - event RemoveTokenFromBlacklist(address token); - - function setLocatorWhitelist( - bytes2 protocol, - address newLocatorWhitelist - ) external; - - function createIndex( - address signerToken, - address senderToken, - bytes2 protocol - ) external returns (address); - - function addTokenToBlacklist(address token) external; - - function removeTokenFromBlacklist(address token) external; - - function setIntent( - address signerToken, - address senderToken, - bytes2 protocol, - uint256 stakingAmount, - bytes32 locator - ) external; - - function unsetIntent( - address signerToken, - address senderToken, - bytes2 protocol - ) external; - - function getStakingToken() external view returns (address); - - function tokenBlacklist(address) external view returns (bool); - - function getStakedAmount( - address user, - address signerToken, - address senderToken, - bytes2 protocol - ) external view returns (uint256); - - function getLocators( - address signerToken, - address senderToken, - bytes2 protocol, - address cursor, - uint256 limit - ) external view returns (bytes32[] memory, uint256[] memory, address); -} diff --git a/source/indexer/contracts/interfaces/ILocatorWhitelist.sol b/source/indexer/contracts/interfaces/ILocatorWhitelist.sol deleted file mode 100644 index 7d9a257a1..000000000 --- a/source/indexer/contracts/interfaces/ILocatorWhitelist.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -interface ILocatorWhitelist { - function has(bytes32 locator) external view returns (bool); -} diff --git a/source/indexer/deploys-blocks.js b/source/indexer/deploys-blocks.js deleted file mode 100644 index 490b26825..000000000 --- a/source/indexer/deploys-blocks.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 1: 18337329, - 5: 9854680, - 30: 5717948, - 31: 4378661, - 40: 305834078, - 41: 262335361, - 56: 32550529, - 97: 34150670, - 137: 48645401, - 8453: 5180096, - 42161: 140046382, - 43113: 26720218, - 43114: 36367783, - 59140: 1711053, - 59144: 619127, - 80001: 41133390, - 84531: 10978032, - 421613: 47402006, - 11155111: 4509265, -} diff --git a/source/indexer/deploys.js b/source/indexer/deploys.js deleted file mode 100644 index e7896c009..000000000 --- a/source/indexer/deploys.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - 1: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 5: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 30: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 31: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 40: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 41: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 56: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 97: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 137: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 8453: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 42161: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 43113: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 43114: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 59140: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 59144: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 80001: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 84531: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 421613: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', - 11155111: '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11', -} diff --git a/source/indexer/deploys.js.d.ts b/source/indexer/deploys.js.d.ts deleted file mode 100644 index 31683c18a..000000000 --- a/source/indexer/deploys.js.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare module '@airswap/pool/deploys.js' -declare module '@airswap/pool/deploys-blocks.js' diff --git a/source/indexer/hardhat.config.js b/source/indexer/hardhat.config.js deleted file mode 100644 index 4b553c55b..000000000 --- a/source/indexer/hardhat.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - typechain: { - outDir: 'typechain', - }, - ...require('../../hardhat.config.js'), -} diff --git a/source/indexer/package.json b/source/indexer/package.json deleted file mode 100644 index 30dd0d999..000000000 --- a/source/indexer/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@airswap/indexer", - "version": "4.1.4", - "description": "AirSwap: Trade Indexer", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/airswap/airswap-protocols" - }, - "files": [ - "./build", - "./typechain", - "./deploys.js", - "./deploys-blocks.js", - "./deploys.js.d.ts" - ], - "scripts": { - "clean": "rm -rf ./cache && rm -rf ./build && rm -rf ./typechain", - "compile": "hardhat compile; yarn typechain", - "typechain": "tsc -b", - "coverage": "hardhat coverage", - "test": "hardhat test", - "test:ci": "hardhat test", - "deploy": "hardhat run ./scripts/deploy.js", - "verify": "hardhat run ./scripts/verify.js", - "owners": "hardhat run ./scripts/owner.js", - "migrate": "hardhat run ./scripts/migrate.js", - "balances": "hardhat run ./scripts/balances.js" - }, - "dependencies": { - "@openzeppelin/contracts": "^4.8.3" - }, - "devDependencies": { - "@airswap/constants": "4.1.6", - "@airswap/metadata": "4.1.12", - "@airswap/types": "4.1.1", - "@airswap/utils": "4.1.8", - "prompt-confirm": "^2.0.4" - }, - "publishConfig": { - "access": "public" - } -} diff --git a/source/indexer/scripts/balances.js b/source/indexer/scripts/balances.js deleted file mode 100644 index f1bd5ad48..000000000 --- a/source/indexer/scripts/balances.js +++ /dev/null @@ -1,71 +0,0 @@ -const { ethers } = require('hardhat') -const { getKnownTokens } = require('@airswap/metadata') -const { chainNames, ChainIds } = require('@airswap/constants') -const BalanceChecker = require('@airswap/balances/build/contracts/BalanceChecker.sol/BalanceChecker.json') -const balancesDeploys = require('@airswap/balances/deploys.js') -const poolDeploys = require('../deploys.js') - -async function main() { - const [account] = await ethers.getSigners() - const chainId = await account.getChainId() - if (chainId === ChainIds.HARDHAT) { - console.log('Value for --network flag is required') - return - } - console.log('Account:', account.address) - console.log('Network:', chainNames[chainId].toUpperCase()) - console.log('\nPool:', poolDeploys[chainId]) - - if (!balancesDeploys[chainId]) { - throw new Error('Unable to check balances on this chain.') - } - - const tokens = (await getKnownTokens(Number(chainId))).tokens - - let count = tokens.length - const addresses = [] - while (count--) { - if (ethers.utils.isAddress(tokens[count].address)) { - addresses.push(tokens[count].address.toLowerCase()) - } - } - - console.log(`\nScanning non-zero balances for ${tokens.length} tokens...\n`) - - const balancesContract = new ethers.Contract( - balancesDeploys[chainId], - BalanceChecker.abi, - account.provider - ) - - const chunk = 750 - let balances = [] - let index = 0 - count = addresses.length - while (index < count) { - balances = balances.concat( - await balancesContract.walletBalances( - poolDeploys[chainId], - addresses.slice(index, index + chunk) - ) - ) - index += chunk - } - - const result = [] - for (let i = 0; i < balances.length; i++) { - if (!balances[i].eq(0)) { - result.push(addresses[i]) - } - } - - console.log('Non-zero balances in', result.length, 'tokens:\n') - console.log(JSON.stringify(result)) -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/indexer/scripts/deploy.js b/source/indexer/scripts/deploy.js deleted file mode 100644 index abfe460a4..000000000 --- a/source/indexer/scripts/deploy.js +++ /dev/null @@ -1,74 +0,0 @@ -/* eslint-disable no-console */ -const fs = require('fs') -const prettier = require('prettier') -const Confirm = require('prompt-confirm') -const { ethers, run } = require('hardhat') -const { chainLabels, chainNames, ChainIds } = require('@airswap/constants') -const { getReceiptUrl } = require('@airswap/utils') -const poolDeploys = require('../deploys.js') -const poolBlocks = require('../deploys-blocks.js') - -async function main() { - await run('compile') - const config = await prettier.resolveConfig('../deploys.js') - - const [deployer] = await ethers.getSigners() - const gasPrice = await deployer.getGasPrice() - const chainId = await deployer.getChainId() - if (chainId === ChainIds.HARDHAT) { - console.log('Value for --network flag is required') - return - } - console.log(`Deployer: ${deployer.address}`) - console.log(`Network: ${chainNames[chainId].toUpperCase()}`) - console.log(`Gas price: ${gasPrice / 10 ** 9} gwei\n`) - - const scale = 10 - const max = 100 - - const prompt = new Confirm('Proceed to deploy?') - if (await prompt.run()) { - const poolFactory = await ethers.getContractFactory('Pool') - const poolContract = await poolFactory.deploy(scale, max, { - gasPrice, - }) - console.log( - 'Deploying...', - getReceiptUrl(chainId, poolContract.deployTransaction.hash) - ) - await poolContract.deployed() - - poolDeploys[chainId] = poolContract.address - fs.writeFileSync( - './deploys.js', - prettier.format( - `module.exports = ${JSON.stringify(poolDeploys, null, '\t')}`, - { ...config, parser: 'babel' } - ) - ) - poolBlocks[chainId] = ( - await poolContract.deployTransaction.wait() - ).blockNumber - fs.writeFileSync( - './deploys-blocks.js', - prettier.format( - `module.exports = ${JSON.stringify(poolBlocks, null, '\t')}`, - { ...config, parser: 'babel' } - ) - ) - console.log(`Deployed: ${poolDeploys[chainId]} @ ${poolBlocks[chainId]}`) - - console.log( - `\nVerify with "yarn verify --network ${chainLabels[ - chainId - ].toLowerCase()}"\n` - ) - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/indexer/scripts/migrate-abis/4-1-1.js b/source/indexer/scripts/migrate-abis/4-1-1.js deleted file mode 100644 index 27293305e..000000000 --- a/source/indexer/scripts/migrate-abis/4-1-1.js +++ /dev/null @@ -1,416 +0,0 @@ -module.exports = { - abi: [ - { - inputs: [ - { internalType: 'uint256', name: '_scale', type: 'uint256' }, - { internalType: 'uint256', name: '_max', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'AddressInvalid', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'AdminNotSet', - type: 'error', - }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'AmountInsufficient', - type: 'error', - }, - { inputs: [], name: 'ClaimAlreadyUsed', type: 'error' }, - { inputs: [], name: 'ClaimsNotProvided', type: 'error' }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'MaxTooHigh', - type: 'error', - }, - { - inputs: [ - { internalType: 'bytes32', name: '', type: 'bytes32' }, - { internalType: 'bytes32', name: '', type: 'bytes32' }, - ], - name: 'ProofInvalid', - type: 'error', - }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'ScaleTooHigh', - type: 'error', - }, - { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - name: 'TreeNotEnabled', - type: 'error', - }, - { inputs: [], name: 'Unauthorized', type: 'error' }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address[]', - name: 'tokens', - type: 'address[]', - }, - { - indexed: false, - internalType: 'address', - name: 'dest', - type: 'address', - }, - ], - name: 'DrainTo', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'bytes32', - name: 'tree', - type: 'bytes32', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'root', - type: 'bytes32', - }, - ], - name: 'Enable', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'previousOwner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'newOwner', - type: 'address', - }, - ], - name: 'OwnershipTransferStarted', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'previousOwner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'newOwner', - type: 'address', - }, - ], - name: 'OwnershipTransferred', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'admin', - type: 'address', - }, - ], - name: 'SetAdmin', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: 'max', - type: 'uint256', - }, - ], - name: 'SetMax', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: 'scale', - type: 'uint256', - }, - ], - name: 'SetScale', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'admin', - type: 'address', - }, - ], - name: 'UnsetAdmin', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'tree', - type: 'bytes32', - }, - ], - name: 'UseClaim', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: false, - internalType: 'address', - name: 'recipient', - type: 'address', - }, - { - indexed: false, - internalType: 'address', - name: 'token', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - ], - name: 'Withdraw', - type: 'event', - }, - { - inputs: [], - name: 'acceptOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'admins', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'uint256', name: '_value', type: 'uint256' }, - { internalType: 'address', name: '_token', type: 'address' }, - ], - name: 'calculate', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '', type: 'bytes32' }, - { internalType: 'address', name: '', type: 'address' }, - ], - name: 'claimed', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address[]', name: '_tokens', type: 'address[]' }, - { internalType: 'address', name: '_dest', type: 'address' }, - ], - name: 'drainTo', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - ], - name: 'enable', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - { internalType: 'address[]', name: '_accounts', type: 'address[]' }, - ], - name: 'enableAndSetClaimed', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: '_account', type: 'address' }, - { internalType: 'bytes32[]', name: '_trees', type: 'bytes32[]' }, - ], - name: 'getStatus', - outputs: [{ internalType: 'bool[]', name: '', type: 'bool[]' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'max', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'owner', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'pendingOwner', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'renounceOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - name: 'rootsByTree', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'scale', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], - name: 'setAdmin', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'uint256', name: '_max', type: 'uint256' }], - name: 'setMax', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'uint256', name: '_scale', type: 'uint256' }], - name: 'setScale', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], - name: 'transferOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], - name: 'unsetAdmin', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: '_claimant', type: 'address' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - { internalType: 'uint256', name: '_value', type: 'uint256' }, - { internalType: 'bytes32[]', name: '_proof', type: 'bytes32[]' }, - ], - name: 'verify', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'pure', - type: 'function', - }, - { - inputs: [ - { - components: [ - { internalType: 'bytes32', name: 'tree', type: 'bytes32' }, - { internalType: 'uint256', name: 'value', type: 'uint256' }, - { internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' }, - ], - internalType: 'struct IPool.Claim[]', - name: '_claims', - type: 'tuple[]', - }, - { internalType: 'address', name: '_token', type: 'address' }, - { internalType: 'uint256', name: '_minimum', type: 'uint256' }, - { internalType: 'address', name: '_recipient', type: 'address' }, - ], - name: 'withdraw', - outputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }], - stateMutability: 'nonpayable', - type: 'function', - }, - ], -} diff --git a/source/indexer/scripts/migrate.js b/source/indexer/scripts/migrate.js deleted file mode 100644 index 0bc28adcb..000000000 --- a/source/indexer/scripts/migrate.js +++ /dev/null @@ -1,76 +0,0 @@ -const Confirm = require('prompt-confirm') -const { ethers } = require('hardhat') -const { chainNames, ChainIds } = require('@airswap/constants') -const { getReceiptUrl } = require('@airswap/utils') - -const { Pool__factory } = require('../typechain/factories/contracts') -const { abi } = require('./migrate-abis/4-1-1.js') -const deploys = require('../deploys.js') - -const CONFIRMATIONS = 2 -const PREVIOUS_POOL = '0xEEcD248D977Fd4D392915b4AdeF8154BA3aE9c02' -const NEW_POOL = '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11' - -async function main() { - const [account] = await ethers.getSigners() - const chainId = await account.getChainId() - if (chainId === ChainIds.HARDHAT) { - console.log('Value for --network flag is required') - return - } - console.log(`Account: ${account.address}`) - console.log(`Network: ${chainNames[chainId].toUpperCase()}\n`) - console.log(`From-pool: ${PREVIOUS_POOL}`) - console.log(`To-pool: ${NEW_POOL}`) - - const previousPool = new ethers.Contract(PREVIOUS_POOL, abi, account.provider) - const logs = await previousPool.queryFilter(previousPool.filters.UseClaim()) - - if (!logs.length) { - console.log('\n✘ No claim events found on from-pool.\n') - return - } - - const trees = {} - let i = logs.length - while (i--) { - const e = logs[i].decode(logs[i].data) - if (!trees[e.tree]) { - trees[e.tree] = [e.account] - } else { - trees[e.tree].push(e.account) - } - } - - const newPool = Pool__factory.connect(deploys[chainId], account) - const isAdmin = await newPool.admins(account.address) - if (!isAdmin) { - console.log('\n✘ Current account must be admin on to-pool.\n') - return - } - - for (const tree in trees) { - const root = await previousPool.rootsByTree(tree) - console.log('\nTree:', tree) - console.log('Root:', root) - console.log('Claims', trees[tree]) - - const gasPrice = await account.getGasPrice() - console.log(`\nGas price: ${gasPrice / 10 ** 9} gwei\n`) - - const prompt = new Confirm(`Enable and set above as claimed on to-pool?`) - if (await prompt.run()) { - const tx = await newPool.enableAndSetClaimed(tree, root, trees[tree]) - console.log('Updating...', getReceiptUrl(chainId, tx.hash), '\n') - await tx.wait(CONFIRMATIONS) - console.log(`✔ Completed for tree ${tree}`) - } - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/indexer/scripts/owner.js b/source/indexer/scripts/owner.js deleted file mode 100644 index bc2fc6a1b..000000000 --- a/source/indexer/scripts/owner.js +++ /dev/null @@ -1,14 +0,0 @@ -const { check } = require('../../../scripts/owners-update') -const { Pool__factory } = require('@airswap/pool/typechain/factories/contracts') -const poolDeploys = require('../deploys.js') - -async function main() { - await check('Pool', Pool__factory, poolDeploys) -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/indexer/scripts/verify.js b/source/indexer/scripts/verify.js deleted file mode 100644 index 4613111b2..000000000 --- a/source/indexer/scripts/verify.js +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable no-console */ -const { ethers, run } = require('hardhat') -const poolDeploys = require('../deploys.js') -const { chainNames } = require('@airswap/constants') - -async function main() { - await run('compile') - const [deployer] = await ethers.getSigners() - console.log(`Deployer: ${deployer.address}`) - - const chainId = await deployer.getChainId() - const scale = 10 - const max = 100 - - console.log(`Verifying on ${chainNames[chainId].toUpperCase()}`) - await run('verify:verify', { - address: poolDeploys[chainId], - constructorArguments: [scale, max], - }) -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/indexer/test/Indexer.js b/source/indexer/test/Indexer.js deleted file mode 100644 index 85135f1a9..000000000 --- a/source/indexer/test/Indexer.js +++ /dev/null @@ -1,40 +0,0 @@ -const { expect } = require('chai') -const { toAtomicString } = require('@airswap/utils') -const { generateTreeFromData, getRoot, getProof } = require('@airswap/merkle') -const { soliditySha3 } = require('web3-utils') - -const { ethers, waffle } = require('hardhat') -const { deployMockContract } = waffle -const IERC20 = require('@openzeppelin/contracts/build/contracts/IERC20.json') -const STAKING = require('@airswap/staking/build/contracts/Staking.sol/Staking.json') -const { ADDRESS_ZERO } = require('@airswap/constants') - -function toWei(value, places) { - return toAtomicString(value, places || 18) -} - -describe('Pool Unit', () => { - let deployer - let alice - let bob - - let pool - let snapshotId - - beforeEach(async () => { - snapshotId = await ethers.provider.send('evm_snapshot') - }) - - afterEach(async () => { - await ethers.provider.send('evm_revert', [snapshotId]) - }) - - before(async () => { - ;[deployer, alice, bob, carol] = await ethers.getSigners() - - pool = await ( - await ethers.getContractFactory('Pool') - ).deploy(CLAIM_SCALE, CLAIM_MAX) - await pool.deployed() - }) -}) diff --git a/source/indexer/tsconfig.json b/source/indexer/tsconfig.json deleted file mode 100644 index ce170734c..000000000 --- a/source/indexer/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./typechain" - }, - "files": ["./typechain/index.ts"] -} From d27ad6ff4976540589ccaac1177fc67bd27cdd75 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 1 Feb 2024 06:40:52 -0500 Subject: [PATCH 07/43] Removed IDelegateFactoryContract --- .../contracts/interfaces/IDelegateFactory.sol | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 source/delegate/contracts/interfaces/IDelegateFactory.sol diff --git a/source/delegate/contracts/interfaces/IDelegateFactory.sol b/source/delegate/contracts/interfaces/IDelegateFactory.sol deleted file mode 100644 index 5f321fede..000000000 --- a/source/delegate/contracts/interfaces/IDelegateFactory.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.17; - -interface IDelegateFactory { - event CreateDelegate( - address indexed delegateContract, - address swapContract, - address indexerContract, - address indexed delegateContractOwner, - address delegateTradeWallet - ); - - /** - * @notice Deploy a trusted delegate contract - * @param delegateTradeWallet the wallet the delegate will trade from - * @return delegateContractAddress address of the delegate contract created - */ - function createDelegate( - address delegateTradeWallet - ) external returns (address delegateContractAddress); -} From 67b6d43b73f575fd9397079dce5bd961afc0f258 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 29 Feb 2024 13:44:34 -0500 Subject: [PATCH 08/43] Created basics of the swap function for the delegate contract --- source/delegate/contracts/Delegate.sol | 379 +++--------------- .../contracts/interfaces/IDelegate.sol | 76 ++-- source/delegate/package.json | 28 +- source/delegate/test/Delegate.js | 197 ++++++++- 4 files changed, 304 insertions(+), 376 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 6381f0794..045da2f8c 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.17; +pragma solidity 0.8.23; import "./interfaces/IDelegate.sol"; import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title Delegate: Deployable Trading Rules for the AirSwap Network @@ -14,345 +14,90 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * @dev inherits IDelegate, Ownable uses SafeMath library */ contract Delegate is IDelegate, Ownable { - using SafeMath for uint256; - + using SafeERC20 for IERC20; // The Swap contract to be used to settle trades - ISwapERC20 public swapContract; - - // Maximum integer for token transfer approval - uint256 internal constant MAX_INT = 2 ** 256 - 1; - - // Address holding tokens that will be trading through this delegate - address public tradeWallet; - - // Mapping of senderToken to signerToken for rule lookup - mapping(address => mapping(address => Rule)) public rules; - - // ERC-20 (fungible token) interface identifier (ERC-165) - bytes4 internal constant ERC20_INTERFACE_ID = 0x36372b07; - - // The protocol identifier for setting intents on an Index - bytes2 public protocol; + ISwapERC20 public swapERC20; /** * @notice Contract Constructor - * @dev owner defaults to msg.sender if delegateContractOwner is provided as address(0) - * @param delegateSwap address Swap contract the delegate will deploy with - * @param delegateContractOwner address Owner of the delegate - * @param delegateTradeWallet address Wallet the delegate will trade from - * @param delegateProtocol bytes2 The protocol identifier for Delegate contracts */ - constructor( - ISwapERC20 delegateSwap, - address delegateContractOwner, - address delegateTradeWallet, - bytes2 delegateProtocol - ) { - swapContract = delegateSwap; - protocol = delegateProtocol; - - // If no delegate owner is provided, the deploying address is the owner. - if (delegateContractOwner != address(0)) { - transferOwnership(delegateContractOwner); - } - - // If no trade wallet is provided, the owner's wallet is the trade wallet. - if (delegateTradeWallet != address(0)) { - tradeWallet = delegateTradeWallet; - } else { - tradeWallet = owner(); - } + constructor(ISwapERC20 _swapERC20) { + swapERC20 = _swapERC20; } /** * @notice Set a Trading Rule - * @dev only callable by the owner of the contract - * @dev 1 senderToken = priceCoef * 10^(-priceExp) * signerToken - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send - * @param maxSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send - * @param priceCoef uint256 Whole number that will be multiplied by 10^(-priceExp) - the price coefficient - * @param priceExp uint256 Exponent of the price to indicate location of the decimal priceCoef * 10^(-priceExp) + * @param _signerToken address Address of an ERC-20 token the consumer would send + * @param _maxSignerAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param _senderToken address Address of an ERC-20 token the delegate would send + * @param _minSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send */ function setRule( - address senderToken, - address signerToken, - uint256 maxSenderAmount, - uint256 priceCoef, - uint256 priceExp - ) external onlyOwner { - _setRule(senderToken, signerToken, maxSenderAmount, priceCoef, priceExp); + address _signerToken, + uint256 _maxSignerAmount, + address _senderToken, + uint256 _minSenderAmount + ) external { + emit SetRule( + msg.sender, + _signerToken, + _maxSignerAmount, + _senderToken, + _minSenderAmount + ); } /** * @notice Unset a Trading Rule * @dev only callable by the owner of the contract, removes from a mapping - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send + * @param _signerToken address Address of an ERC-20 token the consumer would send */ - function unsetRule( - address senderToken, - address signerToken - ) external onlyOwner { - _unsetRule(senderToken, signerToken); + function unsetRule(address _signerToken) external { + emit UnsetRule(msg.sender, _signerToken); } - /** - * @notice Provide an Order - * @dev Rules get reset with new maxSenderAmount - * @param order Types.Order Order a user wants to submit to Swap. - */ - function provideOrder(ISwapERC20.OrderERC20 calldata order) external { - Rule memory rule = rules[order.senderToken][order.signerToken]; - - require(order.v != 0, "SIGNATURE_MUST_BE_SENT"); - - // Ensure the order is for the trade wallet. - require(order.senderWallet == tradeWallet, "SENDER_WALLET_INVALID"); - - // Ensure the tokens are valid ERC20 tokens. - // require( - // order.signer.kind == ERC20_INTERFACE_ID, - // "SIGNER_KIND_MUST_BE_ERC20" - // ); - - // require( - // order.sender.kind == ERC20_INTERFACE_ID, - // "SENDER_KIND_MUST_BE_ERC20" - // ); - - // Ensure that a rule exists. - require(rule.maxSenderAmount != 0, "TOKEN_PAIR_INACTIVE"); - - // Ensure the order does not exceed the maximum amount. - require(order.senderAmount <= rule.maxSenderAmount, "AMOUNT_EXCEEDS_MAX"); - - // Ensure the order is priced according to the rule. - require( - order.senderAmount <= - _calculateSenderAmount( - order.signerAmount, - rule.priceCoef, - rule.priceExp - ), - "PRICE_INVALID" - ); - - // Overwrite the rule with a decremented maxSenderAmount. - rules[order.senderToken][order.signerToken] = Rule({ - maxSenderAmount: (rule.maxSenderAmount).sub(order.senderAmount), - priceCoef: rule.priceCoef, - priceExp: rule.priceExp - }); - - // Perform the swap. - swapContract.swap( - order.senderWallet, - order.nonce, - order.expiry, - order.signerWallet, - order.signerToken, - order.signerAmount, - order.senderToken, - order.senderAmount, - order.v, - order.r, - order.s + function swap( + address _delegator, + address _recipient, + uint256 _nonce, + uint256 _expiry, + address _signerWallet, + address _signerToken, + uint256 _signerAmount, + address _senderToken, + uint256 _senderAmount, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external { + IERC20(_signerToken).safeTransferFrom( + _delegator, + address(this), + _signerAmount ); - emit ProvideOrder( - owner(), - tradeWallet, - order.senderToken, - order.signerToken, - order.senderAmount, - rule.priceCoef, - rule.priceExp + IERC20(_senderToken).approve(address(swapERC20), _senderAmount); + + swapERC20.swap( + _recipient, + _nonce, + _expiry, + _signerWallet, + _signerToken, + _signerAmount, + _senderToken, + _senderAmount, + _v, + _r, + _s ); - } - - /** - * @notice Set a new trade wallet - * @param newTradeWallet address Address of the new trade wallet - */ - function setTradeWallet(address newTradeWallet) external onlyOwner { - require(newTradeWallet != address(0), "TRADE_WALLET_REQUIRED"); - tradeWallet = newTradeWallet; - } - - /** - * @notice Get a Signer-Side Quote from the Delegate - * @param senderAmount uint256 Amount of ERC-20 token the delegate would send - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send - * @return signerAmount uint256 signerAmount Amount of ERC-20 token the consumer would send - */ - function getSignerSideQuote( - uint256 senderAmount, - address senderToken, - address signerToken - ) external view returns (uint256 signerAmount) { - Rule memory rule = rules[senderToken][signerToken]; - - // Ensure that a rule exists. - if (rule.maxSenderAmount > 0) { - // Ensure the senderAmount does not exceed maximum for the rule. - if (senderAmount <= rule.maxSenderAmount) { - signerAmount = _calculateSignerAmount( - senderAmount, - rule.priceCoef, - rule.priceExp - ); - - // Return the quote. - return signerAmount; - } - } - return 0; - } - - /** - * @notice Get a Sender-Side Quote from the Delegate - * @param signerAmount uint256 Amount of ERC-20 token the consumer would send - * @param signerToken address Address of an ERC-20 token the consumer would send - * @param senderToken address Address of an ERC-20 token the delegate would send - * @return senderAmount uint256 Amount of ERC-20 token the delegate would send - */ - function getSenderSideQuote( - uint256 signerAmount, - address signerToken, - address senderToken - ) external view returns (uint256 senderAmount) { - Rule memory rule = rules[senderToken][signerToken]; - - // Ensure that a rule exists. - if (rule.maxSenderAmount > 0) { - // Calculate the senderAmount. - senderAmount = _calculateSenderAmount( - signerAmount, - rule.priceCoef, - rule.priceExp - ); - - // Ensure the senderAmount does not exceed the maximum trade amount. - if (senderAmount <= rule.maxSenderAmount) { - return senderAmount; - } - } - return 0; - } - - /** - * @notice Get a Maximum Quote from the Delegate - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send - * @return senderAmount uint256 Amount the delegate would send - * @return signerAmount uint256 Amount the consumer would send - */ - function getMaxQuote( - address senderToken, - address signerToken - ) external view returns (uint256 senderAmount, uint256 signerAmount) { - Rule memory rule = rules[senderToken][signerToken]; - - senderAmount = rule.maxSenderAmount; - - // Ensure that a rule exists. - if (senderAmount > 0) { - // calculate the signerAmount - signerAmount = _calculateSignerAmount( - senderAmount, - rule.priceCoef, - rule.priceExp - ); - - // Return the maxSenderAmount and calculated signerAmount. - return (senderAmount, signerAmount); - } - return (0, 0); - } - - /** - * @notice Set a Trading Rule - * @dev only callable by the owner of the contract - * @dev 1 senderToken = priceCoef * 10^(-priceExp) * signerToken - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send - * @param maxSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send - * @param priceCoef uint256 Whole number that will be multiplied by 10^(-priceExp) - the price coefficient - * @param priceExp uint256 Exponent of the price to indicate location of the decimal priceCoef * 10^(-priceExp) - */ - function _setRule( - address senderToken, - address signerToken, - uint256 maxSenderAmount, - uint256 priceCoef, - uint256 priceExp - ) internal { - require(priceCoef > 0, "PRICE_COEF_INVALID"); - rules[senderToken][signerToken] = Rule({ - maxSenderAmount: maxSenderAmount, - priceCoef: priceCoef, - priceExp: priceExp - }); - emit SetRule( - owner(), - senderToken, - signerToken, - maxSenderAmount, - priceCoef, - priceExp + IERC20(_senderToken).safeTransferFrom( + address(this), + _signerWallet, + _senderAmount ); - } - - /** - * @notice Unset a Trading Rule - * @param senderToken address Address of an ERC-20 token the delegate would send - * @param signerToken address Address of an ERC-20 token the consumer would send - */ - function _unsetRule(address senderToken, address signerToken) internal { - // using non-zero rule.priceCoef for rule existence check - if (rules[senderToken][signerToken].priceCoef > 0) { - // Delete the rule. - delete rules[senderToken][signerToken]; - emit UnsetRule(owner(), senderToken, signerToken); - } - } - - /** - * @notice Calculate the signer amount for a given sender amount and price - * @param senderAmount uint256 The amount the delegate would send in the swap - * @param priceCoef uint256 Coefficient of the token price defined in the rule - * @param priceExp uint256 Exponent of the token price defined in the rule - */ - function _calculateSignerAmount( - uint256 senderAmount, - uint256 priceCoef, - uint256 priceExp - ) internal pure returns (uint256 signerAmount) { - // Calculate the signer amount using the price formula - uint256 multiplier = senderAmount.mul(priceCoef); - signerAmount = multiplier.div(10 ** priceExp); - // If the div rounded down, round up - if (multiplier.mod(10 ** priceExp) > 0) { - signerAmount++; - } - } - - /** - * @notice Calculate the sender amount for a given signer amount and price - * @param signerAmount uint256 The amount the signer would send in the swap - * @param priceCoef uint256 Coefficient of the token price defined in the rule - * @param priceExp uint256 Exponent of the token price defined in the rule - */ - function _calculateSenderAmount( - uint256 signerAmount, - uint256 priceCoef, - uint256 priceExp - ) internal pure returns (uint256 senderAmount) { - // Calculate the sender anount using the price formula - senderAmount = signerAmount.mul(10 ** priceExp).div(priceCoef); + emit DelegateSwap(_nonce, _signerWallet); } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index c3020d2e3..a7301e90b 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -2,7 +2,7 @@ import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; -pragma solidity 0.8.17; +pragma solidity 0.8.23; interface IDelegate { struct Rule { @@ -11,59 +11,39 @@ interface IDelegate { uint256 priceExp; // Indicates location of the decimal priceCoef * 10^(-priceExp) } - event SetRule( - address indexed owner, - address indexed senderToken, - address indexed signerToken, - uint256 maxSenderAmount, - uint256 priceCoef, - uint256 priceExp - ); + event DelegateSwap(uint256 _nonce, address _signerWallet); - event UnsetRule( - address indexed owner, - address indexed senderToken, - address indexed signerToken + event SetRule( + address owner, + address signerToken, + uint256 maxSignerAmount, + address senderToken, + uint256 maxSenderAmount ); - event ProvideOrder( - address indexed owner, - address tradeWallet, - address indexed senderToken, - address indexed signerToken, - uint256 senderAmount, - uint256 priceCoef, - uint256 priceExp - ); + event UnsetRule(address owner, address signerToken); function setRule( - address senderToken, - address signerToken, - uint256 maxSenderAmount, - uint256 priceCoef, - uint256 priceExp + address _signerToken, + uint256 _maxSignerAmount, + address _senderToken, + uint256 _minSenderAmount ) external; - function unsetRule(address senderToken, address signerToken) external; - - function provideOrder(ISwapERC20.OrderERC20 calldata order) external; - - function getSignerSideQuote( - uint256 senderAmount, - address senderToken, - address signerToken - ) external view returns (uint256 signerAmount); - - function getSenderSideQuote( - uint256 signerAmount, - address signerToken, - address senderToken - ) external view returns (uint256 senderAmount); - - function getMaxQuote( - address senderToken, - address signerToken - ) external view returns (uint256 senderAmount, uint256 signerAmount); + function swap( + address _delegator, + address _recipient, + uint256 _nonce, + uint256 _expiry, + address _signerWallet, + address _signerToken, + uint256 _signerAmount, + address _senderToken, + uint256 _senderAmount, + uint8 _v, + bytes32 _r, + bytes32 _s + ) external; - function tradeWallet() external view returns (address); + function unsetRule(address _signerToken) external; } diff --git a/source/delegate/package.json b/source/delegate/package.json index 5fa515b23..9c35cf04e 100644 --- a/source/delegate/package.json +++ b/source/delegate/package.json @@ -28,13 +28,37 @@ "balances": "hardhat run ./scripts/balances.js" }, "dependencies": { - "@openzeppelin/contracts": "^4.8.3" + "@airswap/utils": "4.2.4", + "@nomiclabs/hardhat-etherscan": "^3.1.0", + "@nomiclabs/hardhat-waffle": "^2.0.3", + "@openzeppelin/contracts": "^4.8.3", + "@typechain/ethers-v5": "^10.2.0", + "@typechain/hardhat": "^6.1.5", + "@types/mocha": "^10.0.1", + "@types/node": "^18.15.11", + "@typescript-eslint/eslint-plugin": "^5.58.0", + "@typescript-eslint/parser": "^5.58.0", + "chai": "^4.3.6", + "dotenv": "^16.0.1", + "eslint": "^8.20.0", + "eslint-config-prettier": "^8.5.0", + "hardhat": "^2.12.7", + "hardhat-gas-reporter": "^1.0.9", + "lerna": "^7.3.0", + "mocha": "^10.2.0", + "prettier": "^2.8.4", + "prettier-plugin-solidity": "^1.1.2", + "solidity-coverage": "^0.8.5", + "ts-node": "^10.9.1", + "typechain": "^8.1.1", + "typescript": "^5.0.4" }, "devDependencies": { "@airswap/constants": "4.1.6", "@airswap/metadata": "4.1.12", + "@airswap/swap-erc20": "^4.2.0", "@airswap/types": "4.1.1", - "@airswap/utils": "4.1.8", + "@airswap/utils": "4.2.4", "prompt-confirm": "^2.0.4" }, "publishConfig": { diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index d7eccc595..fc3a425ef 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -6,22 +6,109 @@ const { soliditySha3 } = require('web3-utils') const { ethers, waffle } = require('hardhat') const { deployMockContract } = waffle const IERC20 = require('@openzeppelin/contracts/build/contracts/IERC20.json') -const STAKING = require('@airswap/staking/build/contracts/Staking.sol/Staking.json') +const SWAP_ERC20 = require('@airswap/swap-erc20/build/contracts/SwapERC20.sol/SwapERC20.json') +const { + createOrderERC20, + orderERC20ToParams, + createOrderERC20Signature, +} = require('@airswap/utils') const { ADDRESS_ZERO } = require('@airswap/constants') +const CHAIN_ID = 31337 +const DEFAULT_BALANCE = '100000' +const DEFAULT_AMOUNT = '10000' +const PROTOCOL_FEE = '30' +const PROTOCOL_FEE_LIGHT = '7' +const REBATE_SCALE = '10' +const REBATE_MAX = '100' -function toWei(value, places) { - return toAtomicString(value, places || 18) -} - -describe('Delefate Unit', () => { +describe('Delegate Unit', () => { let deployer + let signer + let sender let alice let bob + let swapERC20 + let signerToken + let senderToken let delegate - let delegateFactory let snapshotId + function toWei(value, places) { + return toAtomicString(value, places || 18) + } + + async function createSignedOrderERC20(params, signatory) { + const unsignedOrder = createOrderERC20({ + protocolFee: PROTOCOL_FEE, + signerWallet: signer.address, + signerToken: signerToken.address, + signerAmount: DEFAULT_AMOUNT, + senderWallet: sender.address, + senderToken: senderToken.address, + senderAmount: DEFAULT_AMOUNT, + ...params, + }) + return orderERC20ToParams({ + ...unsignedOrder, + ...(await createOrderERC20Signature( + unsignedOrder, + signatory, + swapERC20.address, + CHAIN_ID + )), + }) + } + + async function createSignedPublicOrderERC20(params, signatory) { + const unsignedOrder = createOrderERC20({ + protocolFee: PROTOCOL_FEE, + signerWallet: signer.address, + signerToken: signerToken.address, + signerAmount: DEFAULT_AMOUNT, + senderWallet: ADDRESS_ZERO, + senderToken: senderToken.address, + senderAmount: DEFAULT_AMOUNT, + ...params, + }) + return orderERC20ToParams({ + ...unsignedOrder, + ...(await createOrderERC20Signature( + unsignedOrder, + signatory, + swapERC20.address, + CHAIN_ID + )), + }) + } + + async function setUpAllowances( + signerWallet, + signerAmount, + senderWallet, + senderAmount, + delegator + ) { + await signerToken.mock.allowance + .withArgs(signerWallet, swapERC20.address) + .returns(signerAmount) + await senderToken.mock.allowance + .withArgs(senderWallet, swapERC20.address) + .returns(senderAmount) + await senderToken.mock.allowance + .withArgs(delegator, delegate.address) + .returns(senderAmount) + } + + async function setUpBalances(signerWallet, senderWallet) { + await senderToken.mock.balanceOf + .withArgs(senderWallet) + .returns(DEFAULT_BALANCE) + await signerToken.mock.balanceOf + .withArgs(signerWallet) + .returns(DEFAULT_BALANCE) + } + beforeEach(async () => { snapshotId = await ethers.provider.send('evm_snapshot') }) @@ -31,9 +118,101 @@ describe('Delefate Unit', () => { }) before(async () => { - ;[deployer, alice, bob, carol] = await ethers.getSigners() + ;[deployer, alice, bob, carol, signer, sender] = await ethers.getSigners() + + const swapERC20Factory = await ethers.getContractFactory( + SWAP_ERC20.abi, + SWAP_ERC20.bytecode + ) + swapERC20 = await swapERC20Factory.deploy( + PROTOCOL_FEE, + PROTOCOL_FEE_LIGHT, + deployer.address, + REBATE_SCALE, + REBATE_MAX + ) - delegate = await (await ethers.getContractFactory('Delegate')).deploy() + delegate = await ( + await ethers.getContractFactory('Delegate') + ).deploy(swapERC20.address) await delegate.deployed() + + signerToken = await deployMockContract(deployer, IERC20.abi) + senderToken = await deployMockContract(deployer, IERC20.abi) + await signerToken.mock.transferFrom.returns(true) + await senderToken.mock.transferFrom.returns(true) + }) + + describe('Constructor', async () => { + it('swap ERC20 address is set', async () => { + expect(await delegate.swapERC20()).to.equal(swapERC20.address) + }) + }) + + describe('Rules', async () => { + it('sets a Rule', async () => { + await expect( + delegate + .connect(alice) + .setRule( + signerToken.address, + DEFAULT_AMOUNT, + senderToken.address, + DEFAULT_AMOUNT + ) + ) + .to.emit(delegate, 'SetRule') + .withArgs( + alice.address, + signerToken.address, + DEFAULT_AMOUNT, + senderToken.address, + DEFAULT_AMOUNT + ) + }) + + it('unsets a Rule', async () => { + await expect(delegate.connect(alice).unsetRule(signerToken.address)) + .to.emit(delegate, 'UnsetRule') + .withArgs(alice.address, signerToken.address) + }) + }) + + describe('Swap', async () => { + it('successfully swaps', async () => { + await delegate + .connect(alice) + .setRule( + signerToken.address, + DEFAULT_AMOUNT, + senderToken.address, + DEFAULT_AMOUNT + ) + + const order = await createSignedOrderERC20( + { + signerWallet: bob.address, + senderWallet: delegate.address, + }, + bob + ) + + setUpAllowances( + bob.address, + DEFAULT_AMOUNT + PROTOCOL_FEE, + delegate.address, + DEFAULT_AMOUNT, + alice.address + ) + await setUpBalances(bob.address, alice.address) + + await senderToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + + await expect( + delegate.connect(bob).swap(alice.address, delegate.address, ...order) + ).to.emit(delegate, 'DelegateSwap') + }) }) }) From 4674419028c86a77ec8369172e659dedcbd5521b Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Sun, 10 Mar 2024 11:28:15 -0400 Subject: [PATCH 09/43] Fixed token transfers --- source/delegate/contracts/Delegate.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 045da2f8c..c9e714072 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -70,7 +70,7 @@ contract Delegate is IDelegate, Ownable { bytes32 _r, bytes32 _s ) external { - IERC20(_signerToken).safeTransferFrom( + IERC20(_senderToken).safeTransferFrom( _delegator, address(this), _signerAmount @@ -92,9 +92,9 @@ contract Delegate is IDelegate, Ownable { _s ); - IERC20(_senderToken).safeTransferFrom( + IERC20(_signerToken).safeTransferFrom( address(this), - _signerWallet, + _delegator, _senderAmount ); From 469508b98122f704747ee8e13430666716a6590b Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Sun, 10 Mar 2024 11:32:10 -0400 Subject: [PATCH 10/43] Removed unecessary variable --- source/delegate/contracts/Delegate.sol | 3 +-- source/delegate/contracts/interfaces/IDelegate.sol | 1 - source/delegate/test/Delegate.js | 7 ++++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index c9e714072..6d6f1f355 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -58,7 +58,6 @@ contract Delegate is IDelegate, Ownable { function swap( address _delegator, - address _recipient, uint256 _nonce, uint256 _expiry, address _signerWallet, @@ -79,7 +78,7 @@ contract Delegate is IDelegate, Ownable { IERC20(_senderToken).approve(address(swapERC20), _senderAmount); swapERC20.swap( - _recipient, + address(this), _nonce, _expiry, _signerWallet, diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index a7301e90b..fabcc26e2 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -32,7 +32,6 @@ interface IDelegate { function swap( address _delegator, - address _recipient, uint256 _nonce, uint256 _expiry, address _signerWallet, diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index fc3a425ef..3c3ae7c14 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -210,9 +210,10 @@ describe('Delegate Unit', () => { .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await expect( - delegate.connect(bob).swap(alice.address, delegate.address, ...order) - ).to.emit(delegate, 'DelegateSwap') + await expect(delegate.connect(bob).swap(alice.address, ...order)).to.emit( + delegate, + 'DelegateSwap' + ) }) }) }) From e439848557abe8ef95104d761373fc516f268089 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Sun, 10 Mar 2024 11:36:44 -0400 Subject: [PATCH 11/43] Removed unused imports in Delegate tests --- source/delegate/test/Delegate.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 3c3ae7c14..1d4f4ff66 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -1,7 +1,5 @@ const { expect } = require('chai') const { toAtomicString } = require('@airswap/utils') -const { generateTreeFromData, getRoot, getProof } = require('@airswap/merkle') -const { soliditySha3 } = require('web3-utils') const { ethers, waffle } = require('hardhat') const { deployMockContract } = waffle @@ -34,10 +32,6 @@ describe('Delegate Unit', () => { let delegate let snapshotId - function toWei(value, places) { - return toAtomicString(value, places || 18) - } - async function createSignedOrderERC20(params, signatory) { const unsignedOrder = createOrderERC20({ protocolFee: PROTOCOL_FEE, From 1e32701efb1c4e0f639f80b5df7b7c82b0e37d25 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Sun, 10 Mar 2024 11:36:56 -0400 Subject: [PATCH 12/43] Removed unused imports in Delegate tests --- source/delegate/test/Delegate.js | 1 - 1 file changed, 1 deletion(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 1d4f4ff66..b0e6e7468 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -1,5 +1,4 @@ const { expect } = require('chai') -const { toAtomicString } = require('@airswap/utils') const { ethers, waffle } = require('hardhat') const { deployMockContract } = waffle From 6eb837e97515393ae43ee45f75c6725686c9eb26 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 11 Mar 2024 20:27:18 -0400 Subject: [PATCH 13/43] Fixed transfer amounts --- source/delegate/contracts/Delegate.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 6d6f1f355..d46770067 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -72,7 +72,7 @@ contract Delegate is IDelegate, Ownable { IERC20(_senderToken).safeTransferFrom( _delegator, address(this), - _signerAmount + _senderAmount ); IERC20(_senderToken).approve(address(swapERC20), _senderAmount); @@ -94,7 +94,7 @@ contract Delegate is IDelegate, Ownable { IERC20(_signerToken).safeTransferFrom( address(this), _delegator, - _senderAmount + _signerAmount ); emit DelegateSwap(_nonce, _signerWallet); From 03994bf9ae77763eb4757624c95b326f7d805ed6 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 11 Mar 2024 20:27:55 -0400 Subject: [PATCH 14/43] Updated recipient to delegator in swapERC20 --- source/delegate/contracts/Delegate.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index d46770067..b700cc63c 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -78,7 +78,7 @@ contract Delegate is IDelegate, Ownable { IERC20(_senderToken).approve(address(swapERC20), _senderAmount); swapERC20.swap( - address(this), + _delegator, _nonce, _expiry, _signerWallet, From 97fa0b845079deb8d9ddfe9baf1f4adc08d07f41 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 11 Mar 2024 21:15:38 -0400 Subject: [PATCH 15/43] Renamed signer to delegator and sender to taker --- source/delegate/contracts/Delegate.sol | 57 ++++++++++--------- .../contracts/interfaces/IDelegate.sol | 36 ++++++------ source/delegate/test/Delegate.js | 12 +++- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index b700cc63c..b1eed7221 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -27,33 +27,34 @@ contract Delegate is IDelegate, Ownable { /** * @notice Set a Trading Rule - * @param _signerToken address Address of an ERC-20 token the consumer would send - * @param _maxSignerAmount uint256 Maximum amount of ERC-20 token the delegate would send - * @param _senderToken address Address of an ERC-20 token the delegate would send - * @param _minSenderAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param _delegatorToken address Address of an ERC-20 token the consumer would send + * @param _maxDelegatorAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param _takerToken address Address of an ERC-20 token the delegate would recieve + * @param _minTakerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve */ function setRule( - address _signerToken, - uint256 _maxSignerAmount, - address _senderToken, - uint256 _minSenderAmount + address _delegatorToken, + uint256 _maxDelegatorAmount, + address _takerToken, + uint256 _minTakerAmount ) external { emit SetRule( msg.sender, - _signerToken, - _maxSignerAmount, - _senderToken, - _minSenderAmount + _delegatorToken, + _maxDelegatorAmount, + _takerToken, + _minTakerAmount ); } /** * @notice Unset a Trading Rule * @dev only callable by the owner of the contract, removes from a mapping - * @param _signerToken address Address of an ERC-20 token the consumer would send + * @param _delegatorToken address Address of an ERC-20 token the delegator would send + * @param _takerToken address Address of an ERC-20 token the delegate would receive */ - function unsetRule(address _signerToken) external { - emit UnsetRule(msg.sender, _signerToken); + function unsetRule(address _delegatorToken, address _takerToken) external { + emit UnsetRule(msg.sender, _delegatorToken, _takerToken); } function swap( @@ -61,40 +62,40 @@ contract Delegate is IDelegate, Ownable { uint256 _nonce, uint256 _expiry, address _signerWallet, - address _signerToken, - uint256 _signerAmount, - address _senderToken, - uint256 _senderAmount, + address _takerToken, + uint256 _takerAmount, + address _delegatorToken, + uint256 _delegatorAmount, uint8 _v, bytes32 _r, bytes32 _s ) external { - IERC20(_senderToken).safeTransferFrom( + IERC20(_delegatorToken).safeTransferFrom( _delegator, address(this), - _senderAmount + _delegatorAmount ); - IERC20(_senderToken).approve(address(swapERC20), _senderAmount); + IERC20(_delegatorToken).approve(address(swapERC20), _delegatorAmount); swapERC20.swap( _delegator, _nonce, _expiry, _signerWallet, - _signerToken, - _signerAmount, - _senderToken, - _senderAmount, + _takerToken, + _takerAmount, + _delegatorToken, + _delegatorAmount, _v, _r, _s ); - IERC20(_signerToken).safeTransferFrom( + IERC20(_takerToken).safeTransferFrom( address(this), _delegator, - _signerAmount + _takerAmount ); emit DelegateSwap(_nonce, _signerWallet); diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index fabcc26e2..7c7803d7e 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -14,35 +14,39 @@ interface IDelegate { event DelegateSwap(uint256 _nonce, address _signerWallet); event SetRule( - address owner, - address signerToken, - uint256 maxSignerAmount, - address senderToken, - uint256 maxSenderAmount + address _delegator, + address _delegatorToken, + uint256 _maxDelegatorAmount, + address _takerToken, + uint256 _minTakerAmount ); - event UnsetRule(address owner, address signerToken); + event UnsetRule( + address _delegator, + address _delegatorToken, + address _takerToken + ); function setRule( - address _signerToken, - uint256 _maxSignerAmount, - address _senderToken, - uint256 _minSenderAmount + address _delegatorToken, + uint256 _maxDelegatorAmount, + address _takerToken, + uint256 _minTakerAmount ) external; function swap( address _delegator, uint256 _nonce, uint256 _expiry, - address _signerWallet, - address _signerToken, - uint256 _signerAmount, - address _senderToken, - uint256 _senderAmount, + address _takerWallet, + address _delegatorToken, + uint256 _delegatorAmount, + address _takerToken, + uint256 _takerAmount, uint8 _v, bytes32 _r, bytes32 _s ) external; - function unsetRule(address _signerToken) external; + function unsetRule(address _delegatorToken, address _takerToken) external; } diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index b0e6e7468..f1f4045f6 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -165,9 +165,13 @@ describe('Delegate Unit', () => { }) it('unsets a Rule', async () => { - await expect(delegate.connect(alice).unsetRule(signerToken.address)) + await expect( + delegate + .connect(alice) + .unsetRule(signerToken.address, senderToken.address) + ) .to.emit(delegate, 'UnsetRule') - .withArgs(alice.address, signerToken.address) + .withArgs(alice.address, signerToken.address, senderToken.address) }) }) @@ -199,6 +203,10 @@ describe('Delegate Unit', () => { ) await setUpBalances(bob.address, alice.address) + await signerToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + await senderToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) From e5ee91240e2ecdcf5b83c7815e3682a8b064e7f8 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Tue, 12 Mar 2024 20:25:47 -0400 Subject: [PATCH 16/43] Renamed signer and sender to delegator and taker for clarity and added tracking of remaining rule allowance --- source/delegate/contracts/Delegate.sol | 12 ++ .../contracts/interfaces/IDelegate.sol | 2 + source/delegate/test/Delegate.js | 159 +++++++++--------- 3 files changed, 90 insertions(+), 83 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index b1eed7221..67006b6e7 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -7,6 +7,7 @@ import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "hardhat/console.sol"; /** * @title Delegate: Deployable Trading Rules for the AirSwap Network @@ -18,6 +19,10 @@ contract Delegate is IDelegate, Ownable { // The Swap contract to be used to settle trades ISwapERC20 public swapERC20; + // Mapping of delegator to delegatorToken to to takerToken to remaining DelegatorAmount + mapping(address => mapping(address => mapping(address => uint256))) + public rules; + /** * @notice Contract Constructor */ @@ -38,6 +43,7 @@ contract Delegate is IDelegate, Ownable { address _takerToken, uint256 _minTakerAmount ) external { + rules[msg.sender][_delegatorToken][_takerToken] = _maxDelegatorAmount; emit SetRule( msg.sender, _delegatorToken, @@ -54,6 +60,7 @@ contract Delegate is IDelegate, Ownable { * @param _takerToken address Address of an ERC-20 token the delegate would receive */ function unsetRule(address _delegatorToken, address _takerToken) external { + rules[msg.sender][_delegatorToken][_takerToken] = 0; emit UnsetRule(msg.sender, _delegatorToken, _takerToken); } @@ -70,6 +77,10 @@ contract Delegate is IDelegate, Ownable { bytes32 _r, bytes32 _s ) external { + if (rules[_delegator][_delegatorToken][_takerToken] < _delegatorAmount) { + revert InsufficientDelegatorAmount(); + } + IERC20(_delegatorToken).safeTransferFrom( _delegator, address(this), @@ -98,6 +109,7 @@ contract Delegate is IDelegate, Ownable { _takerAmount ); + rules[_delegator][_delegatorToken][_takerToken] -= _delegatorAmount; emit DelegateSwap(_nonce, _signerWallet); } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 7c7803d7e..9bd68c9c0 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -11,6 +11,8 @@ interface IDelegate { uint256 priceExp; // Indicates location of the decimal priceCoef * 10^(-priceExp) } + error InsufficientDelegatorAmount(); + event DelegateSwap(uint256 _nonce, address _signerWallet); event SetRule( diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index f1f4045f6..516dfd0cb 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -20,47 +20,23 @@ const REBATE_MAX = '100' describe('Delegate Unit', () => { let deployer - let signer - let sender - let alice - let bob + let delegator + let taker + let anyone let swapERC20 - let signerToken - let senderToken - + let delegatorToken + let takerToken let delegate let snapshotId async function createSignedOrderERC20(params, signatory) { const unsignedOrder = createOrderERC20({ protocolFee: PROTOCOL_FEE, - signerWallet: signer.address, - signerToken: signerToken.address, + signerWallet: taker.address, + signerToken: takerToken.address, signerAmount: DEFAULT_AMOUNT, - senderWallet: sender.address, - senderToken: senderToken.address, - senderAmount: DEFAULT_AMOUNT, - ...params, - }) - return orderERC20ToParams({ - ...unsignedOrder, - ...(await createOrderERC20Signature( - unsignedOrder, - signatory, - swapERC20.address, - CHAIN_ID - )), - }) - } - - async function createSignedPublicOrderERC20(params, signatory) { - const unsignedOrder = createOrderERC20({ - protocolFee: PROTOCOL_FEE, - signerWallet: signer.address, - signerToken: signerToken.address, - signerAmount: DEFAULT_AMOUNT, - senderWallet: ADDRESS_ZERO, - senderToken: senderToken.address, + senderWallet: delegate.address, + senderToken: delegatorToken.address, senderAmount: DEFAULT_AMOUNT, ...params, }) @@ -76,29 +52,25 @@ describe('Delegate Unit', () => { } async function setUpAllowances( - signerWallet, - signerAmount, - senderWallet, - senderAmount, - delegator + delegatorWallet, + delegatorAmount, + takerWallet, + takerAmount ) { - await signerToken.mock.allowance - .withArgs(signerWallet, swapERC20.address) - .returns(signerAmount) - await senderToken.mock.allowance - .withArgs(senderWallet, swapERC20.address) - .returns(senderAmount) - await senderToken.mock.allowance - .withArgs(delegator, delegate.address) - .returns(senderAmount) + await delegatorToken.mock.allowance + .withArgs(delegatorWallet, delegate.address) + .returns(delegatorAmount) + await takerToken.mock.allowance + .withArgs(takerWallet, swapERC20.address) + .returns(takerAmount) } - async function setUpBalances(signerWallet, senderWallet) { - await senderToken.mock.balanceOf - .withArgs(senderWallet) + async function setUpBalances(delegatorWallet, takerWallet) { + await delegatorToken.mock.balanceOf + .withArgs(delegatorWallet) .returns(DEFAULT_BALANCE) - await signerToken.mock.balanceOf - .withArgs(signerWallet) + await takerToken.mock.balanceOf + .withArgs(takerWallet) .returns(DEFAULT_BALANCE) } @@ -111,7 +83,7 @@ describe('Delegate Unit', () => { }) before(async () => { - ;[deployer, alice, bob, carol, signer, sender] = await ethers.getSigners() + ;[deployer, delegator, taker, anyone] = await ethers.getSigners() const swapERC20Factory = await ethers.getContractFactory( SWAP_ERC20.abi, @@ -130,10 +102,10 @@ describe('Delegate Unit', () => { ).deploy(swapERC20.address) await delegate.deployed() - signerToken = await deployMockContract(deployer, IERC20.abi) - senderToken = await deployMockContract(deployer, IERC20.abi) - await signerToken.mock.transferFrom.returns(true) - await senderToken.mock.transferFrom.returns(true) + delegatorToken = await deployMockContract(deployer, IERC20.abi) + takerToken = await deployMockContract(deployer, IERC20.abi) + await delegatorToken.mock.transferFrom.returns(true) + await takerToken.mock.transferFrom.returns(true) }) describe('Constructor', async () => { @@ -146,20 +118,20 @@ describe('Delegate Unit', () => { it('sets a Rule', async () => { await expect( delegate - .connect(alice) + .connect(delegator) .setRule( - signerToken.address, + delegatorToken.address, DEFAULT_AMOUNT, - senderToken.address, + takerToken.address, DEFAULT_AMOUNT ) ) .to.emit(delegate, 'SetRule') .withArgs( - alice.address, - signerToken.address, + delegator.address, + delegatorToken.address, DEFAULT_AMOUNT, - senderToken.address, + takerToken.address, DEFAULT_AMOUNT ) }) @@ -167,54 +139,75 @@ describe('Delegate Unit', () => { it('unsets a Rule', async () => { await expect( delegate - .connect(alice) - .unsetRule(signerToken.address, senderToken.address) + .connect(delegator) + .unsetRule(delegatorToken.address, takerToken.address) ) .to.emit(delegate, 'UnsetRule') - .withArgs(alice.address, signerToken.address, senderToken.address) + .withArgs(delegator.address, delegatorToken.address, takerToken.address) }) }) describe('Swap', async () => { it('successfully swaps', async () => { await delegate - .connect(alice) + .connect(delegator) .setRule( - signerToken.address, + delegatorToken.address, DEFAULT_AMOUNT, - senderToken.address, + takerToken.address, DEFAULT_AMOUNT ) + const order = await createSignedOrderERC20({}, taker) + + await setUpAllowances( + delegator.address, + DEFAULT_AMOUNT, + taker.address, + DEFAULT_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(taker.address, delegator.address) + + await delegatorToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + + await takerToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + + await expect( + delegate.connect(taker).swap(delegator.address, ...order) + ).to.emit(delegate, 'DelegateSwap') + }) + + it('fails to swap with no rule', async () => { const order = await createSignedOrderERC20( { - signerWallet: bob.address, + signerWallet: taker.address, senderWallet: delegate.address, }, - bob + taker ) - setUpAllowances( - bob.address, + await setUpAllowances( + taker.address, DEFAULT_AMOUNT + PROTOCOL_FEE, - delegate.address, - DEFAULT_AMOUNT, - alice.address + delegator.address, + DEFAULT_AMOUNT ) - await setUpBalances(bob.address, alice.address) + await setUpBalances(taker.address, delegator.address) - await signerToken.mock.approve + await delegatorToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await senderToken.mock.approve + await takerToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await expect(delegate.connect(bob).swap(alice.address, ...order)).to.emit( - delegate, - 'DelegateSwap' - ) + await expect(delegate.connect(taker).swap(delegator.address, ...order)).to + .be.reverted }) }) }) From 40179660c6dc5f3f7aac3ef991a911d88549f67d Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Mar 2024 06:36:19 -0400 Subject: [PATCH 17/43] Created delegate integration test --- source/delegate/contracts/Delegate.sol | 2 +- source/delegate/test/Delegate.js | 8 ++ source/delegate/test/DelegateIntegration.js | 142 ++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 source/delegate/test/DelegateIntegration.js diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 67006b6e7..97dcac48a 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -106,7 +106,7 @@ contract Delegate is IDelegate, Ownable { IERC20(_takerToken).safeTransferFrom( address(this), _delegator, - _takerAmount + IERC20(_takerToken).balanceOf(address(this)) ); rules[_delegator][_delegatorToken][_takerToken] -= _delegatorAmount; diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 516dfd0cb..3c00ad32d 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -176,6 +176,10 @@ describe('Delegate Unit', () => { .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) + await takerToken.mock.balanceOf + .withArgs(delegate.address) + .returns(DEFAULT_AMOUNT) + await expect( delegate.connect(taker).swap(delegator.address, ...order) ).to.emit(delegate, 'DelegateSwap') @@ -206,6 +210,10 @@ describe('Delegate Unit', () => { .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) + await takerToken.mock.balanceOf + .withArgs(delegate.address) + .returns(DEFAULT_AMOUNT) + await expect(delegate.connect(taker).swap(delegator.address, ...order)).to .be.reverted }) diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js new file mode 100644 index 000000000..486b49cdb --- /dev/null +++ b/source/delegate/test/DelegateIntegration.js @@ -0,0 +1,142 @@ +const { expect } = require('chai') +const { + createOrderERC20, + orderERC20ToParams, + createOrderERC20Signature, +} = require('@airswap/utils') +const { ethers } = require('hardhat') +const ERC20 = require('@openzeppelin/contracts/build/contracts/ERC20PresetMinterPauser.json') +const SWAP_ERC20 = require('@airswap/swap-erc20/build/contracts/SwapERC20.sol/SwapERC20.json') + +describe('Delegate Integration', () => { + let snapshotId + let swap + let takerToken + let delegatorToken + + let deployer + let delegator + let taker + let protocolFeeWallet + + const CHAIN_ID = 31337 + const BONUS_SCALE = '10' + const BONUS_MAX = '100' + const PROTOCOL_FEE = '30' + const PROTOCOL_FEE_LIGHT = '7' + const DEFAULT_AMOUNT = '10000' + const DEFAULT_BALANCE = '1000000' + + async function createSignedOrderERC20(params, taker) { + const unsignedOrder = createOrderERC20({ + protocolFee: PROTOCOL_FEE, + signerWallet: taker.address, + signerToken: takerToken.address, + signerAmount: DEFAULT_AMOUNT, + senderWallet: delegate.address, + senderToken: delegatorToken.address, + senderAmount: DEFAULT_AMOUNT, + ...params, + }) + return orderERC20ToParams({ + ...unsignedOrder, + ...(await createOrderERC20Signature( + unsignedOrder, + taker, + swapERC20.address, + CHAIN_ID + )), + }) + } + + beforeEach(async () => { + snapshotId = await ethers.provider.send('evm_snapshot') + }) + + afterEach(async () => { + await ethers.provider.send('evm_revert', [snapshotId]) + }) + + before('get signers and deploy', async () => { + ;[deployer, delegator, taker, protocolFeeWallet] = await ethers.getSigners() + + swapERC20 = await ( + await ethers.getContractFactory(SWAP_ERC20.abi, SWAP_ERC20.bytecode) + ).deploy( + PROTOCOL_FEE, + PROTOCOL_FEE_LIGHT, + deployer.address, + BONUS_SCALE, + BONUS_MAX + ) + await swapERC20.deployed() + + delegate = await ( + await ethers.getContractFactory('Delegate') + ).deploy(swapERC20.address) + await delegate.deployed() + + takerToken = await ( + await ethers.getContractFactory(ERC20.abi, ERC20.bytecode) + ).deploy('A', 'A') + await takerToken.deployed() + await takerToken.mint(taker.address, DEFAULT_BALANCE) + + delegatorToken = await ( + await ethers.getContractFactory(ERC20.abi, ERC20.bytecode) + ).deploy('B', 'B') + await delegatorToken.deployed() + await delegatorToken.mint(delegator.address, DEFAULT_BALANCE) + + takerToken.connect(taker).approve(swapERC20.address, DEFAULT_BALANCE) + delegatorToken + .connect(delegator) + .approve(swapERC20.address, DEFAULT_BALANCE) + }) + + describe('Test transfers', async () => { + it('test a delegated swap', async () => { + await delegate + .connect(delegator) + .setRule( + delegatorToken.address, + DEFAULT_AMOUNT, + takerToken.address, + DEFAULT_AMOUNT + ) + + delegatorToken + .connect(delegator) + .approve(delegate.address, DEFAULT_AMOUNT) + + takerToken + .connect(taker) + .approve(swapERC20.address, DEFAULT_AMOUNT + PROTOCOL_FEE) + + const order = await createSignedOrderERC20({}, taker) + + await expect( + delegate.connect(taker).swap(delegator.address, ...order) + ).to.emit(delegate, 'DelegateSwap') + + expect(await takerToken.balanceOf(delegator.address)).to.equal( + DEFAULT_AMOUNT + ) + + expect(await takerToken.balanceOf(taker.address)).to.equal( + DEFAULT_BALANCE - DEFAULT_AMOUNT - PROTOCOL_FEE + ) + + expect(await delegatorToken.balanceOf(taker.address)).to.equal( + DEFAULT_AMOUNT + ) + + expect(await delegatorToken.balanceOf(delegator.address)).to.equal( + DEFAULT_BALANCE - DEFAULT_AMOUNT + ) + + expect(await delegatorToken.balanceOf(delegate.address)).to.equal(0) + expect(await takerToken.balanceOf(delegate.address)).to.equal(0) + }) + }) +}) From 809590b74c09b0e54c3b5889b0facec46264f3fa Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 13 Mar 2024 06:37:11 -0400 Subject: [PATCH 18/43] Removed unused variables --- source/delegate/test/Delegate.js | 2 -- source/delegate/test/DelegateIntegration.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 3c00ad32d..923b65f14 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -9,7 +9,6 @@ const { orderERC20ToParams, createOrderERC20Signature, } = require('@airswap/utils') -const { ADDRESS_ZERO } = require('@airswap/constants') const CHAIN_ID = 31337 const DEFAULT_BALANCE = '100000' const DEFAULT_AMOUNT = '10000' @@ -22,7 +21,6 @@ describe('Delegate Unit', () => { let deployer let delegator let taker - let anyone let swapERC20 let delegatorToken let takerToken diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js index 486b49cdb..c51b85072 100644 --- a/source/delegate/test/DelegateIntegration.js +++ b/source/delegate/test/DelegateIntegration.js @@ -10,14 +10,12 @@ const SWAP_ERC20 = require('@airswap/swap-erc20/build/contracts/SwapERC20.sol/Sw describe('Delegate Integration', () => { let snapshotId - let swap let takerToken let delegatorToken let deployer let delegator let taker - let protocolFeeWallet const CHAIN_ID = 31337 const BONUS_SCALE = '10' From 53def1479020cb62ecaf4d7ee6e768638fdf53d0 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 20 Mar 2024 16:25:23 -0400 Subject: [PATCH 19/43] updated delegates contract to solady library --- source/delegate/contracts/Delegate.sol | 27 +- source/delegate/contracts/test/SwapERC20.sol | 784 ++++++++++++++++++ .../contracts/test/interfaces/ISwapERC20.sol | 113 +++ source/delegate/test/Delegate.js | 26 +- 4 files changed, 922 insertions(+), 28 deletions(-) create mode 100644 source/delegate/contracts/test/SwapERC20.sol create mode 100644 source/delegate/contracts/test/interfaces/ISwapERC20.sol diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 97dcac48a..08d5952e8 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -3,11 +3,9 @@ pragma solidity 0.8.23; import "./interfaces/IDelegate.sol"; -import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import "hardhat/console.sol"; +import { ERC20 } from "solady/src/tokens/ERC20.sol"; +import { Ownable } from "solady/src/auth/Ownable.sol"; +import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; /** * @title Delegate: Deployable Trading Rules for the AirSwap Network @@ -15,7 +13,6 @@ import "hardhat/console.sol"; * @dev inherits IDelegate, Ownable uses SafeMath library */ contract Delegate is IDelegate, Ownable { - using SafeERC20 for IERC20; // The Swap contract to be used to settle trades ISwapERC20 public swapERC20; @@ -68,7 +65,7 @@ contract Delegate is IDelegate, Ownable { address _delegator, uint256 _nonce, uint256 _expiry, - address _signerWallet, + address _takerWallet, address _takerToken, uint256 _takerAmount, address _delegatorToken, @@ -81,19 +78,20 @@ contract Delegate is IDelegate, Ownable { revert InsufficientDelegatorAmount(); } - IERC20(_delegatorToken).safeTransferFrom( + SafeTransferLib.safeTransferFrom( + _delegatorToken, _delegator, address(this), _delegatorAmount ); - IERC20(_delegatorToken).approve(address(swapERC20), _delegatorAmount); + ERC20(_delegatorToken).approve(address(swapERC20), _delegatorAmount); swapERC20.swap( - _delegator, + address(this), _nonce, _expiry, - _signerWallet, + _takerWallet, _takerToken, _takerAmount, _delegatorToken, @@ -103,13 +101,14 @@ contract Delegate is IDelegate, Ownable { _s ); - IERC20(_takerToken).safeTransferFrom( + SafeTransferLib.safeTransferFrom( + _takerToken, address(this), _delegator, - IERC20(_takerToken).balanceOf(address(this)) + ERC20(_takerToken).balanceOf(address(this)) ); rules[_delegator][_delegatorToken][_takerToken] -= _delegatorAmount; - emit DelegateSwap(_nonce, _signerWallet); + emit DelegateSwap(_nonce, _takerWallet); } } diff --git a/source/delegate/contracts/test/SwapERC20.sol b/source/delegate/contracts/test/SwapERC20.sol new file mode 100644 index 000000000..4b8720297 --- /dev/null +++ b/source/delegate/contracts/test/SwapERC20.sol @@ -0,0 +1,784 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +import { ECDSA } from "solady/src/utils/ECDSA.sol"; +import { EIP712 } from "solady/src/utils/EIP712.sol"; +import { ERC20 } from "solady/src/tokens/ERC20.sol"; +import { Ownable } from "solady/src/auth/Ownable.sol"; +import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; +import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; + +import "./interfaces/ISwapERC20.sol"; + +/** + * @title AirSwap: Atomic ERC20 Token Swap + * @notice https://www.airswap.io/ + */ +contract SwapERC20 is ISwapERC20, Ownable, EIP712 { + uint256 public immutable DOMAIN_CHAIN_ID; + bytes32 public immutable DOMAIN_SEPARATOR; + + bytes32 public constant ORDER_TYPEHASH = + keccak256( + abi.encodePacked( + "OrderERC20(uint256 nonce,uint256 expiry,address signerWallet,address signerToken,uint256 signerAmount,", + "uint256 protocolFee,address senderWallet,address senderToken,uint256 senderAmount)" + ) + ); + + uint256 public constant FEE_DIVISOR = 10000; + uint256 private constant MAX_ERROR_COUNT = 8; + uint256 private constant MAX_MAX = 100; + uint256 private constant MAX_SCALE = 77; + + /** + * @notice Double mapping of signers to nonce groups to nonce states + * @dev The nonce group is computed as nonce / 256, so each group of 256 sequential nonces uses the same key + * @dev The nonce states are encoded as 256 bits, for each nonce in the group 0 means available and 1 means used + */ + mapping(address => mapping(uint256 => uint256)) private _nonceGroups; + + // Mapping of signer to authorized signatory + mapping(address => address) public override authorized; + + uint256 public protocolFee; + uint256 public protocolFeeLight; + address public protocolFeeWallet; + uint256 public bonusScale; + uint256 public bonusMax; + address public stakingToken; + + /** + * @notice SwapERC20 constructor + * @dev Sets domain and version for EIP712 signatures + * @param _protocolFee uin256 protocol fee to be assessed on swaps + * @param _protocolFeeWallet address destination for protocol fees + * @param _bonusScale uin256 scale factor for bonus + * @param _bonusMax uint256 max bonus percentage + */ + constructor( + uint256 _protocolFee, + uint256 _protocolFeeLight, + address _protocolFeeWallet, + uint256 _bonusScale, + uint256 _bonusMax + ) { + if (_protocolFee >= FEE_DIVISOR) revert InvalidFee(); + if (_protocolFeeLight >= FEE_DIVISOR) revert InvalidFeeLight(); + if (_protocolFeeWallet == address(0)) revert InvalidFeeWallet(); + if (_bonusMax > MAX_MAX) revert MaxTooHigh(); + if (_bonusScale > MAX_SCALE) revert ScaleTooHigh(); + + _initializeOwner(msg.sender); + + DOMAIN_CHAIN_ID = block.chainid; + DOMAIN_SEPARATOR = _domainSeparator(); + + protocolFee = _protocolFee; + protocolFeeLight = _protocolFeeLight; + protocolFeeWallet = _protocolFeeWallet; + bonusMax = _bonusMax; + bonusScale = _bonusScale; + } + + /** + * @notice Return EIP712 domain values + * @return name EIP712 domain name + * @return version EIP712 domain version + */ + function _domainNameAndVersion() + internal + pure + override + returns (string memory name, string memory version) + { + name = "SWAP_ERC20"; + version = "4.3"; + } + + /** + * @notice Atomic ERC20 Swap + * @param recipient address Wallet to receive sender proceeds + * @param nonce uint256 Unique and should be sequential + * @param expiry uint256 Expiry in seconds since 1 January 1970 + * @param signerWallet address Wallet of the signer + * @param signerToken address ERC20 token transferred from the signer + * @param signerAmount uint256 Amount transferred from the signer + * @param senderToken address ERC20 token transferred from the sender + * @param senderAmount uint256 Amount transferred from the sender + * @param v uint8 "v" value of the ECDSA signature + * @param r bytes32 "r" value of the ECDSA signature + * @param s bytes32 "s" value of the ECDSA signature + */ + function swap( + address recipient, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + // Ensure the order is valid + _check( + nonce, + expiry, + signerWallet, + signerToken, + signerAmount, + msg.sender, + senderToken, + senderAmount, + v, + r, + s + ); + + // Transfer token from sender to signer + SafeTransferLib.safeTransferFrom( + senderToken, + msg.sender, + signerWallet, + senderAmount + ); + + // Transfer token from signer to recipient + SafeTransferLib.safeTransferFrom( + signerToken, + signerWallet, + recipient, + signerAmount + ); + + // Calculate and transfer protocol fee + _transferProtocolFee(signerToken, signerWallet, signerAmount); + + // Emit event + emit SwapERC20(nonce, signerWallet); + } + + /** + * @notice Atomic ERC20 Swap for Any Sender + * @param recipient address Wallet to receive sender proceeds + * @param nonce uint256 Unique and should be sequential + * @param expiry uint256 Expiry in seconds since 1 January 1970 + * @param signerWallet address Wallet of the signer + * @param signerToken address ERC20 token transferred from the signer + * @param signerAmount uint256 Amount transferred from the signer + * @param senderToken address ERC20 token transferred from the sender + * @param senderAmount uint256 Amount transferred from the sender + * @param v uint8 "v" value of the ECDSA signature + * @param r bytes32 "r" value of the ECDSA signature + * @param s bytes32 "s" value of the ECDSA signature + */ + function swapAnySender( + address recipient, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + // Ensure the order is valid + _check( + nonce, + expiry, + signerWallet, + signerToken, + signerAmount, + address(0), + senderToken, + senderAmount, + v, + r, + s + ); + + // Transfer token from sender to signer + SafeTransferLib.safeTransferFrom( + senderToken, + msg.sender, + signerWallet, + senderAmount + ); + + // Transfer token from signer to recipient + SafeTransferLib.safeTransferFrom( + signerToken, + signerWallet, + recipient, + signerAmount + ); + + // Calculate and transfer protocol fee + _transferProtocolFee(signerToken, signerWallet, signerAmount); + + // Emit event + emit SwapERC20(nonce, signerWallet); + } + + /** + * @notice Swap Atomic ERC20 Swap (Minimal Gas) + * @dev No transfer checks. Only use with known tokens. + * @param nonce uint256 Unique and should be sequential + * @param expiry uint256 Expiry in seconds since 1 January 1970 + * @param signerWallet address Wallet of the signer + * @param signerToken address ERC20 token transferred from the signer + * @param signerAmount uint256 Amount transferred from the signer + * @param senderToken address ERC20 token transferred from the sender + * @param senderAmount uint256 Amount transferred from the sender + * @param v uint8 "v" value of the ECDSA signature + * @param r bytes32 "r" value of the ECDSA signature + * @param s bytes32 "s" value of the ECDSA signature + */ + function swapLight( + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external override { + // Ensure the expiry is not passed + if (expiry <= block.timestamp) revert OrderExpired(); + + // Recover the signatory from the hash and signature + address signatory = ECDSA.tryRecover( + keccak256( + abi.encodePacked( + "\x19\x01", // EIP191: Indicates EIP712 + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + ORDER_TYPEHASH, + nonce, + expiry, + signerWallet, + signerToken, + signerAmount, + protocolFeeLight, + msg.sender, + senderToken, + senderAmount + ) + ) + ) + ), + v, + r, + s + ); + // Ensure the signatory is not null + if (signatory == address(0)) revert SignatureInvalid(); + + // Ensure the nonce is not yet used and if not mark it used + if (!_markNonceAsUsed(signatory, nonce)) revert NonceAlreadyUsed(nonce); + + // Ensure signatory is authorized to sign + if (authorized[signerWallet] != address(0)) { + // If one is set by signer wallet, signatory must be authorized + if (signatory != authorized[signerWallet]) revert SignatureInvalid(); + } else { + // Otherwise, signatory must be signer wallet + if (signatory != signerWallet) revert SignatureInvalid(); + } + + // Transfer token from sender to signer + SafeTransferLib.safeTransferFrom( + senderToken, + msg.sender, + signerWallet, + senderAmount + ); + + // Transfer token from signer to sender + SafeTransferLib.safeTransferFrom( + signerToken, + signerWallet, + msg.sender, + signerAmount + ); + + // Transfer protocol fee from signer to fee wallet + SafeTransferLib.safeTransferFrom( + signerToken, + signerWallet, + protocolFeeWallet, + (signerAmount * protocolFeeLight) / FEE_DIVISOR + ); + + // Emit event + emit SwapERC20(nonce, signerWallet); + } + + /** + * @notice Set the protocol fee + * @param _protocolFee uint256 Value of the fee in basis points + */ + function setProtocolFee(uint256 _protocolFee) external onlyOwner { + // Ensure the fee is less than divisor + if (_protocolFee >= FEE_DIVISOR) revert InvalidFee(); + protocolFee = _protocolFee; + emit SetProtocolFee(_protocolFee); + } + + /** + * @notice Set the light protocol fee + * @param _protocolFeeLight uint256 Value of the fee in basis points + */ + function setProtocolFeeLight(uint256 _protocolFeeLight) external onlyOwner { + // Ensure the fee is less than divisor + if (_protocolFeeLight >= FEE_DIVISOR) revert InvalidFeeLight(); + protocolFeeLight = _protocolFeeLight; + emit SetProtocolFeeLight(_protocolFeeLight); + } + + /** + * @notice Set the protocol fee wallet + * @param _protocolFeeWallet address Wallet to transfer fee to + */ + function setProtocolFeeWallet(address _protocolFeeWallet) external onlyOwner { + // Ensure the new fee wallet is not null + if (_protocolFeeWallet == address(0)) revert InvalidFeeWallet(); + protocolFeeWallet = _protocolFeeWallet; + emit SetProtocolFeeWallet(_protocolFeeWallet); + } + + /** + * @notice Set staking bonus max + * @dev Only owner + * @param _bonusMax uint256 + */ + function setBonusMax(uint256 _bonusMax) external onlyOwner { + if (_bonusMax > MAX_MAX) revert MaxTooHigh(); + bonusMax = _bonusMax; + emit SetBonusMax(_bonusMax); + } + + /** + * @notice Set staking bonus scale + * @dev Only owner + * @param _bonusScale uint256 + */ + function setBonusScale(uint256 _bonusScale) external onlyOwner { + if (_bonusScale > MAX_SCALE) revert ScaleTooHigh(); + bonusScale = _bonusScale; + emit SetBonusScale(_bonusScale); + } + + /** + * @notice Set staking token + * @param _stakingToken address Token to check balances on + */ + function setStaking(address _stakingToken) external onlyOwner { + // Ensure the new staking token is not null + if (_stakingToken == address(0)) revert InvalidStaking(); + stakingToken = _stakingToken; + emit SetStaking(_stakingToken); + } + + /** + * @notice Authorize a signatory + * @param signatory address Wallet of the signatory to authorize + * @dev Emits an Authorize event + */ + function authorize(address signatory) external override { + if (signatory == address(0)) revert SignatoryInvalid(); + authorized[msg.sender] = signatory; + emit Authorize(signatory, msg.sender); + } + + /** + * @notice Revoke the signatory + * @dev Emits a Revoke event + */ + function revoke() external override { + address tmp = authorized[msg.sender]; + delete authorized[msg.sender]; + emit Revoke(tmp, msg.sender); + } + + /** + * @notice Cancel one or more nonces + * @dev Cancelled nonces are marked as used + * @dev Emits a Cancel event + * @dev Out of gas may occur in arrays of length > 400 + * @param nonces uint256[] List of nonces to cancel + */ + function cancel(uint256[] calldata nonces) external override { + for (uint256 i; i < nonces.length; ) { + uint256 nonce = nonces[i]; + if (_markNonceAsUsed(msg.sender, nonce)) { + emit Cancel(nonce, msg.sender); + } + unchecked { + ++i; + } + } + } + + /** + * @notice Checks an order for errors + * @param senderWallet address Wallet that would send the order + * @param nonce uint256 Unique and should be sequential + * @param expiry uint256 Expiry in seconds since 1 January 1970 + * @param signerWallet address Wallet of the signer + * @param signerToken address ERC20 token transferred from the signer + * @param signerAmount uint256 Amount transferred from the signer + * @param senderToken address ERC20 token transferred from the sender + * @param senderAmount uint256 Amount transferred from the sender + * @param v uint8 "v" value of the ECDSA signature + * @param r bytes32 "r" value of the ECDSA signature + * @param s bytes32 "s" value of the ECDSA signature + * @return bytes32[] errors + */ + function check( + address senderWallet, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external view returns (bytes32[] memory) { + bytes32[] memory errors = new bytes32[](MAX_ERROR_COUNT); + uint256 count; + + OrderERC20 memory order; + order.nonce = nonce; + order.expiry = expiry; + order.signerWallet = signerWallet; + order.signerToken = signerToken; + order.signerAmount = signerAmount; + order.senderToken = senderToken; + order.senderAmount = senderAmount; + order.v = v; + order.r = r; + order.s = s; + order.senderWallet = senderWallet; + + if (DOMAIN_CHAIN_ID != block.chainid) { + errors[count++] = "ChainIdChanged"; + } + + // Validate as the authorized signatory if set + address signatory = order.signerWallet; + if (authorized[signatory] != address(0)) { + signatory = authorized[signatory]; + } + + if ( + !SignatureCheckerLib.isValidSignatureNow( + signatory, + _getOrderHash( + order.nonce, + order.expiry, + order.signerWallet, + order.signerToken, + order.signerAmount, + order.senderWallet, + order.senderToken, + order.senderAmount + ), + abi.encodePacked(r, s, v) + ) + ) { + errors[count++] = "SignatureInvalid"; + } else if (nonceUsed(signatory, order.nonce)) { + errors[count++] = "NonceAlreadyUsed"; + } + + if (order.expiry < block.timestamp) { + errors[count++] = "OrderExpired"; + } + + if (order.senderWallet != address(0)) { + uint256 senderBalance = ERC20(order.senderToken).balanceOf( + order.senderWallet + ); + + uint256 senderAllowance = ERC20(order.senderToken).allowance( + order.senderWallet, + address(this) + ); + + if (senderAllowance < order.senderAmount) { + errors[count++] = "SenderAllowanceLow"; + } + + if (senderBalance < order.senderAmount) { + errors[count++] = "SenderBalanceLow"; + } + } + + uint256 signerBalance = ERC20(order.signerToken).balanceOf( + order.signerWallet + ); + + uint256 signerAllowance = ERC20(order.signerToken).allowance( + order.signerWallet, + address(this) + ); + + uint256 signerFeeAmount = (order.signerAmount * protocolFee) / FEE_DIVISOR; + + if (signerAllowance < order.signerAmount + signerFeeAmount) { + errors[count++] = "SignerAllowanceLow"; + } + + if (signerBalance < order.signerAmount + signerFeeAmount) { + errors[count++] = "SignerBalanceLow"; + } + + // Truncate errors array to actual count + if (count != errors.length) { + assembly { + mstore(errors, count) + } + } + + return errors; + } + + /** + * @notice Calculates bonus from staking balance + * @param stakingBalance uint256 + * @param feeAmount uint256 + */ + function calculateBonus( + uint256 stakingBalance, + uint256 feeAmount + ) public view returns (uint256) { + uint256 divisor = (uint256(10) ** bonusScale) + stakingBalance; + return (bonusMax * stakingBalance * feeAmount) / divisor / MAX_MAX; + } + + /** + * @notice Calculates protocol fee for an account + * @param wallet address + * @param amount uint256 + */ + function calculateProtocolFee( + address wallet, + uint256 amount + ) external view override returns (uint256) { + // Transfer fee from signer to feeWallet + uint256 feeAmount = (amount * protocolFee) / FEE_DIVISOR; + if (stakingToken != address(0) && feeAmount > 0) { + uint256 bonusAmount = calculateBonus( + ERC20(stakingToken).balanceOf(wallet), + feeAmount + ); + return feeAmount - bonusAmount; + } + return feeAmount; + } + + /** + * @notice Returns true if the nonce has been used + * @param signer address Address of the signer + * @param nonce uint256 Nonce being checked + */ + function nonceUsed( + address signer, + uint256 nonce + ) public view override returns (bool) { + uint256 groupKey = nonce / 256; + uint256 indexInGroup = nonce % 256; + return (_nonceGroups[signer][groupKey] >> indexInGroup) & 1 == 1; + } + + /** + * @notice Marks a nonce as used for the given signer + * @param signer address Address of the signer for which to mark the nonce as used + * @param nonce uint256 Nonce to be marked as used + * @return bool True if the nonce was not marked as used already + */ + function _markNonceAsUsed( + address signer, + uint256 nonce + ) private returns (bool) { + uint256 groupKey = nonce / 256; + uint256 indexInGroup = nonce % 256; + uint256 group = _nonceGroups[signer][groupKey]; + + // If it is already used, return false + if ((group >> indexInGroup) & 1 == 1) { + return false; + } + + _nonceGroups[signer][groupKey] = group | (uint256(1) << indexInGroup); + + return true; + } + + /** + * @notice Checks order and reverts on error + * @param nonce uint256 Unique and should be sequential + * @param expiry uint256 Expiry in seconds since 1 January 1970 + * @param signerWallet address Wallet of the signer + * @param signerToken address ERC20 token transferred from the signer + * @param signerAmount uint256 Amount transferred from the signer + * @param senderToken address ERC20 token transferred from the sender + * @param senderAmount uint256 Amount transferred from the sender + * @param v uint8 "v" value of the ECDSA signature + * @param r bytes32 "r" value of the ECDSA signature + * @param s bytes32 "s" value of the ECDSA signature + */ + function _check( + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderWallet, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) private { + // Ensure execution on the intended chain + if (DOMAIN_CHAIN_ID != block.chainid) revert ChainIdChanged(); + + // Ensure the expiry is not passed + if (expiry <= block.timestamp) revert OrderExpired(); + + // Validate as the authorized signatory if set + address signatory = signerWallet; + if (authorized[signatory] != address(0)) { + signatory = authorized[signatory]; + } + + // Ensure the signature is correct for the order + if ( + !SignatureCheckerLib.isValidSignatureNow( + signatory, + _getOrderHash( + nonce, + expiry, + signerWallet, + signerToken, + signerAmount, + senderWallet, + senderToken, + senderAmount + ), + abi.encodePacked(r, s, v) + ) + ) revert SignatureInvalid(); + + // Ensure the nonce is not yet used and if not mark as used + if (!_markNonceAsUsed(signatory, nonce)) revert NonceAlreadyUsed(nonce); + } + + /** + * @notice Hashes order parameters + * @param nonce uint256 + * @param expiry uint256 + * @param signerWallet address + * @param signerToken address + * @param signerAmount uint256 + * @param senderToken address + * @param senderAmount uint256 + * @return bytes32 + */ + function _getOrderHash( + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderWallet, + address senderToken, + uint256 senderAmount + ) private view returns (bytes32) { + return + keccak256( + abi.encodePacked( + "\x19\x01", // EIP191: Indicates EIP712 + DOMAIN_SEPARATOR, + keccak256( + abi.encode( + ORDER_TYPEHASH, + nonce, + expiry, + signerWallet, + signerToken, + signerAmount, + protocolFee, + senderWallet, + senderToken, + senderAmount + ) + ) + ) + ); + } + + /** + * @notice Calculates and transfers protocol fee and staking bonus + * @param sourceToken address + * @param sourceWallet address + * @param amount uint256 + */ + function _transferProtocolFee( + address sourceToken, + address sourceWallet, + uint256 amount + ) private { + // Determine protocol fee from amount + uint256 feeAmount = (amount * protocolFee) / FEE_DIVISOR; + if (feeAmount > 0) { + uint256 bonusAmount; + if (stakingToken != address(0)) { + // Only check staking bonus if staking token set + bonusAmount = calculateBonus( + ERC20(stakingToken).balanceOf(msg.sender), + feeAmount + ); + } + if (bonusAmount > 0) { + // Transfer staking bonus from source to msg.sender + SafeTransferLib.safeTransferFrom( + sourceToken, + sourceWallet, + msg.sender, + bonusAmount + ); + // Transfer remaining protocol fee from source to fee wallet + SafeTransferLib.safeTransferFrom( + sourceToken, + sourceWallet, + protocolFeeWallet, + feeAmount - bonusAmount + ); + } else { + // Transfer full protocol fee from source to fee wallet + SafeTransferLib.safeTransferFrom( + sourceToken, + sourceWallet, + protocolFeeWallet, + feeAmount + ); + } + } + } +} diff --git a/source/delegate/contracts/test/interfaces/ISwapERC20.sol b/source/delegate/contracts/test/interfaces/ISwapERC20.sol new file mode 100644 index 000000000..70a62308f --- /dev/null +++ b/source/delegate/contracts/test/interfaces/ISwapERC20.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +interface ISwapERC20 { + struct OrderERC20 { + uint256 nonce; // Unique number per signatory per order + uint256 expiry; // Expiry time (seconds since unix epoch) + address signerWallet; // Party to the swap that sets terms + address signerToken; // ERC20 token address transferred from signer + uint256 signerAmount; // Amount of tokens transferred from signer + address senderWallet; // Party to the swap that accepts terms + address senderToken; // ERC20 token address transferred from sender + uint256 senderAmount; // Amount of tokens transferred from sender + uint8 v; // ECDSA + bytes32 r; + bytes32 s; + } + + event SwapERC20(uint256 indexed nonce, address indexed signerWallet); + + event Cancel(uint256 indexed nonce, address indexed signerWallet); + event Authorize(address indexed signer, address indexed signerWallet); + event Revoke(address indexed signer, address indexed signerWallet); + event SetProtocolFee(uint256 protocolFee); + event SetProtocolFeeLight(uint256 protocolFeeLight); + event SetProtocolFeeWallet(address indexed feeWallet); + event SetBonusScale(uint256 bonusScale); + event SetBonusMax(uint256 bonusMax); + event SetStaking(address indexed staking); + + error ChainIdChanged(); + error InvalidFee(); + error InvalidFeeLight(); + error InvalidFeeWallet(); + error InvalidStaking(); + error OrderExpired(); + error MaxTooHigh(); + error NonceAlreadyUsed(uint256); + error ScaleTooHigh(); + error SignatoryInvalid(); + error SignatureInvalid(); + error TransferFromFailed(); + + function swap( + address recipient, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function swapAnySender( + address recipient, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function swapLight( + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + function authorize(address sender) external; + + function revoke() external; + + function cancel(uint256[] calldata nonces) external; + + function check( + address senderWallet, + uint256 nonce, + uint256 expiry, + address signerWallet, + address signerToken, + uint256 signerAmount, + address senderToken, + uint256 senderAmount, + uint8 v, + bytes32 r, + bytes32 s + ) external view returns (bytes32[] memory); + + function nonceUsed(address, uint256) external view returns (bool); + + function authorized(address) external view returns (address); + + function calculateProtocolFee( + address, + uint256 + ) external view returns (uint256); +} diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 923b65f14..0da1b0609 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -70,6 +70,9 @@ describe('Delegate Unit', () => { await takerToken.mock.balanceOf .withArgs(takerWallet) .returns(DEFAULT_BALANCE) + await takerToken.mock.balanceOf + .withArgs(delegate.address) + .returns(DEFAULT_AMOUNT) } beforeEach(async () => { @@ -83,10 +86,7 @@ describe('Delegate Unit', () => { before(async () => { ;[deployer, delegator, taker, anyone] = await ethers.getSigners() - const swapERC20Factory = await ethers.getContractFactory( - SWAP_ERC20.abi, - SWAP_ERC20.bytecode - ) + const swapERC20Factory = await ethers.getContractFactory('SwapERC20') swapERC20 = await swapERC20Factory.deploy( PROTOCOL_FEE, PROTOCOL_FEE_LIGHT, @@ -166,6 +166,10 @@ describe('Delegate Unit', () => { ) await setUpBalances(taker.address, delegator.address) + await delegatorToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT) + .returns(true) + await delegatorToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) @@ -174,9 +178,9 @@ describe('Delegate Unit', () => { .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await takerToken.mock.balanceOf - .withArgs(delegate.address) - .returns(DEFAULT_AMOUNT) + await takerToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT) + .returns(true) await expect( delegate.connect(taker).swap(delegator.address, ...order) @@ -184,13 +188,7 @@ describe('Delegate Unit', () => { }) it('fails to swap with no rule', async () => { - const order = await createSignedOrderERC20( - { - signerWallet: taker.address, - senderWallet: delegate.address, - }, - taker - ) + const order = await createSignedOrderERC20({}, taker) await setUpAllowances( taker.address, From a996532aaffd7d1dedb2477c5722eff9d2a52717 Mon Sep 17 00:00:00 2001 From: Don Mosites Date: Thu, 21 Mar 2024 23:16:28 +0100 Subject: [PATCH 20/43] delegates: cleanup deps; remove redundants --- source/delegate/contracts/Delegate.sol | 1 + .../contracts/interfaces/IDelegate.sol | 1 + source/delegate/contracts/test/SwapERC20.sol | 784 ------------------ .../contracts/test/interfaces/ISwapERC20.sol | 113 --- source/delegate/package.json | 33 +- source/delegate/test/Delegate.js | 5 +- 6 files changed, 8 insertions(+), 929 deletions(-) delete mode 100644 source/delegate/contracts/test/SwapERC20.sol delete mode 100644 source/delegate/contracts/test/interfaces/ISwapERC20.sol diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 08d5952e8..2bc04229d 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -3,6 +3,7 @@ pragma solidity 0.8.23; import "./interfaces/IDelegate.sol"; +import "@airswap/swap-erc20/contracts/interfaces/ISwapERC20.sol"; import { ERC20 } from "solady/src/tokens/ERC20.sol"; import { Ownable } from "solady/src/auth/Ownable.sol"; import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 9bd68c9c0..91a0add4d 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -12,6 +12,7 @@ interface IDelegate { } error InsufficientDelegatorAmount(); + error TransferFromFailed(); event DelegateSwap(uint256 _nonce, address _signerWallet); diff --git a/source/delegate/contracts/test/SwapERC20.sol b/source/delegate/contracts/test/SwapERC20.sol deleted file mode 100644 index 4b8720297..000000000 --- a/source/delegate/contracts/test/SwapERC20.sol +++ /dev/null @@ -1,784 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.23; - -import { ECDSA } from "solady/src/utils/ECDSA.sol"; -import { EIP712 } from "solady/src/utils/EIP712.sol"; -import { ERC20 } from "solady/src/tokens/ERC20.sol"; -import { Ownable } from "solady/src/auth/Ownable.sol"; -import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; -import { SignatureCheckerLib } from "solady/src/utils/SignatureCheckerLib.sol"; - -import "./interfaces/ISwapERC20.sol"; - -/** - * @title AirSwap: Atomic ERC20 Token Swap - * @notice https://www.airswap.io/ - */ -contract SwapERC20 is ISwapERC20, Ownable, EIP712 { - uint256 public immutable DOMAIN_CHAIN_ID; - bytes32 public immutable DOMAIN_SEPARATOR; - - bytes32 public constant ORDER_TYPEHASH = - keccak256( - abi.encodePacked( - "OrderERC20(uint256 nonce,uint256 expiry,address signerWallet,address signerToken,uint256 signerAmount,", - "uint256 protocolFee,address senderWallet,address senderToken,uint256 senderAmount)" - ) - ); - - uint256 public constant FEE_DIVISOR = 10000; - uint256 private constant MAX_ERROR_COUNT = 8; - uint256 private constant MAX_MAX = 100; - uint256 private constant MAX_SCALE = 77; - - /** - * @notice Double mapping of signers to nonce groups to nonce states - * @dev The nonce group is computed as nonce / 256, so each group of 256 sequential nonces uses the same key - * @dev The nonce states are encoded as 256 bits, for each nonce in the group 0 means available and 1 means used - */ - mapping(address => mapping(uint256 => uint256)) private _nonceGroups; - - // Mapping of signer to authorized signatory - mapping(address => address) public override authorized; - - uint256 public protocolFee; - uint256 public protocolFeeLight; - address public protocolFeeWallet; - uint256 public bonusScale; - uint256 public bonusMax; - address public stakingToken; - - /** - * @notice SwapERC20 constructor - * @dev Sets domain and version for EIP712 signatures - * @param _protocolFee uin256 protocol fee to be assessed on swaps - * @param _protocolFeeWallet address destination for protocol fees - * @param _bonusScale uin256 scale factor for bonus - * @param _bonusMax uint256 max bonus percentage - */ - constructor( - uint256 _protocolFee, - uint256 _protocolFeeLight, - address _protocolFeeWallet, - uint256 _bonusScale, - uint256 _bonusMax - ) { - if (_protocolFee >= FEE_DIVISOR) revert InvalidFee(); - if (_protocolFeeLight >= FEE_DIVISOR) revert InvalidFeeLight(); - if (_protocolFeeWallet == address(0)) revert InvalidFeeWallet(); - if (_bonusMax > MAX_MAX) revert MaxTooHigh(); - if (_bonusScale > MAX_SCALE) revert ScaleTooHigh(); - - _initializeOwner(msg.sender); - - DOMAIN_CHAIN_ID = block.chainid; - DOMAIN_SEPARATOR = _domainSeparator(); - - protocolFee = _protocolFee; - protocolFeeLight = _protocolFeeLight; - protocolFeeWallet = _protocolFeeWallet; - bonusMax = _bonusMax; - bonusScale = _bonusScale; - } - - /** - * @notice Return EIP712 domain values - * @return name EIP712 domain name - * @return version EIP712 domain version - */ - function _domainNameAndVersion() - internal - pure - override - returns (string memory name, string memory version) - { - name = "SWAP_ERC20"; - version = "4.3"; - } - - /** - * @notice Atomic ERC20 Swap - * @param recipient address Wallet to receive sender proceeds - * @param nonce uint256 Unique and should be sequential - * @param expiry uint256 Expiry in seconds since 1 January 1970 - * @param signerWallet address Wallet of the signer - * @param signerToken address ERC20 token transferred from the signer - * @param signerAmount uint256 Amount transferred from the signer - * @param senderToken address ERC20 token transferred from the sender - * @param senderAmount uint256 Amount transferred from the sender - * @param v uint8 "v" value of the ECDSA signature - * @param r bytes32 "r" value of the ECDSA signature - * @param s bytes32 "s" value of the ECDSA signature - */ - function swap( - address recipient, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external override { - // Ensure the order is valid - _check( - nonce, - expiry, - signerWallet, - signerToken, - signerAmount, - msg.sender, - senderToken, - senderAmount, - v, - r, - s - ); - - // Transfer token from sender to signer - SafeTransferLib.safeTransferFrom( - senderToken, - msg.sender, - signerWallet, - senderAmount - ); - - // Transfer token from signer to recipient - SafeTransferLib.safeTransferFrom( - signerToken, - signerWallet, - recipient, - signerAmount - ); - - // Calculate and transfer protocol fee - _transferProtocolFee(signerToken, signerWallet, signerAmount); - - // Emit event - emit SwapERC20(nonce, signerWallet); - } - - /** - * @notice Atomic ERC20 Swap for Any Sender - * @param recipient address Wallet to receive sender proceeds - * @param nonce uint256 Unique and should be sequential - * @param expiry uint256 Expiry in seconds since 1 January 1970 - * @param signerWallet address Wallet of the signer - * @param signerToken address ERC20 token transferred from the signer - * @param signerAmount uint256 Amount transferred from the signer - * @param senderToken address ERC20 token transferred from the sender - * @param senderAmount uint256 Amount transferred from the sender - * @param v uint8 "v" value of the ECDSA signature - * @param r bytes32 "r" value of the ECDSA signature - * @param s bytes32 "s" value of the ECDSA signature - */ - function swapAnySender( - address recipient, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external override { - // Ensure the order is valid - _check( - nonce, - expiry, - signerWallet, - signerToken, - signerAmount, - address(0), - senderToken, - senderAmount, - v, - r, - s - ); - - // Transfer token from sender to signer - SafeTransferLib.safeTransferFrom( - senderToken, - msg.sender, - signerWallet, - senderAmount - ); - - // Transfer token from signer to recipient - SafeTransferLib.safeTransferFrom( - signerToken, - signerWallet, - recipient, - signerAmount - ); - - // Calculate and transfer protocol fee - _transferProtocolFee(signerToken, signerWallet, signerAmount); - - // Emit event - emit SwapERC20(nonce, signerWallet); - } - - /** - * @notice Swap Atomic ERC20 Swap (Minimal Gas) - * @dev No transfer checks. Only use with known tokens. - * @param nonce uint256 Unique and should be sequential - * @param expiry uint256 Expiry in seconds since 1 January 1970 - * @param signerWallet address Wallet of the signer - * @param signerToken address ERC20 token transferred from the signer - * @param signerAmount uint256 Amount transferred from the signer - * @param senderToken address ERC20 token transferred from the sender - * @param senderAmount uint256 Amount transferred from the sender - * @param v uint8 "v" value of the ECDSA signature - * @param r bytes32 "r" value of the ECDSA signature - * @param s bytes32 "s" value of the ECDSA signature - */ - function swapLight( - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external override { - // Ensure the expiry is not passed - if (expiry <= block.timestamp) revert OrderExpired(); - - // Recover the signatory from the hash and signature - address signatory = ECDSA.tryRecover( - keccak256( - abi.encodePacked( - "\x19\x01", // EIP191: Indicates EIP712 - DOMAIN_SEPARATOR, - keccak256( - abi.encode( - ORDER_TYPEHASH, - nonce, - expiry, - signerWallet, - signerToken, - signerAmount, - protocolFeeLight, - msg.sender, - senderToken, - senderAmount - ) - ) - ) - ), - v, - r, - s - ); - // Ensure the signatory is not null - if (signatory == address(0)) revert SignatureInvalid(); - - // Ensure the nonce is not yet used and if not mark it used - if (!_markNonceAsUsed(signatory, nonce)) revert NonceAlreadyUsed(nonce); - - // Ensure signatory is authorized to sign - if (authorized[signerWallet] != address(0)) { - // If one is set by signer wallet, signatory must be authorized - if (signatory != authorized[signerWallet]) revert SignatureInvalid(); - } else { - // Otherwise, signatory must be signer wallet - if (signatory != signerWallet) revert SignatureInvalid(); - } - - // Transfer token from sender to signer - SafeTransferLib.safeTransferFrom( - senderToken, - msg.sender, - signerWallet, - senderAmount - ); - - // Transfer token from signer to sender - SafeTransferLib.safeTransferFrom( - signerToken, - signerWallet, - msg.sender, - signerAmount - ); - - // Transfer protocol fee from signer to fee wallet - SafeTransferLib.safeTransferFrom( - signerToken, - signerWallet, - protocolFeeWallet, - (signerAmount * protocolFeeLight) / FEE_DIVISOR - ); - - // Emit event - emit SwapERC20(nonce, signerWallet); - } - - /** - * @notice Set the protocol fee - * @param _protocolFee uint256 Value of the fee in basis points - */ - function setProtocolFee(uint256 _protocolFee) external onlyOwner { - // Ensure the fee is less than divisor - if (_protocolFee >= FEE_DIVISOR) revert InvalidFee(); - protocolFee = _protocolFee; - emit SetProtocolFee(_protocolFee); - } - - /** - * @notice Set the light protocol fee - * @param _protocolFeeLight uint256 Value of the fee in basis points - */ - function setProtocolFeeLight(uint256 _protocolFeeLight) external onlyOwner { - // Ensure the fee is less than divisor - if (_protocolFeeLight >= FEE_DIVISOR) revert InvalidFeeLight(); - protocolFeeLight = _protocolFeeLight; - emit SetProtocolFeeLight(_protocolFeeLight); - } - - /** - * @notice Set the protocol fee wallet - * @param _protocolFeeWallet address Wallet to transfer fee to - */ - function setProtocolFeeWallet(address _protocolFeeWallet) external onlyOwner { - // Ensure the new fee wallet is not null - if (_protocolFeeWallet == address(0)) revert InvalidFeeWallet(); - protocolFeeWallet = _protocolFeeWallet; - emit SetProtocolFeeWallet(_protocolFeeWallet); - } - - /** - * @notice Set staking bonus max - * @dev Only owner - * @param _bonusMax uint256 - */ - function setBonusMax(uint256 _bonusMax) external onlyOwner { - if (_bonusMax > MAX_MAX) revert MaxTooHigh(); - bonusMax = _bonusMax; - emit SetBonusMax(_bonusMax); - } - - /** - * @notice Set staking bonus scale - * @dev Only owner - * @param _bonusScale uint256 - */ - function setBonusScale(uint256 _bonusScale) external onlyOwner { - if (_bonusScale > MAX_SCALE) revert ScaleTooHigh(); - bonusScale = _bonusScale; - emit SetBonusScale(_bonusScale); - } - - /** - * @notice Set staking token - * @param _stakingToken address Token to check balances on - */ - function setStaking(address _stakingToken) external onlyOwner { - // Ensure the new staking token is not null - if (_stakingToken == address(0)) revert InvalidStaking(); - stakingToken = _stakingToken; - emit SetStaking(_stakingToken); - } - - /** - * @notice Authorize a signatory - * @param signatory address Wallet of the signatory to authorize - * @dev Emits an Authorize event - */ - function authorize(address signatory) external override { - if (signatory == address(0)) revert SignatoryInvalid(); - authorized[msg.sender] = signatory; - emit Authorize(signatory, msg.sender); - } - - /** - * @notice Revoke the signatory - * @dev Emits a Revoke event - */ - function revoke() external override { - address tmp = authorized[msg.sender]; - delete authorized[msg.sender]; - emit Revoke(tmp, msg.sender); - } - - /** - * @notice Cancel one or more nonces - * @dev Cancelled nonces are marked as used - * @dev Emits a Cancel event - * @dev Out of gas may occur in arrays of length > 400 - * @param nonces uint256[] List of nonces to cancel - */ - function cancel(uint256[] calldata nonces) external override { - for (uint256 i; i < nonces.length; ) { - uint256 nonce = nonces[i]; - if (_markNonceAsUsed(msg.sender, nonce)) { - emit Cancel(nonce, msg.sender); - } - unchecked { - ++i; - } - } - } - - /** - * @notice Checks an order for errors - * @param senderWallet address Wallet that would send the order - * @param nonce uint256 Unique and should be sequential - * @param expiry uint256 Expiry in seconds since 1 January 1970 - * @param signerWallet address Wallet of the signer - * @param signerToken address ERC20 token transferred from the signer - * @param signerAmount uint256 Amount transferred from the signer - * @param senderToken address ERC20 token transferred from the sender - * @param senderAmount uint256 Amount transferred from the sender - * @param v uint8 "v" value of the ECDSA signature - * @param r bytes32 "r" value of the ECDSA signature - * @param s bytes32 "s" value of the ECDSA signature - * @return bytes32[] errors - */ - function check( - address senderWallet, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external view returns (bytes32[] memory) { - bytes32[] memory errors = new bytes32[](MAX_ERROR_COUNT); - uint256 count; - - OrderERC20 memory order; - order.nonce = nonce; - order.expiry = expiry; - order.signerWallet = signerWallet; - order.signerToken = signerToken; - order.signerAmount = signerAmount; - order.senderToken = senderToken; - order.senderAmount = senderAmount; - order.v = v; - order.r = r; - order.s = s; - order.senderWallet = senderWallet; - - if (DOMAIN_CHAIN_ID != block.chainid) { - errors[count++] = "ChainIdChanged"; - } - - // Validate as the authorized signatory if set - address signatory = order.signerWallet; - if (authorized[signatory] != address(0)) { - signatory = authorized[signatory]; - } - - if ( - !SignatureCheckerLib.isValidSignatureNow( - signatory, - _getOrderHash( - order.nonce, - order.expiry, - order.signerWallet, - order.signerToken, - order.signerAmount, - order.senderWallet, - order.senderToken, - order.senderAmount - ), - abi.encodePacked(r, s, v) - ) - ) { - errors[count++] = "SignatureInvalid"; - } else if (nonceUsed(signatory, order.nonce)) { - errors[count++] = "NonceAlreadyUsed"; - } - - if (order.expiry < block.timestamp) { - errors[count++] = "OrderExpired"; - } - - if (order.senderWallet != address(0)) { - uint256 senderBalance = ERC20(order.senderToken).balanceOf( - order.senderWallet - ); - - uint256 senderAllowance = ERC20(order.senderToken).allowance( - order.senderWallet, - address(this) - ); - - if (senderAllowance < order.senderAmount) { - errors[count++] = "SenderAllowanceLow"; - } - - if (senderBalance < order.senderAmount) { - errors[count++] = "SenderBalanceLow"; - } - } - - uint256 signerBalance = ERC20(order.signerToken).balanceOf( - order.signerWallet - ); - - uint256 signerAllowance = ERC20(order.signerToken).allowance( - order.signerWallet, - address(this) - ); - - uint256 signerFeeAmount = (order.signerAmount * protocolFee) / FEE_DIVISOR; - - if (signerAllowance < order.signerAmount + signerFeeAmount) { - errors[count++] = "SignerAllowanceLow"; - } - - if (signerBalance < order.signerAmount + signerFeeAmount) { - errors[count++] = "SignerBalanceLow"; - } - - // Truncate errors array to actual count - if (count != errors.length) { - assembly { - mstore(errors, count) - } - } - - return errors; - } - - /** - * @notice Calculates bonus from staking balance - * @param stakingBalance uint256 - * @param feeAmount uint256 - */ - function calculateBonus( - uint256 stakingBalance, - uint256 feeAmount - ) public view returns (uint256) { - uint256 divisor = (uint256(10) ** bonusScale) + stakingBalance; - return (bonusMax * stakingBalance * feeAmount) / divisor / MAX_MAX; - } - - /** - * @notice Calculates protocol fee for an account - * @param wallet address - * @param amount uint256 - */ - function calculateProtocolFee( - address wallet, - uint256 amount - ) external view override returns (uint256) { - // Transfer fee from signer to feeWallet - uint256 feeAmount = (amount * protocolFee) / FEE_DIVISOR; - if (stakingToken != address(0) && feeAmount > 0) { - uint256 bonusAmount = calculateBonus( - ERC20(stakingToken).balanceOf(wallet), - feeAmount - ); - return feeAmount - bonusAmount; - } - return feeAmount; - } - - /** - * @notice Returns true if the nonce has been used - * @param signer address Address of the signer - * @param nonce uint256 Nonce being checked - */ - function nonceUsed( - address signer, - uint256 nonce - ) public view override returns (bool) { - uint256 groupKey = nonce / 256; - uint256 indexInGroup = nonce % 256; - return (_nonceGroups[signer][groupKey] >> indexInGroup) & 1 == 1; - } - - /** - * @notice Marks a nonce as used for the given signer - * @param signer address Address of the signer for which to mark the nonce as used - * @param nonce uint256 Nonce to be marked as used - * @return bool True if the nonce was not marked as used already - */ - function _markNonceAsUsed( - address signer, - uint256 nonce - ) private returns (bool) { - uint256 groupKey = nonce / 256; - uint256 indexInGroup = nonce % 256; - uint256 group = _nonceGroups[signer][groupKey]; - - // If it is already used, return false - if ((group >> indexInGroup) & 1 == 1) { - return false; - } - - _nonceGroups[signer][groupKey] = group | (uint256(1) << indexInGroup); - - return true; - } - - /** - * @notice Checks order and reverts on error - * @param nonce uint256 Unique and should be sequential - * @param expiry uint256 Expiry in seconds since 1 January 1970 - * @param signerWallet address Wallet of the signer - * @param signerToken address ERC20 token transferred from the signer - * @param signerAmount uint256 Amount transferred from the signer - * @param senderToken address ERC20 token transferred from the sender - * @param senderAmount uint256 Amount transferred from the sender - * @param v uint8 "v" value of the ECDSA signature - * @param r bytes32 "r" value of the ECDSA signature - * @param s bytes32 "s" value of the ECDSA signature - */ - function _check( - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderWallet, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) private { - // Ensure execution on the intended chain - if (DOMAIN_CHAIN_ID != block.chainid) revert ChainIdChanged(); - - // Ensure the expiry is not passed - if (expiry <= block.timestamp) revert OrderExpired(); - - // Validate as the authorized signatory if set - address signatory = signerWallet; - if (authorized[signatory] != address(0)) { - signatory = authorized[signatory]; - } - - // Ensure the signature is correct for the order - if ( - !SignatureCheckerLib.isValidSignatureNow( - signatory, - _getOrderHash( - nonce, - expiry, - signerWallet, - signerToken, - signerAmount, - senderWallet, - senderToken, - senderAmount - ), - abi.encodePacked(r, s, v) - ) - ) revert SignatureInvalid(); - - // Ensure the nonce is not yet used and if not mark as used - if (!_markNonceAsUsed(signatory, nonce)) revert NonceAlreadyUsed(nonce); - } - - /** - * @notice Hashes order parameters - * @param nonce uint256 - * @param expiry uint256 - * @param signerWallet address - * @param signerToken address - * @param signerAmount uint256 - * @param senderToken address - * @param senderAmount uint256 - * @return bytes32 - */ - function _getOrderHash( - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderWallet, - address senderToken, - uint256 senderAmount - ) private view returns (bytes32) { - return - keccak256( - abi.encodePacked( - "\x19\x01", // EIP191: Indicates EIP712 - DOMAIN_SEPARATOR, - keccak256( - abi.encode( - ORDER_TYPEHASH, - nonce, - expiry, - signerWallet, - signerToken, - signerAmount, - protocolFee, - senderWallet, - senderToken, - senderAmount - ) - ) - ) - ); - } - - /** - * @notice Calculates and transfers protocol fee and staking bonus - * @param sourceToken address - * @param sourceWallet address - * @param amount uint256 - */ - function _transferProtocolFee( - address sourceToken, - address sourceWallet, - uint256 amount - ) private { - // Determine protocol fee from amount - uint256 feeAmount = (amount * protocolFee) / FEE_DIVISOR; - if (feeAmount > 0) { - uint256 bonusAmount; - if (stakingToken != address(0)) { - // Only check staking bonus if staking token set - bonusAmount = calculateBonus( - ERC20(stakingToken).balanceOf(msg.sender), - feeAmount - ); - } - if (bonusAmount > 0) { - // Transfer staking bonus from source to msg.sender - SafeTransferLib.safeTransferFrom( - sourceToken, - sourceWallet, - msg.sender, - bonusAmount - ); - // Transfer remaining protocol fee from source to fee wallet - SafeTransferLib.safeTransferFrom( - sourceToken, - sourceWallet, - protocolFeeWallet, - feeAmount - bonusAmount - ); - } else { - // Transfer full protocol fee from source to fee wallet - SafeTransferLib.safeTransferFrom( - sourceToken, - sourceWallet, - protocolFeeWallet, - feeAmount - ); - } - } - } -} diff --git a/source/delegate/contracts/test/interfaces/ISwapERC20.sol b/source/delegate/contracts/test/interfaces/ISwapERC20.sol deleted file mode 100644 index 70a62308f..000000000 --- a/source/delegate/contracts/test/interfaces/ISwapERC20.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.23; - -interface ISwapERC20 { - struct OrderERC20 { - uint256 nonce; // Unique number per signatory per order - uint256 expiry; // Expiry time (seconds since unix epoch) - address signerWallet; // Party to the swap that sets terms - address signerToken; // ERC20 token address transferred from signer - uint256 signerAmount; // Amount of tokens transferred from signer - address senderWallet; // Party to the swap that accepts terms - address senderToken; // ERC20 token address transferred from sender - uint256 senderAmount; // Amount of tokens transferred from sender - uint8 v; // ECDSA - bytes32 r; - bytes32 s; - } - - event SwapERC20(uint256 indexed nonce, address indexed signerWallet); - - event Cancel(uint256 indexed nonce, address indexed signerWallet); - event Authorize(address indexed signer, address indexed signerWallet); - event Revoke(address indexed signer, address indexed signerWallet); - event SetProtocolFee(uint256 protocolFee); - event SetProtocolFeeLight(uint256 protocolFeeLight); - event SetProtocolFeeWallet(address indexed feeWallet); - event SetBonusScale(uint256 bonusScale); - event SetBonusMax(uint256 bonusMax); - event SetStaking(address indexed staking); - - error ChainIdChanged(); - error InvalidFee(); - error InvalidFeeLight(); - error InvalidFeeWallet(); - error InvalidStaking(); - error OrderExpired(); - error MaxTooHigh(); - error NonceAlreadyUsed(uint256); - error ScaleTooHigh(); - error SignatoryInvalid(); - error SignatureInvalid(); - error TransferFromFailed(); - - function swap( - address recipient, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - function swapAnySender( - address recipient, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - function swapLight( - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external; - - function authorize(address sender) external; - - function revoke() external; - - function cancel(uint256[] calldata nonces) external; - - function check( - address senderWallet, - uint256 nonce, - uint256 expiry, - address signerWallet, - address signerToken, - uint256 signerAmount, - address senderToken, - uint256 senderAmount, - uint8 v, - bytes32 r, - bytes32 s - ) external view returns (bytes32[] memory); - - function nonceUsed(address, uint256) external view returns (bool); - - function authorized(address) external view returns (address); - - function calculateProtocolFee( - address, - uint256 - ) external view returns (uint256); -} diff --git a/source/delegate/package.json b/source/delegate/package.json index 9c35cf04e..3ecb87a1c 100644 --- a/source/delegate/package.json +++ b/source/delegate/package.json @@ -27,38 +27,9 @@ "migrate": "hardhat run ./scripts/migrate.js", "balances": "hardhat run ./scripts/balances.js" }, - "dependencies": { - "@airswap/utils": "4.2.4", - "@nomiclabs/hardhat-etherscan": "^3.1.0", - "@nomiclabs/hardhat-waffle": "^2.0.3", - "@openzeppelin/contracts": "^4.8.3", - "@typechain/ethers-v5": "^10.2.0", - "@typechain/hardhat": "^6.1.5", - "@types/mocha": "^10.0.1", - "@types/node": "^18.15.11", - "@typescript-eslint/eslint-plugin": "^5.58.0", - "@typescript-eslint/parser": "^5.58.0", - "chai": "^4.3.6", - "dotenv": "^16.0.1", - "eslint": "^8.20.0", - "eslint-config-prettier": "^8.5.0", - "hardhat": "^2.12.7", - "hardhat-gas-reporter": "^1.0.9", - "lerna": "^7.3.0", - "mocha": "^10.2.0", - "prettier": "^2.8.4", - "prettier-plugin-solidity": "^1.1.2", - "solidity-coverage": "^0.8.5", - "ts-node": "^10.9.1", - "typechain": "^8.1.1", - "typescript": "^5.0.4" - }, "devDependencies": { - "@airswap/constants": "4.1.6", - "@airswap/metadata": "4.1.12", - "@airswap/swap-erc20": "^4.2.0", - "@airswap/types": "4.1.1", - "@airswap/utils": "4.2.4", + "@airswap/utils": "4.3.2", + "@airswap/swap-erc20": "4.3.1", "prompt-confirm": "^2.0.4" }, "publishConfig": { diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 0da1b0609..7028b4b59 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -86,7 +86,10 @@ describe('Delegate Unit', () => { before(async () => { ;[deployer, delegator, taker, anyone] = await ethers.getSigners() - const swapERC20Factory = await ethers.getContractFactory('SwapERC20') + const swapERC20Factory = await ethers.getContractFactory( + SWAP_ERC20.abi, + SWAP_ERC20.bytecode + ) swapERC20 = await swapERC20Factory.deploy( PROTOCOL_FEE, PROTOCOL_FEE_LIGHT, From 274f770dfcb3a9f79081a28abecd8864275959a4 Mon Sep 17 00:00:00 2001 From: Don Mosites Date: Thu, 21 Mar 2024 23:53:36 +0100 Subject: [PATCH 21/43] name updates; test quickfix --- source/delegate/contracts/Delegate.sol | 80 ++++++------ .../contracts/interfaces/IDelegate.sol | 30 ++--- source/delegate/test/Delegate.js | 121 +++++++++--------- source/delegate/test/DelegateIntegration.js | 73 +++++------ 4 files changed, 149 insertions(+), 155 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 2bc04229d..5a0e7c920 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -17,7 +17,7 @@ contract Delegate is IDelegate, Ownable { // The Swap contract to be used to settle trades ISwapERC20 public swapERC20; - // Mapping of delegator to delegatorToken to to takerToken to remaining DelegatorAmount + // Mapping of sender to senderToken to to signerToken to remaining amount mapping(address => mapping(address => mapping(address => uint256))) public rules; @@ -30,86 +30,84 @@ contract Delegate is IDelegate, Ownable { /** * @notice Set a Trading Rule - * @param _delegatorToken address Address of an ERC-20 token the consumer would send + * @param _senderToken address Address of an ERC-20 token the consumer would send * @param _maxDelegatorAmount uint256 Maximum amount of ERC-20 token the delegate would send - * @param _takerToken address Address of an ERC-20 token the delegate would recieve - * @param _minTakerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve + * @param _signerToken address Address of an ERC-20 token the delegate would recieve + * @param _minSignerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve */ function setRule( - address _delegatorToken, + address _senderToken, uint256 _maxDelegatorAmount, - address _takerToken, - uint256 _minTakerAmount + address _signerToken, + uint256 _minSignerAmount ) external { - rules[msg.sender][_delegatorToken][_takerToken] = _maxDelegatorAmount; + rules[msg.sender][_senderToken][_signerToken] = _maxDelegatorAmount; emit SetRule( msg.sender, - _delegatorToken, + _senderToken, _maxDelegatorAmount, - _takerToken, - _minTakerAmount + _signerToken, + _minSignerAmount ); } /** * @notice Unset a Trading Rule * @dev only callable by the owner of the contract, removes from a mapping - * @param _delegatorToken address Address of an ERC-20 token the delegator would send - * @param _takerToken address Address of an ERC-20 token the delegate would receive + * @param _senderToken address Address of an ERC-20 token the sender would send + * @param _signerToken address Address of an ERC-20 token the delegate would receive */ - function unsetRule(address _delegatorToken, address _takerToken) external { - rules[msg.sender][_delegatorToken][_takerToken] = 0; - emit UnsetRule(msg.sender, _delegatorToken, _takerToken); + function unsetRule(address _senderToken, address _signerToken) external { + rules[msg.sender][_senderToken][_signerToken] = 0; + emit UnsetRule(msg.sender, _senderToken, _signerToken); } function swap( - address _delegator, + address _delegatorWallet, uint256 _nonce, uint256 _expiry, - address _takerWallet, - address _takerToken, - uint256 _takerAmount, - address _delegatorToken, - uint256 _delegatorAmount, + address _signerWallet, + address _signerToken, + uint256 _signerAmount, + address _senderToken, + uint256 _senderAmount, uint8 _v, bytes32 _r, bytes32 _s ) external { - if (rules[_delegator][_delegatorToken][_takerToken] < _delegatorAmount) { + if (rules[_delegatorWallet][_senderToken][_signerToken] < _senderAmount) { revert InsufficientDelegatorAmount(); } SafeTransferLib.safeTransferFrom( - _delegatorToken, - _delegator, + _senderToken, + _delegatorWallet, address(this), - _delegatorAmount + _senderAmount ); - ERC20(_delegatorToken).approve(address(swapERC20), _delegatorAmount); + ERC20(_senderToken).approve(address(swapERC20), _senderAmount); - swapERC20.swap( - address(this), + swapERC20.swapLight( _nonce, _expiry, - _takerWallet, - _takerToken, - _takerAmount, - _delegatorToken, - _delegatorAmount, + _signerWallet, + _signerToken, + _signerAmount, + _senderToken, + _senderAmount, _v, _r, _s ); - SafeTransferLib.safeTransferFrom( - _takerToken, - address(this), - _delegator, - ERC20(_takerToken).balanceOf(address(this)) + SafeTransferLib.safeTransfer( + _signerToken, + _delegatorWallet, + _signerAmount ); - rules[_delegator][_delegatorToken][_takerToken] -= _delegatorAmount; - emit DelegateSwap(_nonce, _takerWallet); + rules[_delegatorWallet][_senderToken][_signerToken] -= _senderAmount; + emit DelegateSwap(_nonce, _signerWallet); } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 91a0add4d..a26156f36 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -17,39 +17,39 @@ interface IDelegate { event DelegateSwap(uint256 _nonce, address _signerWallet); event SetRule( - address _delegator, - address _delegatorToken, + address _signer, + address _signerToken, uint256 _maxDelegatorAmount, - address _takerToken, + address _senderToken, uint256 _minTakerAmount ); event UnsetRule( - address _delegator, - address _delegatorToken, - address _takerToken + address _signer, + address _signerToken, + address _senderToken ); function setRule( - address _delegatorToken, + address _signerToken, uint256 _maxDelegatorAmount, - address _takerToken, + address _senderToken, uint256 _minTakerAmount ) external; function swap( - address _delegator, + address _senderWallet, uint256 _nonce, uint256 _expiry, - address _takerWallet, - address _delegatorToken, - uint256 _delegatorAmount, - address _takerToken, - uint256 _takerAmount, + address _signerWallet, + address _signerToken, + uint256 _signerAmount, + address _senderToken, + uint256 _senderAmount, uint8 _v, bytes32 _r, bytes32 _s ) external; - function unsetRule(address _delegatorToken, address _takerToken) external; + function unsetRule(address _signerToken, address _senderToken) external; } diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 7028b4b59..a567799be 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -12,29 +12,28 @@ const { const CHAIN_ID = 31337 const DEFAULT_BALANCE = '100000' const DEFAULT_AMOUNT = '10000' -const PROTOCOL_FEE = '30' -const PROTOCOL_FEE_LIGHT = '7' +const PROTOCOL_FEE = '5' const REBATE_SCALE = '10' const REBATE_MAX = '100' describe('Delegate Unit', () => { let deployer - let delegator - let taker + let sender + let signer let swapERC20 - let delegatorToken - let takerToken + let senderToken + let signerToken let delegate let snapshotId async function createSignedOrderERC20(params, signatory) { const unsignedOrder = createOrderERC20({ protocolFee: PROTOCOL_FEE, - signerWallet: taker.address, - signerToken: takerToken.address, + signerWallet: signer.address, + signerToken: signerToken.address, signerAmount: DEFAULT_AMOUNT, senderWallet: delegate.address, - senderToken: delegatorToken.address, + senderToken: senderToken.address, senderAmount: DEFAULT_AMOUNT, ...params, }) @@ -50,27 +49,27 @@ describe('Delegate Unit', () => { } async function setUpAllowances( - delegatorWallet, - delegatorAmount, - takerWallet, - takerAmount + senderWallet, + senderAmount, + signerWallet, + signerAmount ) { - await delegatorToken.mock.allowance - .withArgs(delegatorWallet, delegate.address) - .returns(delegatorAmount) - await takerToken.mock.allowance - .withArgs(takerWallet, swapERC20.address) - .returns(takerAmount) + await senderToken.mock.allowance + .withArgs(senderWallet, delegate.address) + .returns(senderAmount) + await signerToken.mock.allowance + .withArgs(signerWallet, swapERC20.address) + .returns(signerAmount) } - async function setUpBalances(delegatorWallet, takerWallet) { - await delegatorToken.mock.balanceOf - .withArgs(delegatorWallet) + async function setUpBalances(senderWallet, signerWallet) { + await senderToken.mock.balanceOf + .withArgs(senderWallet) .returns(DEFAULT_BALANCE) - await takerToken.mock.balanceOf - .withArgs(takerWallet) + await signerToken.mock.balanceOf + .withArgs(signerWallet) .returns(DEFAULT_BALANCE) - await takerToken.mock.balanceOf + await signerToken.mock.balanceOf .withArgs(delegate.address) .returns(DEFAULT_AMOUNT) } @@ -84,7 +83,7 @@ describe('Delegate Unit', () => { }) before(async () => { - ;[deployer, delegator, taker, anyone] = await ethers.getSigners() + ;[deployer, sender, signer, anyone] = await ethers.getSigners() const swapERC20Factory = await ethers.getContractFactory( SWAP_ERC20.abi, @@ -92,7 +91,7 @@ describe('Delegate Unit', () => { ) swapERC20 = await swapERC20Factory.deploy( PROTOCOL_FEE, - PROTOCOL_FEE_LIGHT, + PROTOCOL_FEE, deployer.address, REBATE_SCALE, REBATE_MAX @@ -103,10 +102,12 @@ describe('Delegate Unit', () => { ).deploy(swapERC20.address) await delegate.deployed() - delegatorToken = await deployMockContract(deployer, IERC20.abi) - takerToken = await deployMockContract(deployer, IERC20.abi) - await delegatorToken.mock.transferFrom.returns(true) - await takerToken.mock.transferFrom.returns(true) + senderToken = await deployMockContract(deployer, IERC20.abi) + signerToken = await deployMockContract(deployer, IERC20.abi) + await senderToken.mock.transferFrom.returns(true) + await signerToken.mock.transferFrom.returns(true) + await senderToken.mock.transfer.returns(true) + await signerToken.mock.transfer.returns(true) }) describe('Constructor', async () => { @@ -119,20 +120,20 @@ describe('Delegate Unit', () => { it('sets a Rule', async () => { await expect( delegate - .connect(delegator) + .connect(sender) .setRule( - delegatorToken.address, + senderToken.address, DEFAULT_AMOUNT, - takerToken.address, + signerToken.address, DEFAULT_AMOUNT ) ) .to.emit(delegate, 'SetRule') .withArgs( - delegator.address, - delegatorToken.address, + sender.address, + senderToken.address, DEFAULT_AMOUNT, - takerToken.address, + signerToken.address, DEFAULT_AMOUNT ) }) @@ -140,80 +141,80 @@ describe('Delegate Unit', () => { it('unsets a Rule', async () => { await expect( delegate - .connect(delegator) - .unsetRule(delegatorToken.address, takerToken.address) + .connect(sender) + .unsetRule(senderToken.address, signerToken.address) ) .to.emit(delegate, 'UnsetRule') - .withArgs(delegator.address, delegatorToken.address, takerToken.address) + .withArgs(sender.address, senderToken.address, signerToken.address) }) }) describe('Swap', async () => { it('successfully swaps', async () => { await delegate - .connect(delegator) + .connect(sender) .setRule( - delegatorToken.address, + senderToken.address, DEFAULT_AMOUNT, - takerToken.address, + signerToken.address, DEFAULT_AMOUNT ) - const order = await createSignedOrderERC20({}, taker) + const order = await createSignedOrderERC20({}, signer) await setUpAllowances( - delegator.address, + sender.address, DEFAULT_AMOUNT, - taker.address, + signer.address, DEFAULT_AMOUNT + PROTOCOL_FEE ) - await setUpBalances(taker.address, delegator.address) + await setUpBalances(signer.address, sender.address) - await delegatorToken.mock.approve + await senderToken.mock.approve .withArgs(delegate.address, DEFAULT_AMOUNT) .returns(true) - await delegatorToken.mock.approve + await senderToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await takerToken.mock.approve + await signerToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await takerToken.mock.approve + await signerToken.mock.approve .withArgs(delegate.address, DEFAULT_AMOUNT) .returns(true) await expect( - delegate.connect(taker).swap(delegator.address, ...order) + delegate.connect(signer).swap(sender.address, ...order) ).to.emit(delegate, 'DelegateSwap') }) it('fails to swap with no rule', async () => { - const order = await createSignedOrderERC20({}, taker) + const order = await createSignedOrderERC20({}, signer) await setUpAllowances( - taker.address, + signer.address, DEFAULT_AMOUNT + PROTOCOL_FEE, - delegator.address, + sender.address, DEFAULT_AMOUNT ) - await setUpBalances(taker.address, delegator.address) + await setUpBalances(signer.address, sender.address) - await delegatorToken.mock.approve + await senderToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await takerToken.mock.approve + await signerToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - await takerToken.mock.balanceOf + await signerToken.mock.balanceOf .withArgs(delegate.address) .returns(DEFAULT_AMOUNT) - await expect(delegate.connect(taker).swap(delegator.address, ...order)).to + await expect(delegate.connect(signer).swap(sender.address, ...order)).to .be.reverted }) }) diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js index c51b85072..a5e03fae1 100644 --- a/source/delegate/test/DelegateIntegration.js +++ b/source/delegate/test/DelegateIntegration.js @@ -10,29 +10,28 @@ const SWAP_ERC20 = require('@airswap/swap-erc20/build/contracts/SwapERC20.sol/Sw describe('Delegate Integration', () => { let snapshotId - let takerToken - let delegatorToken + let signerToken + let senderToken let deployer - let delegator - let taker + let sender + let signer const CHAIN_ID = 31337 const BONUS_SCALE = '10' const BONUS_MAX = '100' - const PROTOCOL_FEE = '30' - const PROTOCOL_FEE_LIGHT = '7' + const PROTOCOL_FEE = '5' const DEFAULT_AMOUNT = '10000' const DEFAULT_BALANCE = '1000000' - async function createSignedOrderERC20(params, taker) { + async function createSignedOrderERC20(params, signer) { const unsignedOrder = createOrderERC20({ protocolFee: PROTOCOL_FEE, - signerWallet: taker.address, - signerToken: takerToken.address, + signerWallet: signer.address, + signerToken: signerToken.address, signerAmount: DEFAULT_AMOUNT, senderWallet: delegate.address, - senderToken: delegatorToken.address, + senderToken: senderToken.address, senderAmount: DEFAULT_AMOUNT, ...params, }) @@ -40,7 +39,7 @@ describe('Delegate Integration', () => { ...unsignedOrder, ...(await createOrderERC20Signature( unsignedOrder, - taker, + signer, swapERC20.address, CHAIN_ID )), @@ -56,13 +55,13 @@ describe('Delegate Integration', () => { }) before('get signers and deploy', async () => { - ;[deployer, delegator, taker, protocolFeeWallet] = await ethers.getSigners() + ;[deployer, sender, signer, protocolFeeWallet] = await ethers.getSigners() swapERC20 = await ( await ethers.getContractFactory(SWAP_ERC20.abi, SWAP_ERC20.bytecode) ).deploy( PROTOCOL_FEE, - PROTOCOL_FEE_LIGHT, + PROTOCOL_FEE, deployer.address, BONUS_SCALE, BONUS_MAX @@ -74,67 +73,63 @@ describe('Delegate Integration', () => { ).deploy(swapERC20.address) await delegate.deployed() - takerToken = await ( + signerToken = await ( await ethers.getContractFactory(ERC20.abi, ERC20.bytecode) ).deploy('A', 'A') - await takerToken.deployed() - await takerToken.mint(taker.address, DEFAULT_BALANCE) + await signerToken.deployed() + await signerToken.mint(signer.address, DEFAULT_BALANCE) - delegatorToken = await ( + senderToken = await ( await ethers.getContractFactory(ERC20.abi, ERC20.bytecode) ).deploy('B', 'B') - await delegatorToken.deployed() - await delegatorToken.mint(delegator.address, DEFAULT_BALANCE) + await senderToken.deployed() + await senderToken.mint(sender.address, DEFAULT_BALANCE) - takerToken.connect(taker).approve(swapERC20.address, DEFAULT_BALANCE) - delegatorToken - .connect(delegator) - .approve(swapERC20.address, DEFAULT_BALANCE) + signerToken.connect(signer).approve(swapERC20.address, DEFAULT_BALANCE) + senderToken.connect(sender).approve(delegate.address, DEFAULT_BALANCE) }) describe('Test transfers', async () => { it('test a delegated swap', async () => { await delegate - .connect(delegator) + .connect(sender) .setRule( - delegatorToken.address, + senderToken.address, DEFAULT_AMOUNT, - takerToken.address, + signerToken.address, DEFAULT_AMOUNT ) - delegatorToken - .connect(delegator) - .approve(delegate.address, DEFAULT_AMOUNT) + senderToken.connect(sender).approve(delegate.address, DEFAULT_AMOUNT) - takerToken - .connect(taker) + signerToken + .connect(signer) .approve(swapERC20.address, DEFAULT_AMOUNT + PROTOCOL_FEE) - const order = await createSignedOrderERC20({}, taker) + const order = await createSignedOrderERC20({}, signer) await expect( - delegate.connect(taker).swap(delegator.address, ...order) + delegate.connect(signer).swap(sender.address, ...order) ).to.emit(delegate, 'DelegateSwap') - expect(await takerToken.balanceOf(delegator.address)).to.equal( + expect(await signerToken.balanceOf(sender.address)).to.equal( DEFAULT_AMOUNT ) - expect(await takerToken.balanceOf(taker.address)).to.equal( + expect(await signerToken.balanceOf(signer.address)).to.equal( DEFAULT_BALANCE - DEFAULT_AMOUNT - PROTOCOL_FEE ) - expect(await delegatorToken.balanceOf(taker.address)).to.equal( + expect(await senderToken.balanceOf(signer.address)).to.equal( DEFAULT_AMOUNT ) - expect(await delegatorToken.balanceOf(delegator.address)).to.equal( + expect(await senderToken.balanceOf(sender.address)).to.equal( DEFAULT_BALANCE - DEFAULT_AMOUNT ) - expect(await delegatorToken.balanceOf(delegate.address)).to.equal(0) - expect(await takerToken.balanceOf(delegate.address)).to.equal(0) + expect(await senderToken.balanceOf(delegate.address)).to.equal(0) + expect(await signerToken.balanceOf(delegate.address)).to.equal(0) }) }) }) From 4b1a9935fe11607f8c7a3a41639071cde954d5d8 Mon Sep 17 00:00:00 2001 From: Don Mosites Date: Thu, 21 Mar 2024 23:53:58 +0100 Subject: [PATCH 22/43] prettier --- source/delegate/contracts/Delegate.sol | 6 +----- source/delegate/contracts/interfaces/IDelegate.sol | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 5a0e7c920..ec97b6e37 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -101,11 +101,7 @@ contract Delegate is IDelegate, Ownable { _s ); - SafeTransferLib.safeTransfer( - _signerToken, - _delegatorWallet, - _signerAmount - ); + SafeTransferLib.safeTransfer(_signerToken, _delegatorWallet, _signerAmount); rules[_delegatorWallet][_senderToken][_signerToken] -= _senderAmount; emit DelegateSwap(_nonce, _signerWallet); diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index a26156f36..2812102d4 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -24,11 +24,7 @@ interface IDelegate { uint256 _minTakerAmount ); - event UnsetRule( - address _signer, - address _signerToken, - address _senderToken - ); + event UnsetRule(address _signer, address _signerToken, address _senderToken); function setRule( address _signerToken, From 10b0548668fe9dad4e33b4fe73e49146ca505ec1 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Fri, 29 Mar 2024 06:40:05 -0400 Subject: [PATCH 23/43] Renamed _maxDelegatorAmount to _maxSenderAmount for consistency --- source/delegate/contracts/Delegate.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index ec97b6e37..5180ebd8e 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -31,21 +31,21 @@ contract Delegate is IDelegate, Ownable { /** * @notice Set a Trading Rule * @param _senderToken address Address of an ERC-20 token the consumer would send - * @param _maxDelegatorAmount uint256 Maximum amount of ERC-20 token the delegate would send + * @param _maxSenderAmount uint256 Maximum amount of ERC-20 token the sender wants to swap * @param _signerToken address Address of an ERC-20 token the delegate would recieve * @param _minSignerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve */ function setRule( address _senderToken, - uint256 _maxDelegatorAmount, + uint256 _maxSenderAmount, address _signerToken, uint256 _minSignerAmount ) external { - rules[msg.sender][_senderToken][_signerToken] = _maxDelegatorAmount; + rules[msg.sender][_senderToken][_signerToken] = _maxSenderAmount; emit SetRule( msg.sender, _senderToken, - _maxDelegatorAmount, + _maxSenderAmount, _signerToken, _minSignerAmount ); From 868dfd7f4ab5730165b4678588ba9b7aba7f9edc Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Fri, 29 Mar 2024 06:48:09 -0400 Subject: [PATCH 24/43] Added test to check delegate allowance --- source/delegate/contracts/Delegate.sol | 2 +- .../contracts/interfaces/IDelegate.sol | 2 +- source/delegate/test/Delegate.js | 73 +++++++++++++------ 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 5180ebd8e..8317d989a 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -76,7 +76,7 @@ contract Delegate is IDelegate, Ownable { bytes32 _s ) external { if (rules[_delegatorWallet][_senderToken][_signerToken] < _senderAmount) { - revert InsufficientDelegatorAmount(); + revert InsufficientDelegateAllowance(); } SafeTransferLib.safeTransferFrom( diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 2812102d4..636230a5f 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -11,7 +11,7 @@ interface IDelegate { uint256 priceExp; // Indicates location of the decimal priceCoef * 10^(-priceExp) } - error InsufficientDelegatorAmount(); + error InsufficientDelegateAllowance(); error TransferFromFailed(); event DelegateSwap(uint256 _nonce, address _signerWallet); diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index a567799be..aba1c2b71 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -74,6 +74,24 @@ describe('Delegate Unit', () => { .returns(DEFAULT_AMOUNT) } + async function setUpApprovals() { + await senderToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT) + .returns(true) + + await senderToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + + await signerToken.mock.approve + .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .returns(true) + + await signerToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT) + .returns(true) + } + beforeEach(async () => { snapshotId = await ethers.provider.send('evm_snapshot') }) @@ -170,21 +188,7 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) - await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT) - .returns(true) - - await senderToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) - .returns(true) - - await signerToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) - .returns(true) - - await signerToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT) - .returns(true) + await setUpApprovals() await expect( delegate.connect(signer).swap(sender.address, ...order) @@ -202,13 +206,7 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) - await senderToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) - .returns(true) - - await signerToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) - .returns(true) + setUpApprovals() await signerToken.mock.balanceOf .withArgs(delegate.address) @@ -217,5 +215,36 @@ describe('Delegate Unit', () => { await expect(delegate.connect(signer).swap(sender.address, ...order)).to .be.reverted }) + + it('fails to swap with insufficient remaining signer amount on Rule', async () => { + await delegate + .connect(sender) + .setRule( + senderToken.address, + DEFAULT_AMOUNT - 1, + signerToken.address, + DEFAULT_AMOUNT + ) + + const order = await createSignedOrderERC20({}, signer) + + await setUpAllowances( + sender.address, + DEFAULT_AMOUNT, + signer.address, + DEFAULT_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(signer.address, sender.address) + + await setUpApprovals() + + await signerToken.mock.balanceOf + .withArgs(signer.address) + .returns(DEFAULT_AMOUNT - 1) + + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.be.revertedWith('InsufficientSenderAmount') + }) }) }) From b27a3b17b46d09c19763a5c824e39394e934f523 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Fri, 29 Mar 2024 07:22:10 -0400 Subject: [PATCH 25/43] Added internal rule tests --- source/delegate/contracts/Delegate.sol | 1 + source/delegate/test/Delegate.js | 49 ++++++++++++++++----- source/delegate/test/DelegateIntegration.js | 2 - 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 8317d989a..f15dc0e09 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -42,6 +42,7 @@ contract Delegate is IDelegate, Ownable { uint256 _minSignerAmount ) external { rules[msg.sender][_senderToken][_signerToken] = _maxSenderAmount; + emit SetRule( msg.sender, _senderToken, diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index aba1c2b71..3e56b8c25 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -86,10 +86,6 @@ describe('Delegate Unit', () => { await signerToken.mock.approve .withArgs(swapERC20.address, DEFAULT_AMOUNT) .returns(true) - - await signerToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT) - .returns(true) } beforeEach(async () => { @@ -126,6 +122,8 @@ describe('Delegate Unit', () => { await signerToken.mock.transferFrom.returns(true) await senderToken.mock.transfer.returns(true) await signerToken.mock.transfer.returns(true) + + setUpApprovals() }) describe('Constructor', async () => { @@ -165,6 +163,37 @@ describe('Delegate Unit', () => { .to.emit(delegate, 'UnsetRule') .withArgs(sender.address, senderToken.address, signerToken.address) }) + + it('setting and unsetting a Rule updates the rule balance', async () => { + await delegate + .connect(sender) + .setRule( + senderToken.address, + DEFAULT_AMOUNT, + signerToken.address, + DEFAULT_AMOUNT + ) + + expect( + await delegate.rules( + sender.address, + senderToken.address, + signerToken.address + ) + ).to.equal(DEFAULT_AMOUNT) + + await delegate + .connect(sender) + .unsetRule(senderToken.address, signerToken.address) + + expect( + await delegate.rules( + sender.address, + senderToken.address, + signerToken.address + ) + ).to.equal(0) + }) }) describe('Swap', async () => { @@ -188,8 +217,6 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) - await setUpApprovals() - await expect( delegate.connect(signer).swap(sender.address, ...order) ).to.emit(delegate, 'DelegateSwap') @@ -206,8 +233,6 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) - setUpApprovals() - await signerToken.mock.balanceOf .withArgs(delegate.address) .returns(DEFAULT_AMOUNT) @@ -217,6 +242,10 @@ describe('Delegate Unit', () => { }) it('fails to swap with insufficient remaining signer amount on Rule', async () => { + await senderToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT - 1) + .returns(true) + await delegate .connect(sender) .setRule( @@ -236,15 +265,13 @@ describe('Delegate Unit', () => { ) await setUpBalances(signer.address, sender.address) - await setUpApprovals() - await signerToken.mock.balanceOf .withArgs(signer.address) .returns(DEFAULT_AMOUNT - 1) await expect( delegate.connect(signer).swap(sender.address, ...order) - ).to.be.revertedWith('InsufficientSenderAmount') + ).to.be.revertedWith('InsufficientDelegateAllowance') }) }) }) diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js index a5e03fae1..a224efede 100644 --- a/source/delegate/test/DelegateIntegration.js +++ b/source/delegate/test/DelegateIntegration.js @@ -100,8 +100,6 @@ describe('Delegate Integration', () => { DEFAULT_AMOUNT ) - senderToken.connect(sender).approve(delegate.address, DEFAULT_AMOUNT) - signerToken .connect(signer) .approve(swapERC20.address, DEFAULT_AMOUNT + PROTOCOL_FEE) From 8f1c372056d12f9228b63782068e96ef1d1e52e7 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 4 Apr 2024 18:16:44 -0400 Subject: [PATCH 26/43] Implemented Delegate price check --- source/delegate/contracts/Delegate.sol | 41 +++++++---- .../contracts/interfaces/IDelegate.sol | 23 +++--- source/delegate/test/Delegate.js | 70 ++++++++++++++----- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index f15dc0e09..351b21229 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -17,9 +17,8 @@ contract Delegate is IDelegate, Ownable { // The Swap contract to be used to settle trades ISwapERC20 public swapERC20; - // Mapping of sender to senderToken to to signerToken to remaining amount - mapping(address => mapping(address => mapping(address => uint256))) - public rules; + // Mapping of sender to senderToken to to signerToken to Rule + mapping(address => mapping(address => mapping(address => Rule))) public rules; /** * @notice Contract Constructor @@ -31,24 +30,30 @@ contract Delegate is IDelegate, Ownable { /** * @notice Set a Trading Rule * @param _senderToken address Address of an ERC-20 token the consumer would send - * @param _maxSenderAmount uint256 Maximum amount of ERC-20 token the sender wants to swap + * @param _senderAmount uint256 Maximum amount of ERC-20 token the sender wants to swap * @param _signerToken address Address of an ERC-20 token the delegate would recieve - * @param _minSignerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve + * @param _signerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve */ function setRule( address _senderToken, - uint256 _maxSenderAmount, + uint256 _senderAmount, address _signerToken, - uint256 _minSignerAmount + uint256 _signerAmount ) external { - rules[msg.sender][_senderToken][_signerToken] = _maxSenderAmount; + rules[msg.sender][_senderToken][_signerToken] = Rule( + msg.sender, + _senderToken, + _senderAmount, + _signerToken, + _signerAmount + ); emit SetRule( msg.sender, _senderToken, - _maxSenderAmount, + _senderAmount, _signerToken, - _minSignerAmount + _signerAmount ); } @@ -59,7 +64,8 @@ contract Delegate is IDelegate, Ownable { * @param _signerToken address Address of an ERC-20 token the delegate would receive */ function unsetRule(address _senderToken, address _signerToken) external { - rules[msg.sender][_senderToken][_signerToken] = 0; + Rule storage rule = rules[msg.sender][_senderToken][_signerToken]; + rule.senderAmount = 0; emit UnsetRule(msg.sender, _senderToken, _signerToken); } @@ -76,7 +82,15 @@ contract Delegate is IDelegate, Ownable { bytes32 _r, bytes32 _s ) external { - if (rules[_delegatorWallet][_senderToken][_signerToken] < _senderAmount) { + Rule storage rule = rules[_delegatorWallet][_senderToken][_signerToken]; + + if ( + _senderAmount > (_signerAmount * rule.senderAmount) / rule.signerAmount + ) { + revert InsufficientSignerAmount(); + } + + if (rule.senderAmount < _senderAmount) { revert InsufficientDelegateAllowance(); } @@ -104,7 +118,8 @@ contract Delegate is IDelegate, Ownable { SafeTransferLib.safeTransfer(_signerToken, _delegatorWallet, _signerAmount); - rules[_delegatorWallet][_senderToken][_signerToken] -= _senderAmount; + rules[_delegatorWallet][_senderToken][_signerToken] + .senderAmount -= _senderAmount; emit DelegateSwap(_nonce, _signerWallet); } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index 636230a5f..dfcde9123 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -6,31 +6,34 @@ pragma solidity 0.8.23; interface IDelegate { struct Rule { - uint256 maxSenderAmount; // The maximum amount of ERC-20 token the delegate would send - uint256 priceCoef; // Number to be multiplied by 10^(-priceExp) - the price coefficient - uint256 priceExp; // Indicates location of the decimal priceCoef * 10^(-priceExp) + address sender; + address senderToken; + uint256 senderAmount; + address signerToken; + uint256 signerAmount; } error InsufficientDelegateAllowance(); + error InsufficientSignerAmount(); error TransferFromFailed(); event DelegateSwap(uint256 _nonce, address _signerWallet); event SetRule( - address _signer, - address _signerToken, - uint256 _maxDelegatorAmount, + address _sender, address _senderToken, - uint256 _minTakerAmount + uint256 _senderAmount, + address _signerToken, + uint256 _signerAmount ); event UnsetRule(address _signer, address _signerToken, address _senderToken); function setRule( - address _signerToken, - uint256 _maxDelegatorAmount, address _senderToken, - uint256 _minTakerAmount + uint256 _senderAmount, + address _signerToken, + uint256 _signerAmount ) external; function swap( diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 3e56b8c25..99719a102 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -174,25 +174,25 @@ describe('Delegate Unit', () => { DEFAULT_AMOUNT ) - expect( - await delegate.rules( - sender.address, - senderToken.address, - signerToken.address - ) - ).to.equal(DEFAULT_AMOUNT) + let rule = await delegate.rules( + sender.address, + senderToken.address, + signerToken.address + ) + + expect(rule.senderAmount.toString()).to.equal(DEFAULT_AMOUNT) await delegate .connect(sender) .unsetRule(senderToken.address, signerToken.address) - expect( - await delegate.rules( - sender.address, - senderToken.address, - signerToken.address - ) - ).to.equal(0) + rule = await delegate.rules( + sender.address, + senderToken.address, + signerToken.address + ) + + expect(rule.senderAmount.toString()).to.equal('0') }) }) @@ -241,7 +241,7 @@ describe('Delegate Unit', () => { .be.reverted }) - it('fails to swap with insufficient remaining signer amount on Rule', async () => { + it('fails to swap with insufficient remaining sender amount on Rule', async () => { await senderToken.mock.approve .withArgs(delegate.address, DEFAULT_AMOUNT - 1) .returns(true) @@ -252,7 +252,7 @@ describe('Delegate Unit', () => { senderToken.address, DEFAULT_AMOUNT - 1, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_AMOUNT - 1 ) const order = await createSignedOrderERC20({}, signer) @@ -273,5 +273,43 @@ describe('Delegate Unit', () => { delegate.connect(signer).swap(sender.address, ...order) ).to.be.revertedWith('InsufficientDelegateAllowance') }) + + it('fails to swap with insufficient signer amount on Rule', async () => { + await senderToken.mock.approve + .withArgs(delegate.address, DEFAULT_AMOUNT - 1) + .returns(true) + + await delegate + .connect(sender) + .setRule( + senderToken.address, + DEFAULT_AMOUNT, + signerToken.address, + DEFAULT_AMOUNT + ) + + const order = await createSignedOrderERC20( + { + signerAmount: DEFAULT_AMOUNT - 1, + }, + signer + ) + + await setUpAllowances( + sender.address, + DEFAULT_AMOUNT, + signer.address, + DEFAULT_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(signer.address, sender.address) + + await signerToken.mock.balanceOf + .withArgs(signer.address) + .returns(DEFAULT_AMOUNT - 1) + + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.be.revertedWith('InsufficientSignerAmount') + }) }) }) From c505ce51c3896189b5e91d0fb498aac157f9170a Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 4 Apr 2024 21:10:32 -0400 Subject: [PATCH 27/43] Separated setting and unsetting rules tests --- source/delegate/test/Delegate.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 99719a102..fbff275ed 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -164,7 +164,7 @@ describe('Delegate Unit', () => { .withArgs(sender.address, senderToken.address, signerToken.address) }) - it('setting and unsetting a Rule updates the rule balance', async () => { + it('setting a Rule updates the rule balance', async () => { await delegate .connect(sender) .setRule( @@ -181,6 +181,23 @@ describe('Delegate Unit', () => { ) expect(rule.senderAmount.toString()).to.equal(DEFAULT_AMOUNT) + }) + + it('unsetting a Rule updates the rule balance', async () => { + await delegate + .connect(sender) + .setRule( + senderToken.address, + DEFAULT_AMOUNT, + signerToken.address, + DEFAULT_AMOUNT + ) + + let rule = await delegate.rules( + sender.address, + senderToken.address, + signerToken.address + ) await delegate .connect(sender) From 7b976cc0cbb334aa0105e55606e4d77b02899ea1 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Tue, 9 Apr 2024 20:25:24 -0400 Subject: [PATCH 28/43] Specified DEFAULT_SIGNER_AMOUNT and DEFAULT_SENDER_AMOUNT in tests. Added a test case when SENDER_AMOUNT is above requirements --- source/delegate/test/Delegate.js | 103 +++++++++++++------- source/delegate/test/DelegateIntegration.js | 21 ++-- 2 files changed, 78 insertions(+), 46 deletions(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index fbff275ed..4b927e2a2 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -11,7 +11,8 @@ const { } = require('@airswap/utils') const CHAIN_ID = 31337 const DEFAULT_BALANCE = '100000' -const DEFAULT_AMOUNT = '10000' +const DEFAULT_SENDER_AMOUNT = '10000' +const DEFAULT_SIGNER_AMOUNT = '10000' const PROTOCOL_FEE = '5' const REBATE_SCALE = '10' const REBATE_MAX = '100' @@ -31,10 +32,10 @@ describe('Delegate Unit', () => { protocolFee: PROTOCOL_FEE, signerWallet: signer.address, signerToken: signerToken.address, - signerAmount: DEFAULT_AMOUNT, + signerAmount: DEFAULT_SIGNER_AMOUNT, senderWallet: delegate.address, senderToken: senderToken.address, - senderAmount: DEFAULT_AMOUNT, + senderAmount: DEFAULT_SENDER_AMOUNT, ...params, }) return orderERC20ToParams({ @@ -71,20 +72,20 @@ describe('Delegate Unit', () => { .returns(DEFAULT_BALANCE) await signerToken.mock.balanceOf .withArgs(delegate.address) - .returns(DEFAULT_AMOUNT) + .returns(DEFAULT_SIGNER_AMOUNT) } async function setUpApprovals() { await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT) + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT) .returns(true) await senderToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .withArgs(swapERC20.address, DEFAULT_SENDER_AMOUNT) .returns(true) await signerToken.mock.approve - .withArgs(swapERC20.address, DEFAULT_AMOUNT) + .withArgs(swapERC20.address, DEFAULT_SIGNER_AMOUNT) .returns(true) } @@ -139,18 +140,18 @@ describe('Delegate Unit', () => { .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) ) .to.emit(delegate, 'SetRule') .withArgs( sender.address, senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) }) @@ -169,9 +170,9 @@ describe('Delegate Unit', () => { .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) let rule = await delegate.rules( @@ -180,7 +181,7 @@ describe('Delegate Unit', () => { signerToken.address ) - expect(rule.senderAmount.toString()).to.equal(DEFAULT_AMOUNT) + expect(rule.senderAmount.toString()).to.equal(DEFAULT_SENDER_AMOUNT) }) it('unsetting a Rule updates the rule balance', async () => { @@ -188,9 +189,9 @@ describe('Delegate Unit', () => { .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) let rule = await delegate.rules( @@ -219,18 +220,48 @@ describe('Delegate Unit', () => { .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) const order = await createSignedOrderERC20({}, signer) await setUpAllowances( sender.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signer.address, - DEFAULT_AMOUNT + PROTOCOL_FEE + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(signer.address, sender.address) + + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.emit(delegate, 'DelegateSwap') + }) + + it('successfully swaps if sender amount is above the minimum', async () => { + await delegate + .connect(sender) + .setRule( + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT + ) + + const order = await createSignedOrderERC20( + { + senderAmount: DEFAULT_SENDER_AMOUNT + 1, + }, + signer + ) + + await setUpAllowances( + sender.address, + DEFAULT_SENDER_AMOUNT, + signer.address, + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE ) await setUpBalances(signer.address, sender.address) @@ -244,15 +275,15 @@ describe('Delegate Unit', () => { await setUpAllowances( signer.address, - DEFAULT_AMOUNT + PROTOCOL_FEE, + DEFAULT_SENDER_AMOUNT + PROTOCOL_FEE, sender.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) await setUpBalances(signer.address, sender.address) await signerToken.mock.balanceOf .withArgs(delegate.address) - .returns(DEFAULT_AMOUNT) + .returns(DEFAULT_SIGNER_AMOUNT) await expect(delegate.connect(signer).swap(sender.address, ...order)).to .be.reverted @@ -260,31 +291,31 @@ describe('Delegate Unit', () => { it('fails to swap with insufficient remaining sender amount on Rule', async () => { await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT - 1) + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT - 1) .returns(true) await delegate .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT - 1, + DEFAULT_SENDER_AMOUNT - 1, signerToken.address, - DEFAULT_AMOUNT - 1 + DEFAULT_SIGNER_AMOUNT - 1 ) const order = await createSignedOrderERC20({}, signer) await setUpAllowances( sender.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signer.address, - DEFAULT_AMOUNT + PROTOCOL_FEE + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE ) await setUpBalances(signer.address, sender.address) await signerToken.mock.balanceOf .withArgs(signer.address) - .returns(DEFAULT_AMOUNT - 1) + .returns(DEFAULT_SIGNER_AMOUNT - 1) await expect( delegate.connect(signer).swap(sender.address, ...order) @@ -293,36 +324,36 @@ describe('Delegate Unit', () => { it('fails to swap with insufficient signer amount on Rule', async () => { await senderToken.mock.approve - .withArgs(delegate.address, DEFAULT_AMOUNT - 1) + .withArgs(delegate.address, DEFAULT_SENDER_AMOUNT - 1) .returns(true) await delegate .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) const order = await createSignedOrderERC20( { - signerAmount: DEFAULT_AMOUNT - 1, + signerAmount: DEFAULT_SIGNER_AMOUNT - 1, }, signer ) await setUpAllowances( sender.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signer.address, - DEFAULT_AMOUNT + PROTOCOL_FEE + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE ) await setUpBalances(signer.address, sender.address) await signerToken.mock.balanceOf .withArgs(signer.address) - .returns(DEFAULT_AMOUNT - 1) + .returns(DEFAULT_SIGNER_AMOUNT - 1) await expect( delegate.connect(signer).swap(sender.address, ...order) diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js index a224efede..7a62905c9 100644 --- a/source/delegate/test/DelegateIntegration.js +++ b/source/delegate/test/DelegateIntegration.js @@ -21,7 +21,8 @@ describe('Delegate Integration', () => { const BONUS_SCALE = '10' const BONUS_MAX = '100' const PROTOCOL_FEE = '5' - const DEFAULT_AMOUNT = '10000' + const DEFAULT_SENDER_AMOUNT = '10000' + const DEFAULT_SIGNER_AMOUNT = '10000' const DEFAULT_BALANCE = '1000000' async function createSignedOrderERC20(params, signer) { @@ -29,10 +30,10 @@ describe('Delegate Integration', () => { protocolFee: PROTOCOL_FEE, signerWallet: signer.address, signerToken: signerToken.address, - signerAmount: DEFAULT_AMOUNT, + signerAmount: DEFAULT_SIGNER_AMOUNT, senderWallet: delegate.address, senderToken: senderToken.address, - senderAmount: DEFAULT_AMOUNT, + senderAmount: DEFAULT_SENDER_AMOUNT, ...params, }) return orderERC20ToParams({ @@ -95,14 +96,14 @@ describe('Delegate Integration', () => { .connect(sender) .setRule( senderToken.address, - DEFAULT_AMOUNT, + DEFAULT_SENDER_AMOUNT, signerToken.address, - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) signerToken .connect(signer) - .approve(swapERC20.address, DEFAULT_AMOUNT + PROTOCOL_FEE) + .approve(swapERC20.address, DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE) const order = await createSignedOrderERC20({}, signer) @@ -111,19 +112,19 @@ describe('Delegate Integration', () => { ).to.emit(delegate, 'DelegateSwap') expect(await signerToken.balanceOf(sender.address)).to.equal( - DEFAULT_AMOUNT + DEFAULT_SIGNER_AMOUNT ) expect(await signerToken.balanceOf(signer.address)).to.equal( - DEFAULT_BALANCE - DEFAULT_AMOUNT - PROTOCOL_FEE + DEFAULT_BALANCE - DEFAULT_SIGNER_AMOUNT - PROTOCOL_FEE ) expect(await senderToken.balanceOf(signer.address)).to.equal( - DEFAULT_AMOUNT + DEFAULT_SENDER_AMOUNT ) expect(await senderToken.balanceOf(sender.address)).to.equal( - DEFAULT_BALANCE - DEFAULT_AMOUNT + DEFAULT_BALANCE - DEFAULT_SENDER_AMOUNT ) expect(await senderToken.balanceOf(delegate.address)).to.equal(0) From 38727884162e96c64287489a9b3398e2d2d7cead Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Tue, 16 Apr 2024 08:46:36 -0400 Subject: [PATCH 29/43] Removed test to check if sender can send more token that defined in the rule --- source/delegate/test/Delegate.js | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 4b927e2a2..1283d8928 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -175,7 +175,7 @@ describe('Delegate Unit', () => { DEFAULT_SIGNER_AMOUNT ) - let rule = await delegate.rules( + const rule = await delegate.rules( sender.address, senderToken.address, signerToken.address @@ -240,36 +240,6 @@ describe('Delegate Unit', () => { ).to.emit(delegate, 'DelegateSwap') }) - it('successfully swaps if sender amount is above the minimum', async () => { - await delegate - .connect(sender) - .setRule( - senderToken.address, - DEFAULT_SENDER_AMOUNT, - signerToken.address, - DEFAULT_SIGNER_AMOUNT - ) - - const order = await createSignedOrderERC20( - { - senderAmount: DEFAULT_SENDER_AMOUNT + 1, - }, - signer - ) - - await setUpAllowances( - sender.address, - DEFAULT_SENDER_AMOUNT, - signer.address, - DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE - ) - await setUpBalances(signer.address, sender.address) - - await expect( - delegate.connect(signer).swap(sender.address, ...order) - ).to.emit(delegate, 'DelegateSwap') - }) - it('fails to swap with no rule', async () => { const order = await createSignedOrderERC20({}, signer) From 07076a387f5d70a160741e3804716fa37507af67 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 22 Apr 2024 07:39:10 -0400 Subject: [PATCH 30/43] Implemented signatory logic allowing sender to delegate rule setting on their behalf --- source/delegate/contracts/Delegate.sol | 62 +++++++++-- .../contracts/interfaces/IDelegate.sol | 12 +- source/delegate/test/Delegate.js | 104 +++++++++++++++++- source/delegate/test/DelegateIntegration.js | 1 + 4 files changed, 163 insertions(+), 16 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 351b21229..9023c010d 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -20,6 +20,9 @@ contract Delegate is IDelegate, Ownable { // Mapping of sender to senderToken to to signerToken to Rule mapping(address => mapping(address => mapping(address => Rule))) public rules; + // Mapping of signer to authorized signatory + mapping(address => address) public authorized; + /** * @notice Contract Constructor */ @@ -35,13 +38,20 @@ contract Delegate is IDelegate, Ownable { * @param _signerAmount uint256 Minimum amount of ERC-20 token the delegate would recieve */ function setRule( + address _senderWallet, address _senderToken, uint256 _senderAmount, address _signerToken, uint256 _signerAmount ) external { - rules[msg.sender][_senderToken][_signerToken] = Rule( - msg.sender, + if (authorized[_senderWallet] != address(0)) { + if (authorized[_senderWallet] != msg.sender) revert SignatoryInvalid(); + } else { + if (_senderWallet != msg.sender) revert SignatoryInvalid(); + } + + rules[_senderWallet][_senderToken][_signerToken] = Rule( + _senderWallet, _senderToken, _senderAmount, _signerToken, @@ -49,7 +59,7 @@ contract Delegate is IDelegate, Ownable { ); emit SetRule( - msg.sender, + _senderWallet, _senderToken, _senderAmount, _signerToken, @@ -63,14 +73,23 @@ contract Delegate is IDelegate, Ownable { * @param _senderToken address Address of an ERC-20 token the sender would send * @param _signerToken address Address of an ERC-20 token the delegate would receive */ - function unsetRule(address _senderToken, address _signerToken) external { - Rule storage rule = rules[msg.sender][_senderToken][_signerToken]; + function unsetRule( + address _senderWallet, + address _senderToken, + address _signerToken + ) external { + if (authorized[_senderWallet] != address(0)) { + if (authorized[_senderWallet] != msg.sender) revert SignatoryInvalid(); + } else { + if (_senderWallet != msg.sender) revert SignatoryInvalid(); + } + Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; rule.senderAmount = 0; - emit UnsetRule(msg.sender, _senderToken, _signerToken); + emit UnsetRule(_senderWallet, _senderToken, _signerToken); } function swap( - address _delegatorWallet, + address _senderWallet, uint256 _nonce, uint256 _expiry, address _signerWallet, @@ -82,7 +101,7 @@ contract Delegate is IDelegate, Ownable { bytes32 _r, bytes32 _s ) external { - Rule storage rule = rules[_delegatorWallet][_senderToken][_signerToken]; + Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; if ( _senderAmount > (_signerAmount * rule.senderAmount) / rule.signerAmount @@ -96,7 +115,7 @@ contract Delegate is IDelegate, Ownable { SafeTransferLib.safeTransferFrom( _senderToken, - _delegatorWallet, + _senderWallet, address(this), _senderAmount ); @@ -116,10 +135,31 @@ contract Delegate is IDelegate, Ownable { _s ); - SafeTransferLib.safeTransfer(_signerToken, _delegatorWallet, _signerAmount); + SafeTransferLib.safeTransfer(_signerToken, _senderWallet, _signerAmount); - rules[_delegatorWallet][_senderToken][_signerToken] + rules[_senderWallet][_senderToken][_signerToken] .senderAmount -= _senderAmount; emit DelegateSwap(_nonce, _signerWallet); } + + /** + * @notice Authorize a signatory + * @param _signatory address Wallet of the signatory to authorize + * @dev Emits an Authorize event + */ + function authorize(address _signatory) external { + if (_signatory == address(0)) revert SignatoryInvalid(); + authorized[msg.sender] = _signatory; + emit Authorize(_signatory, msg.sender); + } + + /** + * @notice Revoke the signatory + * @dev Emits a Revoke event + */ + function revoke() external { + address _tmp = authorized[msg.sender]; + delete authorized[msg.sender]; + emit Revoke(_tmp, msg.sender); + } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index dfcde9123..f6af63ef5 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -15,12 +15,15 @@ interface IDelegate { error InsufficientDelegateAllowance(); error InsufficientSignerAmount(); + error SignatoryInvalid(); error TransferFromFailed(); + event Authorize(address _signatory, address _signer); event DelegateSwap(uint256 _nonce, address _signerWallet); + event Revoke(address _tmp, address _signer); event SetRule( - address _sender, + address _senderWallet, address _senderToken, uint256 _senderAmount, address _signerToken, @@ -30,6 +33,7 @@ interface IDelegate { event UnsetRule(address _signer, address _signerToken, address _senderToken); function setRule( + address _sender, address _senderToken, uint256 _senderAmount, address _signerToken, @@ -50,5 +54,9 @@ interface IDelegate { bytes32 _s ) external; - function unsetRule(address _signerToken, address _senderToken) external; + function unsetRule( + address _sender, + address _signerToken, + address _senderToken + ) external; } diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 1283d8928..68678a5fe 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -5,6 +5,7 @@ const { deployMockContract } = waffle const IERC20 = require('@openzeppelin/contracts/build/contracts/IERC20.json') const SWAP_ERC20 = require('@airswap/swap-erc20/build/contracts/SwapERC20.sol/SwapERC20.json') const { + ADDRESS_ZERO, createOrderERC20, orderERC20ToParams, createOrderERC20Signature, @@ -25,6 +26,7 @@ describe('Delegate Unit', () => { let senderToken let signerToken let delegate + let signatory let snapshotId async function createSignedOrderERC20(params, signatory) { @@ -98,7 +100,7 @@ describe('Delegate Unit', () => { }) before(async () => { - ;[deployer, sender, signer, anyone] = await ethers.getSigners() + ;[deployer, sender, signer, signatory, anyone] = await ethers.getSigners() const swapERC20Factory = await ethers.getContractFactory( SWAP_ERC20.abi, @@ -139,6 +141,7 @@ describe('Delegate Unit', () => { delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, @@ -159,7 +162,51 @@ describe('Delegate Unit', () => { await expect( delegate .connect(sender) - .unsetRule(senderToken.address, signerToken.address) + .unsetRule(sender.address, senderToken.address, signerToken.address) + ) + .to.emit(delegate, 'UnsetRule') + .withArgs(sender.address, senderToken.address, signerToken.address) + }) + + it('a signatory can set a Rule', async () => { + await delegate.connect(sender).authorize(signatory.address) + await expect( + delegate + .connect(signatory) + .setRule( + sender.address, + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT + ) + ) + .to.emit(delegate, 'SetRule') + .withArgs( + sender.address, + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT + ) + }) + + it('a signatory can unset a Rule', async () => { + await delegate.connect(sender).authorize(signatory.address) + await delegate + .connect(signatory) + .setRule( + sender.address, + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT + ) + + await expect( + delegate + .connect(signatory) + .unsetRule(sender.address, senderToken.address, signerToken.address) ) .to.emit(delegate, 'UnsetRule') .withArgs(sender.address, senderToken.address, signerToken.address) @@ -169,6 +216,7 @@ describe('Delegate Unit', () => { await delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, @@ -188,6 +236,7 @@ describe('Delegate Unit', () => { await delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, @@ -202,7 +251,7 @@ describe('Delegate Unit', () => { await delegate .connect(sender) - .unsetRule(senderToken.address, signerToken.address) + .unsetRule(sender.address, senderToken.address, signerToken.address) rule = await delegate.rules( sender.address, @@ -214,11 +263,58 @@ describe('Delegate Unit', () => { }) }) + describe('Test authorization', async () => { + it('test authorized is set', async () => { + await delegate.connect(anyone).authorize(signer.address) + expect(await delegate.authorized(anyone.address)).to.equal(signer.address) + }) + + it('test authorize with zero address', async () => { + await expect( + delegate.connect(deployer).authorize(ADDRESS_ZERO) + ).to.be.revertedWith('SignatoryInvalid') + }) + + it('test revoke', async () => { + await delegate.connect(anyone).revoke() + expect(await delegate.authorized(anyone.address)).to.equal(ADDRESS_ZERO) + }) + }) + describe('Swap', async () => { it('successfully swaps', async () => { await delegate .connect(sender) .setRule( + sender.address, + senderToken.address, + DEFAULT_SENDER_AMOUNT, + signerToken.address, + DEFAULT_SIGNER_AMOUNT + ) + + const order = await createSignedOrderERC20({}, signer) + + await setUpAllowances( + sender.address, + DEFAULT_SENDER_AMOUNT, + signer.address, + DEFAULT_SIGNER_AMOUNT + PROTOCOL_FEE + ) + await setUpBalances(signer.address, sender.address) + + await expect( + delegate.connect(signer).swap(sender.address, ...order) + ).to.emit(delegate, 'DelegateSwap') + }) + + it('successfully swaps with a signatory', async () => { + await delegate.connect(sender).authorize(signatory.address) + + await delegate + .connect(signatory) + .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, @@ -267,6 +363,7 @@ describe('Delegate Unit', () => { await delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT - 1, signerToken.address, @@ -300,6 +397,7 @@ describe('Delegate Unit', () => { await delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, diff --git a/source/delegate/test/DelegateIntegration.js b/source/delegate/test/DelegateIntegration.js index 7a62905c9..04f8f0c93 100644 --- a/source/delegate/test/DelegateIntegration.js +++ b/source/delegate/test/DelegateIntegration.js @@ -95,6 +95,7 @@ describe('Delegate Integration', () => { await delegate .connect(sender) .setRule( + sender.address, senderToken.address, DEFAULT_SENDER_AMOUNT, signerToken.address, From 8784a44ecf5aa86c569573c6d5bd443e9d9fcf22 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 6 May 2024 21:22:59 -0400 Subject: [PATCH 31/43] Wrote delegate deploy script --- source/delegate/contracts/Delegate.sol | 2 +- source/delegate/scripts/deploy.js | 49 +++++++++++++------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 9023c010d..ab0093cba 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -11,7 +11,7 @@ import { SafeTransferLib } from "solady/src/utils/SafeTransferLib.sol"; /** * @title Delegate: Deployable Trading Rules for the AirSwap Network * @notice Supports fungible tokens (ERC-20) - * @dev inherits IDelegate, Ownable uses SafeMath library + * @dev inherits IDelegate, Ownable and uses SafeTransferLib */ contract Delegate is IDelegate, Ownable { // The Swap contract to be used to settle trades diff --git a/source/delegate/scripts/deploy.js b/source/delegate/scripts/deploy.js index abfe460a4..a9464f620 100644 --- a/source/delegate/scripts/deploy.js +++ b/source/delegate/scripts/deploy.js @@ -3,60 +3,59 @@ const fs = require('fs') const prettier = require('prettier') const Confirm = require('prompt-confirm') const { ethers, run } = require('hardhat') -const { chainLabels, chainNames, ChainIds } = require('@airswap/constants') +const swapERC20Deploys = require('@airswap/swap-erc20/deploys.js') +const { ChainIds, chainLabels } = require('@airswap/utils') const { getReceiptUrl } = require('@airswap/utils') -const poolDeploys = require('../deploys.js') -const poolBlocks = require('../deploys-blocks.js') +const delegateDeploys = require('../deploys.js') +const delegateBlocks = require('../deploys-blocks.js') +const { displayDeployerInfo } = require('../../../scripts/deployer-info') async function main() { await run('compile') - const config = await prettier.resolveConfig('../deploys.js') - + const prettierConfig = await prettier.resolveConfig('../deploys.js') const [deployer] = await ethers.getSigners() - const gasPrice = await deployer.getGasPrice() const chainId = await deployer.getChainId() if (chainId === ChainIds.HARDHAT) { console.log('Value for --network flag is required') return } - console.log(`Deployer: ${deployer.address}`) - console.log(`Network: ${chainNames[chainId].toUpperCase()}`) - console.log(`Gas price: ${gasPrice / 10 ** 9} gwei\n`) + await displayDeployerInfo(deployer) - const scale = 10 - const max = 100 + console.log(`swapERC20Contract: ${swapERC20Deploys[chainId]}\n`) const prompt = new Confirm('Proceed to deploy?') if (await prompt.run()) { - const poolFactory = await ethers.getContractFactory('Pool') - const poolContract = await poolFactory.deploy(scale, max, { - gasPrice, - }) + const delegateFactory = await ethers.getContractFactory('Delegate') + const delegateContract = await delegateFactory.deploy( + swapERC20Deploys[chainId] + ) console.log( 'Deploying...', - getReceiptUrl(chainId, poolContract.deployTransaction.hash) + getReceiptUrl(chainId, delegateContract.deployTransaction.hash) ) - await poolContract.deployed() + await delegateContract.deployed() - poolDeploys[chainId] = poolContract.address + delegateDeploys[chainId] = delegateContract.address fs.writeFileSync( './deploys.js', prettier.format( - `module.exports = ${JSON.stringify(poolDeploys, null, '\t')}`, - { ...config, parser: 'babel' } + `module.exports = ${JSON.stringify(delegateDeploys, null, '\t')}`, + { ...prettierConfig, parser: 'babel' } ) ) - poolBlocks[chainId] = ( - await poolContract.deployTransaction.wait() + delegateBlocks[chainId] = ( + await delegateContract.deployTransaction.wait() ).blockNumber fs.writeFileSync( './deploys-blocks.js', prettier.format( - `module.exports = ${JSON.stringify(poolBlocks, null, '\t')}`, - { ...config, parser: 'babel' } + `module.exports = ${JSON.stringify(delegateBlocks, null, '\t')}`, + { ...prettierConfig, parser: 'babel' } ) ) - console.log(`Deployed: ${poolDeploys[chainId]} @ ${poolBlocks[chainId]}`) + console.log( + `Deployed: ${delegateDeploys[chainId]} @ ${delegateBlocks[chainId]}` + ) console.log( `\nVerify with "yarn verify --network ${chainLabels[ From 822f3466c17d8dba2fcaa005c1dec6fe1101b6a7 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Mon, 6 May 2024 21:27:58 -0400 Subject: [PATCH 32/43] Removed unecessary scripts --- source/delegate/scripts/balances.js | 71 --------------------------- source/delegate/scripts/migrate.js | 76 ----------------------------- source/delegate/scripts/verify.js | 9 ++-- 3 files changed, 4 insertions(+), 152 deletions(-) delete mode 100644 source/delegate/scripts/balances.js delete mode 100644 source/delegate/scripts/migrate.js diff --git a/source/delegate/scripts/balances.js b/source/delegate/scripts/balances.js deleted file mode 100644 index f1bd5ad48..000000000 --- a/source/delegate/scripts/balances.js +++ /dev/null @@ -1,71 +0,0 @@ -const { ethers } = require('hardhat') -const { getKnownTokens } = require('@airswap/metadata') -const { chainNames, ChainIds } = require('@airswap/constants') -const BalanceChecker = require('@airswap/balances/build/contracts/BalanceChecker.sol/BalanceChecker.json') -const balancesDeploys = require('@airswap/balances/deploys.js') -const poolDeploys = require('../deploys.js') - -async function main() { - const [account] = await ethers.getSigners() - const chainId = await account.getChainId() - if (chainId === ChainIds.HARDHAT) { - console.log('Value for --network flag is required') - return - } - console.log('Account:', account.address) - console.log('Network:', chainNames[chainId].toUpperCase()) - console.log('\nPool:', poolDeploys[chainId]) - - if (!balancesDeploys[chainId]) { - throw new Error('Unable to check balances on this chain.') - } - - const tokens = (await getKnownTokens(Number(chainId))).tokens - - let count = tokens.length - const addresses = [] - while (count--) { - if (ethers.utils.isAddress(tokens[count].address)) { - addresses.push(tokens[count].address.toLowerCase()) - } - } - - console.log(`\nScanning non-zero balances for ${tokens.length} tokens...\n`) - - const balancesContract = new ethers.Contract( - balancesDeploys[chainId], - BalanceChecker.abi, - account.provider - ) - - const chunk = 750 - let balances = [] - let index = 0 - count = addresses.length - while (index < count) { - balances = balances.concat( - await balancesContract.walletBalances( - poolDeploys[chainId], - addresses.slice(index, index + chunk) - ) - ) - index += chunk - } - - const result = [] - for (let i = 0; i < balances.length; i++) { - if (!balances[i].eq(0)) { - result.push(addresses[i]) - } - } - - console.log('Non-zero balances in', result.length, 'tokens:\n') - console.log(JSON.stringify(result)) -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/delegate/scripts/migrate.js b/source/delegate/scripts/migrate.js deleted file mode 100644 index 0bc28adcb..000000000 --- a/source/delegate/scripts/migrate.js +++ /dev/null @@ -1,76 +0,0 @@ -const Confirm = require('prompt-confirm') -const { ethers } = require('hardhat') -const { chainNames, ChainIds } = require('@airswap/constants') -const { getReceiptUrl } = require('@airswap/utils') - -const { Pool__factory } = require('../typechain/factories/contracts') -const { abi } = require('./migrate-abis/4-1-1.js') -const deploys = require('../deploys.js') - -const CONFIRMATIONS = 2 -const PREVIOUS_POOL = '0xEEcD248D977Fd4D392915b4AdeF8154BA3aE9c02' -const NEW_POOL = '0xbbcec987E4C189FCbAB0a2534c77b3ba89229F11' - -async function main() { - const [account] = await ethers.getSigners() - const chainId = await account.getChainId() - if (chainId === ChainIds.HARDHAT) { - console.log('Value for --network flag is required') - return - } - console.log(`Account: ${account.address}`) - console.log(`Network: ${chainNames[chainId].toUpperCase()}\n`) - console.log(`From-pool: ${PREVIOUS_POOL}`) - console.log(`To-pool: ${NEW_POOL}`) - - const previousPool = new ethers.Contract(PREVIOUS_POOL, abi, account.provider) - const logs = await previousPool.queryFilter(previousPool.filters.UseClaim()) - - if (!logs.length) { - console.log('\n✘ No claim events found on from-pool.\n') - return - } - - const trees = {} - let i = logs.length - while (i--) { - const e = logs[i].decode(logs[i].data) - if (!trees[e.tree]) { - trees[e.tree] = [e.account] - } else { - trees[e.tree].push(e.account) - } - } - - const newPool = Pool__factory.connect(deploys[chainId], account) - const isAdmin = await newPool.admins(account.address) - if (!isAdmin) { - console.log('\n✘ Current account must be admin on to-pool.\n') - return - } - - for (const tree in trees) { - const root = await previousPool.rootsByTree(tree) - console.log('\nTree:', tree) - console.log('Root:', root) - console.log('Claims', trees[tree]) - - const gasPrice = await account.getGasPrice() - console.log(`\nGas price: ${gasPrice / 10 ** 9} gwei\n`) - - const prompt = new Confirm(`Enable and set above as claimed on to-pool?`) - if (await prompt.run()) { - const tx = await newPool.enableAndSetClaimed(tree, root, trees[tree]) - console.log('Updating...', getReceiptUrl(chainId, tx.hash), '\n') - await tx.wait(CONFIRMATIONS) - console.log(`✔ Completed for tree ${tree}`) - } - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error) - process.exit(1) - }) diff --git a/source/delegate/scripts/verify.js b/source/delegate/scripts/verify.js index 4613111b2..70aa73400 100644 --- a/source/delegate/scripts/verify.js +++ b/source/delegate/scripts/verify.js @@ -1,6 +1,7 @@ /* eslint-disable no-console */ const { ethers, run } = require('hardhat') -const poolDeploys = require('../deploys.js') +const delegateDeploys = require('../deploys.js') +const swapERC20Deploys = require('@airswap/swap-erc20/deploys.js') const { chainNames } = require('@airswap/constants') async function main() { @@ -9,13 +10,11 @@ async function main() { console.log(`Deployer: ${deployer.address}`) const chainId = await deployer.getChainId() - const scale = 10 - const max = 100 console.log(`Verifying on ${chainNames[chainId].toUpperCase()}`) await run('verify:verify', { - address: poolDeploys[chainId], - constructorArguments: [scale, max], + address: delegateDeploys[chainId], + constructorArguments: [swapERC20Deploys[chainId]], }) } From d79aa1365ced6cff925c73e98f911a30010e4681 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Tue, 7 May 2024 06:14:43 -0400 Subject: [PATCH 33/43] updated deploy.js.d.ts --- source/delegate/deploys.js.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/delegate/deploys.js.d.ts b/source/delegate/deploys.js.d.ts index 31683c18a..dff926ba4 100644 --- a/source/delegate/deploys.js.d.ts +++ b/source/delegate/deploys.js.d.ts @@ -1,2 +1,2 @@ -declare module '@airswap/pool/deploys.js' -declare module '@airswap/pool/deploys-blocks.js' +declare module '@airswap/delegate/deploys.js' +declare module '@airswap/delegate/deploys-blocks.js' From e95307943b058de12f19e386040641ed3fbb9a7f Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 8 May 2024 06:10:24 -0400 Subject: [PATCH 34/43] Fixed chain name import --- source/delegate/scripts/verify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/delegate/scripts/verify.js b/source/delegate/scripts/verify.js index 70aa73400..93fefecec 100644 --- a/source/delegate/scripts/verify.js +++ b/source/delegate/scripts/verify.js @@ -2,7 +2,7 @@ const { ethers, run } = require('hardhat') const delegateDeploys = require('../deploys.js') const swapERC20Deploys = require('@airswap/swap-erc20/deploys.js') -const { chainNames } = require('@airswap/constants') +const { chainNames } = require('@airswap/utils') async function main() { await run('compile') @@ -11,7 +11,7 @@ async function main() { const chainId = await deployer.getChainId() - console.log(`Verifying on ${chainNames[chainId].toUpperCase()}`) + console.log(`Verifying on ${chainNames[chainId]}`) await run('verify:verify', { address: delegateDeploys[chainId], constructorArguments: [swapERC20Deploys[chainId]], From 7bf35775a9ea01d151e9334f49bdfec8d8ba04d2 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 8 May 2024 06:10:44 -0400 Subject: [PATCH 35/43] Deployed to Sepolia --- source/delegate/deploys-blocks.js | 4 +++- source/delegate/deploys.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/source/delegate/deploys-blocks.js b/source/delegate/deploys-blocks.js index 4ba52ba2c..af0eb7b2f 100644 --- a/source/delegate/deploys-blocks.js +++ b/source/delegate/deploys-blocks.js @@ -1 +1,3 @@ -module.exports = {} +module.exports = { + 11155111: 5860493, +} diff --git a/source/delegate/deploys.js b/source/delegate/deploys.js index 4ba52ba2c..3597b14a4 100644 --- a/source/delegate/deploys.js +++ b/source/delegate/deploys.js @@ -1 +1,3 @@ -module.exports = {} +module.exports = { + 11155111: '0x786D24f6f45f909128278fd384244365Bb0710b7', +} From b08cce0bf48a48e3b21d7f69e0179054ea3774aa Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 8 May 2024 06:17:54 -0400 Subject: [PATCH 36/43] Renamed Signatory to Manager, adjusted tests accordingly --- source/delegate/contracts/Delegate.sol | 18 ++++++------- .../contracts/interfaces/IDelegate.sol | 3 ++- source/delegate/test/Delegate.js | 26 +++++++++---------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index ab0093cba..8f98c2524 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -45,9 +45,9 @@ contract Delegate is IDelegate, Ownable { uint256 _signerAmount ) external { if (authorized[_senderWallet] != address(0)) { - if (authorized[_senderWallet] != msg.sender) revert SignatoryInvalid(); + if (authorized[_senderWallet] != msg.sender) revert SenderInvalid(); } else { - if (_senderWallet != msg.sender) revert SignatoryInvalid(); + if (_senderWallet != msg.sender) revert SenderInvalid(); } rules[_senderWallet][_senderToken][_signerToken] = Rule( @@ -79,9 +79,9 @@ contract Delegate is IDelegate, Ownable { address _signerToken ) external { if (authorized[_senderWallet] != address(0)) { - if (authorized[_senderWallet] != msg.sender) revert SignatoryInvalid(); + if (authorized[_senderWallet] != msg.sender) revert SenderInvalid(); } else { - if (_senderWallet != msg.sender) revert SignatoryInvalid(); + if (_senderWallet != msg.sender) revert SenderInvalid(); } Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; rule.senderAmount = 0; @@ -144,13 +144,13 @@ contract Delegate is IDelegate, Ownable { /** * @notice Authorize a signatory - * @param _signatory address Wallet of the signatory to authorize + * @param _manager address Wallet of the signatory to authorize * @dev Emits an Authorize event */ - function authorize(address _signatory) external { - if (_signatory == address(0)) revert SignatoryInvalid(); - authorized[msg.sender] = _signatory; - emit Authorize(_signatory, msg.sender); + function authorize(address _manager) external { + if (_manager == address(0)) revert ManagerInvalid(); + authorized[msg.sender] = _manager; + emit Authorize(_manager, msg.sender); } /** diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index f6af63ef5..a05c03509 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -15,7 +15,8 @@ interface IDelegate { error InsufficientDelegateAllowance(); error InsufficientSignerAmount(); - error SignatoryInvalid(); + error ManagerInvalid(); + error SenderInvalid(); error TransferFromFailed(); event Authorize(address _signatory, address _signer); diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 68678a5fe..4391d0d68 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -26,7 +26,7 @@ describe('Delegate Unit', () => { let senderToken let signerToken let delegate - let signatory + let manager let snapshotId async function createSignedOrderERC20(params, signatory) { @@ -100,7 +100,7 @@ describe('Delegate Unit', () => { }) before(async () => { - ;[deployer, sender, signer, signatory, anyone] = await ethers.getSigners() + ;[deployer, sender, signer, manager, anyone] = await ethers.getSigners() const swapERC20Factory = await ethers.getContractFactory( SWAP_ERC20.abi, @@ -168,11 +168,11 @@ describe('Delegate Unit', () => { .withArgs(sender.address, senderToken.address, signerToken.address) }) - it('a signatory can set a Rule', async () => { - await delegate.connect(sender).authorize(signatory.address) + it('a manager can set a Rule', async () => { + await delegate.connect(sender).authorize(manager.address) await expect( delegate - .connect(signatory) + .connect(manager) .setRule( sender.address, senderToken.address, @@ -191,10 +191,10 @@ describe('Delegate Unit', () => { ) }) - it('a signatory can unset a Rule', async () => { - await delegate.connect(sender).authorize(signatory.address) + it('a manager can unset a Rule', async () => { + await delegate.connect(sender).authorize(manager.address) await delegate - .connect(signatory) + .connect(manager) .setRule( sender.address, senderToken.address, @@ -205,7 +205,7 @@ describe('Delegate Unit', () => { await expect( delegate - .connect(signatory) + .connect(manager) .unsetRule(sender.address, senderToken.address, signerToken.address) ) .to.emit(delegate, 'UnsetRule') @@ -272,7 +272,7 @@ describe('Delegate Unit', () => { it('test authorize with zero address', async () => { await expect( delegate.connect(deployer).authorize(ADDRESS_ZERO) - ).to.be.revertedWith('SignatoryInvalid') + ).to.be.revertedWith('ManagerInvalid') }) it('test revoke', async () => { @@ -308,11 +308,11 @@ describe('Delegate Unit', () => { ).to.emit(delegate, 'DelegateSwap') }) - it('successfully swaps with a signatory', async () => { - await delegate.connect(sender).authorize(signatory.address) + it('successfully swaps with a manager', async () => { + await delegate.connect(sender).authorize(manager.address) await delegate - .connect(signatory) + .connect(manager) .setRule( sender.address, senderToken.address, From 5b76c8824cf89c6b5982e7d81ab138fe907bf4be Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Wed, 8 May 2024 06:19:13 -0400 Subject: [PATCH 37/43] Deployed to Sepolia --- source/delegate/deploys-blocks.js | 2 +- source/delegate/deploys.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/delegate/deploys-blocks.js b/source/delegate/deploys-blocks.js index af0eb7b2f..f69b9ec49 100644 --- a/source/delegate/deploys-blocks.js +++ b/source/delegate/deploys-blocks.js @@ -1,3 +1,3 @@ module.exports = { - 11155111: 5860493, + 11155111: 5860563, } diff --git a/source/delegate/deploys.js b/source/delegate/deploys.js index 3597b14a4..f0c7d6a1a 100644 --- a/source/delegate/deploys.js +++ b/source/delegate/deploys.js @@ -1,3 +1,3 @@ module.exports = { - 11155111: '0x786D24f6f45f909128278fd384244365Bb0710b7', + 11155111: '0x4f4F5517Fd344A4abe84C91D8F80111Fb821B531', } From c20ee770cb7ae65d792d893fc3aeb7156f92a0d0 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Fri, 10 May 2024 19:11:18 -0400 Subject: [PATCH 38/43] prettier --- source/delegate/scripts/migrate-abis/4-1-1.js | 416 ------------------ tools/utils/src/abis/ERC1155.json | 334 -------------- tools/utils/src/abis/ERC165.json | 30 -- tools/utils/src/abis/ERC20.json | 297 ------------- tools/utils/src/abis/ERC721.json | 357 --------------- tools/utils/src/metadata.ts | 8 +- tools/utils/src/swap-erc20.ts | 2 +- 7 files changed, 5 insertions(+), 1439 deletions(-) delete mode 100644 source/delegate/scripts/migrate-abis/4-1-1.js delete mode 100644 tools/utils/src/abis/ERC1155.json delete mode 100644 tools/utils/src/abis/ERC165.json delete mode 100644 tools/utils/src/abis/ERC20.json delete mode 100644 tools/utils/src/abis/ERC721.json diff --git a/source/delegate/scripts/migrate-abis/4-1-1.js b/source/delegate/scripts/migrate-abis/4-1-1.js deleted file mode 100644 index 27293305e..000000000 --- a/source/delegate/scripts/migrate-abis/4-1-1.js +++ /dev/null @@ -1,416 +0,0 @@ -module.exports = { - abi: [ - { - inputs: [ - { internalType: 'uint256', name: '_scale', type: 'uint256' }, - { internalType: 'uint256', name: '_max', type: 'uint256' }, - ], - stateMutability: 'nonpayable', - type: 'constructor', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'AddressInvalid', - type: 'error', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'AdminNotSet', - type: 'error', - }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'AmountInsufficient', - type: 'error', - }, - { inputs: [], name: 'ClaimAlreadyUsed', type: 'error' }, - { inputs: [], name: 'ClaimsNotProvided', type: 'error' }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'MaxTooHigh', - type: 'error', - }, - { - inputs: [ - { internalType: 'bytes32', name: '', type: 'bytes32' }, - { internalType: 'bytes32', name: '', type: 'bytes32' }, - ], - name: 'ProofInvalid', - type: 'error', - }, - { - inputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - name: 'ScaleTooHigh', - type: 'error', - }, - { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - name: 'TreeNotEnabled', - type: 'error', - }, - { inputs: [], name: 'Unauthorized', type: 'error' }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address[]', - name: 'tokens', - type: 'address[]', - }, - { - indexed: false, - internalType: 'address', - name: 'dest', - type: 'address', - }, - ], - name: 'DrainTo', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'bytes32', - name: 'tree', - type: 'bytes32', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'root', - type: 'bytes32', - }, - ], - name: 'Enable', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'previousOwner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'newOwner', - type: 'address', - }, - ], - name: 'OwnershipTransferStarted', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'address', - name: 'previousOwner', - type: 'address', - }, - { - indexed: true, - internalType: 'address', - name: 'newOwner', - type: 'address', - }, - ], - name: 'OwnershipTransferred', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'admin', - type: 'address', - }, - ], - name: 'SetAdmin', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: 'max', - type: 'uint256', - }, - ], - name: 'SetMax', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'uint256', - name: 'scale', - type: 'uint256', - }, - ], - name: 'SetScale', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'admin', - type: 'address', - }, - ], - name: 'UnsetAdmin', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: false, - internalType: 'bytes32', - name: 'tree', - type: 'bytes32', - }, - ], - name: 'UseClaim', - type: 'event', - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: 'address', - name: 'account', - type: 'address', - }, - { - indexed: false, - internalType: 'address', - name: 'recipient', - type: 'address', - }, - { - indexed: false, - internalType: 'address', - name: 'token', - type: 'address', - }, - { - indexed: false, - internalType: 'uint256', - name: 'amount', - type: 'uint256', - }, - ], - name: 'Withdraw', - type: 'event', - }, - { - inputs: [], - name: 'acceptOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'admins', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'uint256', name: '_value', type: 'uint256' }, - { internalType: 'address', name: '_token', type: 'address' }, - ], - name: 'calculate', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '', type: 'bytes32' }, - { internalType: 'address', name: '', type: 'address' }, - ], - name: 'claimed', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { internalType: 'address[]', name: '_tokens', type: 'address[]' }, - { internalType: 'address', name: '_dest', type: 'address' }, - ], - name: 'drainTo', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - ], - name: 'enable', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'bytes32', name: '_tree', type: 'bytes32' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - { internalType: 'address[]', name: '_accounts', type: 'address[]' }, - ], - name: 'enableAndSetClaimed', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: '_account', type: 'address' }, - { internalType: 'bytes32[]', name: '_trees', type: 'bytes32[]' }, - ], - name: 'getStatus', - outputs: [{ internalType: 'bool[]', name: '', type: 'bool[]' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'max', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'owner', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'pendingOwner', - outputs: [{ internalType: 'address', name: '', type: 'address' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'renounceOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - name: 'rootsByTree', - outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'scale', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], - name: 'setAdmin', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'uint256', name: '_max', type: 'uint256' }], - name: 'setMax', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'uint256', name: '_scale', type: 'uint256' }], - name: 'setScale', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: 'newOwner', type: 'address' }], - name: 'transferOwnership', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [{ internalType: 'address', name: '_admin', type: 'address' }], - name: 'unsetAdmin', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { internalType: 'address', name: '_claimant', type: 'address' }, - { internalType: 'bytes32', name: '_root', type: 'bytes32' }, - { internalType: 'uint256', name: '_value', type: 'uint256' }, - { internalType: 'bytes32[]', name: '_proof', type: 'bytes32[]' }, - ], - name: 'verify', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'pure', - type: 'function', - }, - { - inputs: [ - { - components: [ - { internalType: 'bytes32', name: 'tree', type: 'bytes32' }, - { internalType: 'uint256', name: 'value', type: 'uint256' }, - { internalType: 'bytes32[]', name: 'proof', type: 'bytes32[]' }, - ], - internalType: 'struct IPool.Claim[]', - name: '_claims', - type: 'tuple[]', - }, - { internalType: 'address', name: '_token', type: 'address' }, - { internalType: 'uint256', name: '_minimum', type: 'uint256' }, - { internalType: 'address', name: '_recipient', type: 'address' }, - ], - name: 'withdraw', - outputs: [{ internalType: 'uint256', name: '_amount', type: 'uint256' }], - stateMutability: 'nonpayable', - type: 'function', - }, - ], -} diff --git a/tools/utils/src/abis/ERC1155.json b/tools/utils/src/abis/ERC1155.json deleted file mode 100644 index 8486b3605..000000000 --- a/tools/utils/src/abis/ERC1155.json +++ /dev/null @@ -1,334 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ERC1155", - "sourceName": "contracts/token/ERC1155/ERC1155.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "string", - "name": "uri_", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "indexed": false, - "internalType": "uint256[]", - "name": "values", - "type": "uint256[]" - } - ], - "name": "TransferBatch", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "TransferSingle", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "string", - "name": "value", - "type": "string" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "URI", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address[]", - "name": "accounts", - "type": "address[]" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - } - ], - "name": "balanceOfBatch", - "outputs": [ - { - "internalType": "uint256[]", - "name": "", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256[]", - "name": "ids", - "type": "uint256[]" - }, - { - "internalType": "uint256[]", - "name": "amounts", - "type": "uint256[]" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeBatchTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "id", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "name": "uri", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x60806040523480156200001157600080fd5b50604051620015cb380380620015cb83398101604081905262000034916200011b565b6200003f8162000046565b5062000233565b80516200005b9060029060208401906200005f565b5050565b8280546200006d90620001f7565b90600052602060002090601f016020900481019282620000915760008555620000dc565b82601f10620000ac57805160ff1916838001178555620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b50620000ea929150620000ee565b5090565b5b80821115620000ea5760008155600101620000ef565b634e487b7160e01b600052604160045260246000fd5b600060208083850312156200012f57600080fd5b82516001600160401b03808211156200014757600080fd5b818501915085601f8301126200015c57600080fd5b81518181111562000171576200017162000105565b604051601f8201601f19908116603f011681019083821181831017156200019c576200019c62000105565b816040528281528886848701011115620001b557600080fd5b600093505b82841015620001d95784840186015181850187015292850192620001ba565b82841115620001eb5760008684830101525b98975050505050505050565b600181811c908216806200020c57607f821691505b6020821081036200022d57634e487b7160e01b600052602260045260246000fd5b50919050565b61138880620002436000396000f3fe608060405234801561001057600080fd5b50600436106100875760003560e01c80634e1273f41161005b5780634e1273f41461010a578063a22cb4651461012a578063e985e9c51461013d578063f242432a1461017957600080fd5b8062fdd58e1461008c57806301ffc9a7146100b25780630e89341c146100d55780632eb2c2d6146100f5575b600080fd5b61009f61009a366004610b3f565b61018c565b6040519081526020015b60405180910390f35b6100c56100c0366004610b82565b610222565b60405190151581526020016100a9565b6100e86100e3366004610ba6565b610274565b6040516100a99190610c0c565b610108610103366004610d6b565b610308565b005b61011d610118366004610e15565b610354565b6040516100a99190610f1b565b610108610138366004610f2e565b61047e565b6100c561014b366004610f6a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b610108610187366004610f9d565b61048d565b60006001600160a01b0383166101fc5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000908152602081815260408083206001600160a01b03949094168352929052205490565b60006001600160e01b03198216636cdb3d1360e11b148061025357506001600160e01b031982166303a24d0760e21b145b8061026e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606002805461028390611002565b80601f01602080910402602001604051908101604052809291908181526020018280546102af90611002565b80156102fc5780601f106102d1576101008083540402835291602001916102fc565b820191906000526020600020905b8154815290600101906020018083116102df57829003601f168201915b50505050509050919050565b6001600160a01b0385163314806103245750610324853361014b565b6103405760405162461bcd60e51b81526004016101f39061103c565b61034d85858585856104d2565b5050505050565b606081518351146103b95760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016101f3565b6000835167ffffffffffffffff8111156103d5576103d5610c1f565b6040519080825280602002602001820160405280156103fe578160200160208202803683370190505b50905060005b8451811015610476576104498582815181106104225761042261108a565b602002602001015185838151811061043c5761043c61108a565b602002602001015161018c565b82828151811061045b5761045b61108a565b602090810291909101015261046f816110b6565b9050610404565b509392505050565b6104893383836106af565b5050565b6001600160a01b0385163314806104a957506104a9853361014b565b6104c55760405162461bcd60e51b81526004016101f39061103c565b61034d858585858561078f565b81518351146105345760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b60648201526084016101f3565b6001600160a01b03841661055a5760405162461bcd60e51b81526004016101f3906110cf565b3360005b845181101561064157600085828151811061057b5761057b61108a565b6020026020010151905060008583815181106105995761059961108a565b602090810291909101810151600084815280835260408082206001600160a01b038e1683529093529190912054909150818110156105e95760405162461bcd60e51b81526004016101f390611114565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b1682528120805484929061062690849061115e565b925050819055505050508061063a906110b6565b905061055e565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051610691929190611176565b60405180910390a46106a78187878787876108b9565b505050505050565b816001600160a01b0316836001600160a01b0316036107225760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016101f3565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166107b55760405162461bcd60e51b81526004016101f3906110cf565b3360006107c185610a1d565b905060006107ce85610a1d565b90506000868152602081815260408083206001600160a01b038c168452909152902054858110156108115760405162461bcd60e51b81526004016101f390611114565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061084e90849061115e565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46108ae848a8a8a8a8a610a68565b505050505050505050565b6001600160a01b0384163b156106a75760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906108fd90899089908890889088906004016111a4565b6020604051808303816000875af1925050508015610938575060408051601f3d908101601f1916820190925261093591810190611202565b60015b6109e45761094461121f565b806308c379a00361097d575061095861123b565b80610963575061097f565b8060405162461bcd60e51b81526004016101f39190610c0c565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016101f3565b6001600160e01b0319811663bc197c8160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b50505050505050565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110610a5757610a5761108a565b602090810291909101015292915050565b6001600160a01b0384163b156106a75760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190610aac908990899088908890889060040161130d565b6020604051808303816000875af1925050508015610ae7575060408051601f3d908101601f19168201909252610ae491810190611202565b60015b610af35761094461121f565b6001600160e01b0319811663f23a6e6160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b80356001600160a01b0381168114610b3a57600080fd5b919050565b60008060408385031215610b5257600080fd5b610b5b83610b23565b946020939093013593505050565b6001600160e01b031981168114610b7f57600080fd5b50565b600060208284031215610b9457600080fd5b8135610b9f81610b69565b9392505050565b600060208284031215610bb857600080fd5b5035919050565b6000815180845260005b81811015610be557602081850181015186830182015201610bc9565b81811115610bf7576000602083870101525b50601f01601f19169290920160200192915050565b602081526000610b9f6020830184610bbf565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715610c5b57610c5b610c1f565b6040525050565b600067ffffffffffffffff821115610c7c57610c7c610c1f565b5060051b60200190565b600082601f830112610c9757600080fd5b81356020610ca482610c62565b604051610cb18282610c35565b83815260059390931b8501820192828101915086841115610cd157600080fd5b8286015b84811015610cec5780358352918301918301610cd5565b509695505050505050565b600082601f830112610d0857600080fd5b813567ffffffffffffffff811115610d2257610d22610c1f565b604051610d39601f8301601f191660200182610c35565b818152846020838601011115610d4e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610d8357600080fd5b610d8c86610b23565b9450610d9a60208701610b23565b9350604086013567ffffffffffffffff80821115610db757600080fd5b610dc389838a01610c86565b94506060880135915080821115610dd957600080fd5b610de589838a01610c86565b93506080880135915080821115610dfb57600080fd5b50610e0888828901610cf7565b9150509295509295909350565b60008060408385031215610e2857600080fd5b823567ffffffffffffffff80821115610e4057600080fd5b818501915085601f830112610e5457600080fd5b81356020610e6182610c62565b604051610e6e8282610c35565b83815260059390931b8501820192828101915089841115610e8e57600080fd5b948201945b83861015610eb357610ea486610b23565b82529482019490820190610e93565b96505086013592505080821115610ec957600080fd5b50610ed685828601610c86565b9150509250929050565b600081518084526020808501945080840160005b83811015610f1057815187529582019590820190600101610ef4565b509495945050505050565b602081526000610b9f6020830184610ee0565b60008060408385031215610f4157600080fd5b610f4a83610b23565b915060208301358015158114610f5f57600080fd5b809150509250929050565b60008060408385031215610f7d57600080fd5b610f8683610b23565b9150610f9460208401610b23565b90509250929050565b600080600080600060a08688031215610fb557600080fd5b610fbe86610b23565b9450610fcc60208701610b23565b93506040860135925060608601359150608086013567ffffffffffffffff811115610ff657600080fd5b610e0888828901610cf7565b600181811c9082168061101657607f821691505b60208210810361103657634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016110c8576110c86110a0565b5060010190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60008219821115611171576111716110a0565b500190565b6040815260006111896040830185610ee0565b828103602084015261119b8185610ee0565b95945050505050565b6001600160a01b0386811682528516602082015260a0604082018190526000906111d090830186610ee0565b82810360608401526111e28186610ee0565b905082810360808401526111f68185610bbf565b98975050505050505050565b60006020828403121561121457600080fd5b8151610b9f81610b69565b600060033d11156112385760046000803e5060005160e01c5b90565b600060443d10156112495790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561127957505050505090565b82850191508151818111156112915750505050505090565b843d87010160208285010111156112ab5750505050505090565b6112ba60208286010187610c35565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061134790830184610bbf565b97965050505050505056fea26469706673582212202f31a5ed9841bb19ea3048d1ee82155c8ba6a9a7cec7bee194b0e339d260147f64736f6c634300080d0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100875760003560e01c80634e1273f41161005b5780634e1273f41461010a578063a22cb4651461012a578063e985e9c51461013d578063f242432a1461017957600080fd5b8062fdd58e1461008c57806301ffc9a7146100b25780630e89341c146100d55780632eb2c2d6146100f5575b600080fd5b61009f61009a366004610b3f565b61018c565b6040519081526020015b60405180910390f35b6100c56100c0366004610b82565b610222565b60405190151581526020016100a9565b6100e86100e3366004610ba6565b610274565b6040516100a99190610c0c565b610108610103366004610d6b565b610308565b005b61011d610118366004610e15565b610354565b6040516100a99190610f1b565b610108610138366004610f2e565b61047e565b6100c561014b366004610f6a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b610108610187366004610f9d565b61048d565b60006001600160a01b0383166101fc5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000908152602081815260408083206001600160a01b03949094168352929052205490565b60006001600160e01b03198216636cdb3d1360e11b148061025357506001600160e01b031982166303a24d0760e21b145b8061026e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606002805461028390611002565b80601f01602080910402602001604051908101604052809291908181526020018280546102af90611002565b80156102fc5780601f106102d1576101008083540402835291602001916102fc565b820191906000526020600020905b8154815290600101906020018083116102df57829003601f168201915b50505050509050919050565b6001600160a01b0385163314806103245750610324853361014b565b6103405760405162461bcd60e51b81526004016101f39061103c565b61034d85858585856104d2565b5050505050565b606081518351146103b95760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016101f3565b6000835167ffffffffffffffff8111156103d5576103d5610c1f565b6040519080825280602002602001820160405280156103fe578160200160208202803683370190505b50905060005b8451811015610476576104498582815181106104225761042261108a565b602002602001015185838151811061043c5761043c61108a565b602002602001015161018c565b82828151811061045b5761045b61108a565b602090810291909101015261046f816110b6565b9050610404565b509392505050565b6104893383836106af565b5050565b6001600160a01b0385163314806104a957506104a9853361014b565b6104c55760405162461bcd60e51b81526004016101f39061103c565b61034d858585858561078f565b81518351146105345760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b60648201526084016101f3565b6001600160a01b03841661055a5760405162461bcd60e51b81526004016101f3906110cf565b3360005b845181101561064157600085828151811061057b5761057b61108a565b6020026020010151905060008583815181106105995761059961108a565b602090810291909101810151600084815280835260408082206001600160a01b038e1683529093529190912054909150818110156105e95760405162461bcd60e51b81526004016101f390611114565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b1682528120805484929061062690849061115e565b925050819055505050508061063a906110b6565b905061055e565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051610691929190611176565b60405180910390a46106a78187878787876108b9565b505050505050565b816001600160a01b0316836001600160a01b0316036107225760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016101f3565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166107b55760405162461bcd60e51b81526004016101f3906110cf565b3360006107c185610a1d565b905060006107ce85610a1d565b90506000868152602081815260408083206001600160a01b038c168452909152902054858110156108115760405162461bcd60e51b81526004016101f390611114565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061084e90849061115e565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46108ae848a8a8a8a8a610a68565b505050505050505050565b6001600160a01b0384163b156106a75760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906108fd90899089908890889088906004016111a4565b6020604051808303816000875af1925050508015610938575060408051601f3d908101601f1916820190925261093591810190611202565b60015b6109e45761094461121f565b806308c379a00361097d575061095861123b565b80610963575061097f565b8060405162461bcd60e51b81526004016101f39190610c0c565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016101f3565b6001600160e01b0319811663bc197c8160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b50505050505050565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110610a5757610a5761108a565b602090810291909101015292915050565b6001600160a01b0384163b156106a75760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190610aac908990899088908890889060040161130d565b6020604051808303816000875af1925050508015610ae7575060408051601f3d908101601f19168201909252610ae491810190611202565b60015b610af35761094461121f565b6001600160e01b0319811663f23a6e6160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b80356001600160a01b0381168114610b3a57600080fd5b919050565b60008060408385031215610b5257600080fd5b610b5b83610b23565b946020939093013593505050565b6001600160e01b031981168114610b7f57600080fd5b50565b600060208284031215610b9457600080fd5b8135610b9f81610b69565b9392505050565b600060208284031215610bb857600080fd5b5035919050565b6000815180845260005b81811015610be557602081850181015186830182015201610bc9565b81811115610bf7576000602083870101525b50601f01601f19169290920160200192915050565b602081526000610b9f6020830184610bbf565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715610c5b57610c5b610c1f565b6040525050565b600067ffffffffffffffff821115610c7c57610c7c610c1f565b5060051b60200190565b600082601f830112610c9757600080fd5b81356020610ca482610c62565b604051610cb18282610c35565b83815260059390931b8501820192828101915086841115610cd157600080fd5b8286015b84811015610cec5780358352918301918301610cd5565b509695505050505050565b600082601f830112610d0857600080fd5b813567ffffffffffffffff811115610d2257610d22610c1f565b604051610d39601f8301601f191660200182610c35565b818152846020838601011115610d4e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610d8357600080fd5b610d8c86610b23565b9450610d9a60208701610b23565b9350604086013567ffffffffffffffff80821115610db757600080fd5b610dc389838a01610c86565b94506060880135915080821115610dd957600080fd5b610de589838a01610c86565b93506080880135915080821115610dfb57600080fd5b50610e0888828901610cf7565b9150509295509295909350565b60008060408385031215610e2857600080fd5b823567ffffffffffffffff80821115610e4057600080fd5b818501915085601f830112610e5457600080fd5b81356020610e6182610c62565b604051610e6e8282610c35565b83815260059390931b8501820192828101915089841115610e8e57600080fd5b948201945b83861015610eb357610ea486610b23565b82529482019490820190610e93565b96505086013592505080821115610ec957600080fd5b50610ed685828601610c86565b9150509250929050565b600081518084526020808501945080840160005b83811015610f1057815187529582019590820190600101610ef4565b509495945050505050565b602081526000610b9f6020830184610ee0565b60008060408385031215610f4157600080fd5b610f4a83610b23565b915060208301358015158114610f5f57600080fd5b809150509250929050565b60008060408385031215610f7d57600080fd5b610f8683610b23565b9150610f9460208401610b23565b90509250929050565b600080600080600060a08688031215610fb557600080fd5b610fbe86610b23565b9450610fcc60208701610b23565b93506040860135925060608601359150608086013567ffffffffffffffff811115610ff657600080fd5b610e0888828901610cf7565b600181811c9082168061101657607f821691505b60208210810361103657634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016110c8576110c86110a0565b5060010190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60008219821115611171576111716110a0565b500190565b6040815260006111896040830185610ee0565b828103602084015261119b8185610ee0565b95945050505050565b6001600160a01b0386811682528516602082015260a0604082018190526000906111d090830186610ee0565b82810360608401526111e28186610ee0565b905082810360808401526111f68185610bbf565b98975050505050505050565b60006020828403121561121457600080fd5b8151610b9f81610b69565b600060033d11156112385760046000803e5060005160e01c5b90565b600060443d10156112495790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561127957505050505090565b82850191508151818111156112915750505050505090565b843d87010160208285010111156112ab5750505050505090565b6112ba60208286010187610c35565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061134790830184610bbf565b97965050505050505056fea26469706673582212202f31a5ed9841bb19ea3048d1ee82155c8ba6a9a7cec7bee194b0e339d260147f64736f6c634300080d0033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/tools/utils/src/abis/ERC165.json b/tools/utils/src/abis/ERC165.json deleted file mode 100644 index e1bfd6b4f..000000000 --- a/tools/utils/src/abis/ERC165.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ERC165", - "sourceName": "contracts/utils/introspection/ERC165.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - } - ], - "bytecode": "0x", - "deployedBytecode": "0x", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/tools/utils/src/abis/ERC20.json b/tools/utils/src/abis/ERC20.json deleted file mode 100644 index e1f5a7ac6..000000000 --- a/tools/utils/src/abis/ERC20.json +++ /dev/null @@ -1,297 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ERC20", - "sourceName": "contracts/token/ERC20/ERC20.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "string", - "name": "name_", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol_", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "subtractedValue", - "type": "uint256" - } - ], - "name": "decreaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "addedValue", - "type": "uint256" - } - ], - "name": "increaseAllowance", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x60806040523480156200001157600080fd5b5060405162000aed38038062000aed8339810160408190526200003491620001db565b81516200004990600390602085019062000068565b5080516200005f90600490602084019062000068565b50505062000281565b828054620000769062000245565b90600052602060002090601f0160209004810192826200009a5760008555620000e5565b82601f10620000b557805160ff1916838001178555620000e5565b82800160010185558215620000e5579182015b82811115620000e5578251825591602001919060010190620000c8565b50620000f3929150620000f7565b5090565b5b80821115620000f35760008155600101620000f8565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013657600080fd5b81516001600160401b03808211156200015357620001536200010e565b604051601f8301601f19908116603f011681019082821181831017156200017e576200017e6200010e565b816040528381526020925086838588010111156200019b57600080fd5b600091505b83821015620001bf5785820183015181830184015290820190620001a0565b83821115620001d15760008385830101525b9695505050505050565b60008060408385031215620001ef57600080fd5b82516001600160401b03808211156200020757600080fd5b620002158683870162000124565b935060208501519150808211156200022c57600080fd5b506200023b8582860162000124565b9150509250929050565b600181811c908216806200025a57607f821691505b6020821081036200027b57634e487b7160e01b600052602260045260246000fd5b50919050565b61085c80620002916000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069a565b60405180910390f35b6100df6100da36600461070b565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610735565b61024a565b604051601281526020016100c3565b6100df61013136600461070b565b61026e565b6100f3610144366004610771565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df61017536600461070b565b61029f565b6100df61018836600461070b565b61031f565b6100f361019b366004610793565b61032d565b6060600380546101af906107c6565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c6565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b9190610800565b610358565b6060600480546101af906107c6565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f0565b600060208083528351808285015260005b818110156106c7578581018301518582016040015282016106ab565b818111156106d9576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461070657600080fd5b919050565b6000806040838503121561071e57600080fd5b610727836106ef565b946020939093013593505050565b60008060006060848603121561074a57600080fd5b610753846106ef565b9250610761602085016106ef565b9150604084013590509250925092565b60006020828403121561078357600080fd5b61078c826106ef565b9392505050565b600080604083850312156107a657600080fd5b6107af836106ef565b91506107bd602084016106ef565b90509250929050565b600181811c908216806107da57607f821691505b6020821081036107fa57634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561082157634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212208ea3918651cefe661c47475f544a91c156156839b9d304a33b7b43e599a312a064736f6c634300080d0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069a565b60405180910390f35b6100df6100da36600461070b565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610735565b61024a565b604051601281526020016100c3565b6100df61013136600461070b565b61026e565b6100f3610144366004610771565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df61017536600461070b565b61029f565b6100df61018836600461070b565b61031f565b6100f361019b366004610793565b61032d565b6060600380546101af906107c6565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c6565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b9190610800565b610358565b6060600480546101af906107c6565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f0565b600060208083528351808285015260005b818110156106c7578581018301518582016040015282016106ab565b818111156106d9576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461070657600080fd5b919050565b6000806040838503121561071e57600080fd5b610727836106ef565b946020939093013593505050565b60008060006060848603121561074a57600080fd5b610753846106ef565b9250610761602085016106ef565b9150604084013590509250925092565b60006020828403121561078357600080fd5b61078c826106ef565b9392505050565b600080604083850312156107a657600080fd5b6107af836106ef565b91506107bd602084016106ef565b90509250929050565b600181811c908216806107da57607f821691505b6020821081036107fa57634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561082157634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212208ea3918651cefe661c47475f544a91c156156839b9d304a33b7b43e599a312a064736f6c634300080d0033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/tools/utils/src/abis/ERC721.json b/tools/utils/src/abis/ERC721.json deleted file mode 100644 index 789fdef4b..000000000 --- a/tools/utils/src/abis/ERC721.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "_format": "hh-sol-artifact-1", - "contractName": "ERC721", - "sourceName": "contracts/token/ERC721/ERC721.sol", - "abi": [ - { - "inputs": [ - { - "internalType": "string", - "name": "name_", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol_", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "approved", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "indexed": false, - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "getApproved", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "operator", - "type": "address" - } - ], - "name": "isApprovedForAll", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "ownerOf", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "safeTransferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "operator", - "type": "address" - }, - { - "internalType": "bool", - "name": "approved", - "type": "bool" - } - ], - "name": "setApprovalForAll", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "interfaceId", - "type": "bytes4" - } - ], - "name": "supportsInterface", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "tokenURI", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "tokenId", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } - ], - "bytecode": "0x60806040523480156200001157600080fd5b506040516200138c3803806200138c8339810160408190526200003491620001db565b81516200004990600090602085019062000068565b5080516200005f90600190602084019062000068565b50505062000281565b828054620000769062000245565b90600052602060002090601f0160209004810192826200009a5760008555620000e5565b82601f10620000b557805160ff1916838001178555620000e5565b82800160010185558215620000e5579182015b82811115620000e5578251825591602001919060010190620000c8565b50620000f3929150620000f7565b5090565b5b80821115620000f35760008155600101620000f8565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013657600080fd5b81516001600160401b03808211156200015357620001536200010e565b604051601f8301601f19908116603f011681019082821181831017156200017e576200017e6200010e565b816040528381526020925086838588010111156200019b57600080fd5b600091505b83821015620001bf5785820183015181830184015290820190620001a0565b83821115620001d15760008385830101525b9695505050505050565b60008060408385031215620001ef57600080fd5b82516001600160401b03808211156200020757600080fd5b620002158683870162000124565b935060208501519150808211156200022c57600080fd5b506200023b8582860162000124565b9150509250929050565b600181811c908216806200025a57607f821691505b6020821081036200027b57634e487b7160e01b600052602260045260246000fd5b50919050565b6110fb80620002916000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636352211e1161008c578063a22cb46511610066578063a22cb465146101b3578063b88d4fde146101c6578063c87b56dd146101d9578063e985e9c5146101ec57600080fd5b80636352211e1461017757806370a082311461018a57806395d89b41146101ab57600080fd5b806301ffc9a7146100d457806306fdde03146100fc578063081812fc14610111578063095ea7b31461013c57806323b872dd1461015157806342842e0e14610164575b600080fd5b6100e76100e2366004610c7f565b610228565b60405190151581526020015b60405180910390f35b61010461027a565b6040516100f39190610cf4565b61012461011f366004610d07565b61030c565b6040516001600160a01b0390911681526020016100f3565b61014f61014a366004610d3c565b610333565b005b61014f61015f366004610d66565b61044d565b61014f610172366004610d66565b61047e565b610124610185366004610d07565b610499565b61019d610198366004610da2565b6104f9565b6040519081526020016100f3565b61010461057f565b61014f6101c1366004610dbd565b61058e565b61014f6101d4366004610e0f565b61059d565b6101046101e7366004610d07565b6105d5565b6100e76101fa366004610eeb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160e01b031982166380ac58cd60e01b148061025957506001600160e01b03198216635b5e139f60e01b145b8061027457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461028990610f1e565b80601f01602080910402602001604051908101604052809291908181526020018280546102b590610f1e565b80156103025780601f106102d757610100808354040283529160200191610302565b820191906000526020600020905b8154815290600101906020018083116102e557829003601f168201915b5050505050905090565b600061031782610649565b506000908152600460205260409020546001600160a01b031690565b600061033e82610499565b9050806001600160a01b0316836001600160a01b0316036103b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806103cc57506103cc81336101fa565b61043e5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016103a7565b61044883836106ab565b505050565b6104573382610719565b6104735760405162461bcd60e51b81526004016103a790610f58565b610448838383610798565b6104488383836040518060200160405280600081525061059d565b6000818152600260205260408120546001600160a01b0316806102745760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b60006001600160a01b0382166105635760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016103a7565b506001600160a01b031660009081526003602052604090205490565b60606001805461028990610f1e565b6105993383836108fc565b5050565b6105a73383610719565b6105c35760405162461bcd60e51b81526004016103a790610f58565b6105cf848484846109ca565b50505050565b60606105e082610649565b60006105f760408051602081019091526000815290565b905060008151116106175760405180602001604052806000815250610642565b80610621846109fd565b604051602001610632929190610fa5565b6040516020818303038152906040525b9392505050565b6000818152600260205260409020546001600160a01b03166106a85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906106e082610499565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061072583610499565b9050806001600160a01b0316846001600160a01b0316148061076c57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806107905750836001600160a01b03166107858461030c565b6001600160a01b0316145b949350505050565b826001600160a01b03166107ab82610499565b6001600160a01b0316146107d15760405162461bcd60e51b81526004016103a790610fd4565b6001600160a01b0382166108335760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016103a7565b826001600160a01b031661084682610499565b6001600160a01b03161461086c5760405162461bcd60e51b81526004016103a790610fd4565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b816001600160a01b0316836001600160a01b03160361095d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016103a7565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6109d5848484610798565b6109e184848484610a90565b6105cf5760405162461bcd60e51b81526004016103a790611019565b60606000610a0a83610b91565b600101905060008167ffffffffffffffff811115610a2a57610a2a610df9565b6040519080825280601f01601f191660200182016040528015610a54576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610a5e57509392505050565b60006001600160a01b0384163b15610b8657604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610ad490339089908890889060040161106b565b6020604051808303816000875af1925050508015610b0f575060408051601f3d908101601f19168201909252610b0c918101906110a8565b60015b610b6c573d808015610b3d576040519150601f19603f3d011682016040523d82523d6000602084013e610b42565b606091505b508051600003610b645760405162461bcd60e51b81526004016103a790611019565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610790565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610bd05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610bfc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610c1a57662386f26fc10000830492506010015b6305f5e1008310610c32576305f5e100830492506008015b6127108310610c4657612710830492506004015b60648310610c58576064830492506002015b600a83106102745760010192915050565b6001600160e01b0319811681146106a857600080fd5b600060208284031215610c9157600080fd5b813561064281610c69565b60005b83811015610cb7578181015183820152602001610c9f565b838111156105cf5750506000910152565b60008151808452610ce0816020860160208601610c9c565b601f01601f19169290920160200192915050565b6020815260006106426020830184610cc8565b600060208284031215610d1957600080fd5b5035919050565b80356001600160a01b0381168114610d3757600080fd5b919050565b60008060408385031215610d4f57600080fd5b610d5883610d20565b946020939093013593505050565b600080600060608486031215610d7b57600080fd5b610d8484610d20565b9250610d9260208501610d20565b9150604084013590509250925092565b600060208284031215610db457600080fd5b61064282610d20565b60008060408385031215610dd057600080fd5b610dd983610d20565b915060208301358015158114610dee57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215610e2557600080fd5b610e2e85610d20565b9350610e3c60208601610d20565b925060408501359150606085013567ffffffffffffffff80821115610e6057600080fd5b818701915087601f830112610e7457600080fd5b813581811115610e8657610e86610df9565b604051601f8201601f19908116603f01168101908382118183101715610eae57610eae610df9565b816040528281528a6020848701011115610ec757600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215610efe57600080fd5b610f0783610d20565b9150610f1560208401610d20565b90509250929050565b600181811c90821680610f3257607f821691505b602082108103610f5257634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60008351610fb7818460208801610c9c565b835190830190610fcb818360208801610c9c565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061109e90830184610cc8565b9695505050505050565b6000602082840312156110ba57600080fd5b815161064281610c6956fea26469706673582212203444012838d8a4d94e0f3add6d8bb2fb39f1578fcb587501af32ec2cd13620e164736f6c634300080d0033", - "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636352211e1161008c578063a22cb46511610066578063a22cb465146101b3578063b88d4fde146101c6578063c87b56dd146101d9578063e985e9c5146101ec57600080fd5b80636352211e1461017757806370a082311461018a57806395d89b41146101ab57600080fd5b806301ffc9a7146100d457806306fdde03146100fc578063081812fc14610111578063095ea7b31461013c57806323b872dd1461015157806342842e0e14610164575b600080fd5b6100e76100e2366004610c7f565b610228565b60405190151581526020015b60405180910390f35b61010461027a565b6040516100f39190610cf4565b61012461011f366004610d07565b61030c565b6040516001600160a01b0390911681526020016100f3565b61014f61014a366004610d3c565b610333565b005b61014f61015f366004610d66565b61044d565b61014f610172366004610d66565b61047e565b610124610185366004610d07565b610499565b61019d610198366004610da2565b6104f9565b6040519081526020016100f3565b61010461057f565b61014f6101c1366004610dbd565b61058e565b61014f6101d4366004610e0f565b61059d565b6101046101e7366004610d07565b6105d5565b6100e76101fa366004610eeb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160e01b031982166380ac58cd60e01b148061025957506001600160e01b03198216635b5e139f60e01b145b8061027457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461028990610f1e565b80601f01602080910402602001604051908101604052809291908181526020018280546102b590610f1e565b80156103025780601f106102d757610100808354040283529160200191610302565b820191906000526020600020905b8154815290600101906020018083116102e557829003601f168201915b5050505050905090565b600061031782610649565b506000908152600460205260409020546001600160a01b031690565b600061033e82610499565b9050806001600160a01b0316836001600160a01b0316036103b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806103cc57506103cc81336101fa565b61043e5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016103a7565b61044883836106ab565b505050565b6104573382610719565b6104735760405162461bcd60e51b81526004016103a790610f58565b610448838383610798565b6104488383836040518060200160405280600081525061059d565b6000818152600260205260408120546001600160a01b0316806102745760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b60006001600160a01b0382166105635760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016103a7565b506001600160a01b031660009081526003602052604090205490565b60606001805461028990610f1e565b6105993383836108fc565b5050565b6105a73383610719565b6105c35760405162461bcd60e51b81526004016103a790610f58565b6105cf848484846109ca565b50505050565b60606105e082610649565b60006105f760408051602081019091526000815290565b905060008151116106175760405180602001604052806000815250610642565b80610621846109fd565b604051602001610632929190610fa5565b6040516020818303038152906040525b9392505050565b6000818152600260205260409020546001600160a01b03166106a85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906106e082610499565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061072583610499565b9050806001600160a01b0316846001600160a01b0316148061076c57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806107905750836001600160a01b03166107858461030c565b6001600160a01b0316145b949350505050565b826001600160a01b03166107ab82610499565b6001600160a01b0316146107d15760405162461bcd60e51b81526004016103a790610fd4565b6001600160a01b0382166108335760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016103a7565b826001600160a01b031661084682610499565b6001600160a01b03161461086c5760405162461bcd60e51b81526004016103a790610fd4565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b816001600160a01b0316836001600160a01b03160361095d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016103a7565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6109d5848484610798565b6109e184848484610a90565b6105cf5760405162461bcd60e51b81526004016103a790611019565b60606000610a0a83610b91565b600101905060008167ffffffffffffffff811115610a2a57610a2a610df9565b6040519080825280601f01601f191660200182016040528015610a54576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610a5e57509392505050565b60006001600160a01b0384163b15610b8657604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610ad490339089908890889060040161106b565b6020604051808303816000875af1925050508015610b0f575060408051601f3d908101601f19168201909252610b0c918101906110a8565b60015b610b6c573d808015610b3d576040519150601f19603f3d011682016040523d82523d6000602084013e610b42565b606091505b508051600003610b645760405162461bcd60e51b81526004016103a790611019565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610790565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610bd05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610bfc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610c1a57662386f26fc10000830492506010015b6305f5e1008310610c32576305f5e100830492506008015b6127108310610c4657612710830492506004015b60648310610c58576064830492506002015b600a83106102745760010192915050565b6001600160e01b0319811681146106a857600080fd5b600060208284031215610c9157600080fd5b813561064281610c69565b60005b83811015610cb7578181015183820152602001610c9f565b838111156105cf5750506000910152565b60008151808452610ce0816020860160208601610c9c565b601f01601f19169290920160200192915050565b6020815260006106426020830184610cc8565b600060208284031215610d1957600080fd5b5035919050565b80356001600160a01b0381168114610d3757600080fd5b919050565b60008060408385031215610d4f57600080fd5b610d5883610d20565b946020939093013593505050565b600080600060608486031215610d7b57600080fd5b610d8484610d20565b9250610d9260208501610d20565b9150604084013590509250925092565b600060208284031215610db457600080fd5b61064282610d20565b60008060408385031215610dd057600080fd5b610dd983610d20565b915060208301358015158114610dee57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215610e2557600080fd5b610e2e85610d20565b9350610e3c60208601610d20565b925060408501359150606085013567ffffffffffffffff80821115610e6057600080fd5b818701915087601f830112610e7457600080fd5b813581811115610e8657610e86610df9565b604051601f8201601f19908116603f01168101908382118183101715610eae57610eae610df9565b816040528281528a6020848701011115610ec757600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215610efe57600080fd5b610f0783610d20565b9150610f1560208401610d20565b90509250929050565b600181811c90821680610f3257607f821691505b602082108103610f5257634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60008351610fb7818460208801610c9c565b835190830190610fcb818360208801610c9c565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061109e90830184610cc8565b9695505050505050565b6000602082840312156110ba57600080fd5b815161064281610c6956fea26469706673582212203444012838d8a4d94e0f3add6d8bb2fb39f1578fcb587501af32ec2cd13620e164736f6c634300080d0033", - "linkReferences": {}, - "deployedLinkReferences": {} -} diff --git a/tools/utils/src/metadata.ts b/tools/utils/src/metadata.ts index d882fb6d8..bdc65ba69 100644 --- a/tools/utils/src/metadata.ts +++ b/tools/utils/src/metadata.ts @@ -22,10 +22,10 @@ const AIRSWAP_SYMBOL = 'AST' const DEFAULT_NAME = 'Unknown NFT' const DEFAULT_IPFS_URI = 'https://ipfs.io/ipfs/' -import { abi as ERC165_ABI } from './abis/ERC165.json' -import { abi as ERC20_ABI } from './abis/ERC20.json' -import { abi as ERC721_ABI } from './abis/ERC721.json' -import { abi as ERC1155_ABI } from './abis/ERC1155.json' +import { abi as ERC165_ABI } from '@openzeppelin/contracts/build/contracts/ERC165.json' +import { abi as ERC20_ABI } from '@openzeppelin/contracts/build/contracts/ERC20.json' +import { abi as ERC721_ABI } from '@openzeppelin/contracts/build/contracts/ERC721.json' +import { abi as ERC1155_ABI } from '@openzeppelin/contracts/build/contracts/ERC1155.json' export async function getKnownTokens( chainId: number diff --git a/tools/utils/src/swap-erc20.ts b/tools/utils/src/swap-erc20.ts index 98568fece..c41783e78 100644 --- a/tools/utils/src/swap-erc20.ts +++ b/tools/utils/src/swap-erc20.ts @@ -7,7 +7,7 @@ import { SignTypedDataVersion, } from '@metamask/eth-sig-util' -import { abi as ERC20_ABI } from './abis/ERC20.json' +import { abi as ERC20_ABI } from '@openzeppelin/contracts/build/contracts/ERC20.json' const erc20Interface = new ethers.utils.Interface(ERC20_ABI) import { From a017d41cbf0a047c0b122d64b69fa914d007cc02 Mon Sep 17 00:00:00 2001 From: Don Mosites Date: Wed, 15 May 2024 10:44:22 +0200 Subject: [PATCH 39/43] restore abis --- tools/utils/src/abis/ERC1155.json | 334 ++++++++++++++++++++++++++++ tools/utils/src/abis/ERC165.json | 30 +++ tools/utils/src/abis/ERC20.json | 297 +++++++++++++++++++++++++ tools/utils/src/abis/ERC721.json | 357 ++++++++++++++++++++++++++++++ tools/utils/src/metadata.ts | 8 +- tools/utils/src/swap-erc20.ts | 2 +- 6 files changed, 1023 insertions(+), 5 deletions(-) create mode 100644 tools/utils/src/abis/ERC1155.json create mode 100644 tools/utils/src/abis/ERC165.json create mode 100644 tools/utils/src/abis/ERC20.json create mode 100644 tools/utils/src/abis/ERC721.json diff --git a/tools/utils/src/abis/ERC1155.json b/tools/utils/src/abis/ERC1155.json new file mode 100644 index 000000000..8486b3605 --- /dev/null +++ b/tools/utils/src/abis/ERC1155.json @@ -0,0 +1,334 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC1155", + "sourceName": "contracts/token/ERC1155/ERC1155.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "uri_", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "TransferBatch", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TransferSingle", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "value", + "type": "string" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "URI", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "accounts", + "type": "address[]" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + } + ], + "name": "balanceOfBatch", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "ids", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "amounts", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeBatchTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "uri", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b50604051620015cb380380620015cb83398101604081905262000034916200011b565b6200003f8162000046565b5062000233565b80516200005b9060029060208401906200005f565b5050565b8280546200006d90620001f7565b90600052602060002090601f016020900481019282620000915760008555620000dc565b82601f10620000ac57805160ff1916838001178555620000dc565b82800160010185558215620000dc579182015b82811115620000dc578251825591602001919060010190620000bf565b50620000ea929150620000ee565b5090565b5b80821115620000ea5760008155600101620000ef565b634e487b7160e01b600052604160045260246000fd5b600060208083850312156200012f57600080fd5b82516001600160401b03808211156200014757600080fd5b818501915085601f8301126200015c57600080fd5b81518181111562000171576200017162000105565b604051601f8201601f19908116603f011681019083821181831017156200019c576200019c62000105565b816040528281528886848701011115620001b557600080fd5b600093505b82841015620001d95784840186015181850187015292850192620001ba565b82841115620001eb5760008684830101525b98975050505050505050565b600181811c908216806200020c57607f821691505b6020821081036200022d57634e487b7160e01b600052602260045260246000fd5b50919050565b61138880620002436000396000f3fe608060405234801561001057600080fd5b50600436106100875760003560e01c80634e1273f41161005b5780634e1273f41461010a578063a22cb4651461012a578063e985e9c51461013d578063f242432a1461017957600080fd5b8062fdd58e1461008c57806301ffc9a7146100b25780630e89341c146100d55780632eb2c2d6146100f5575b600080fd5b61009f61009a366004610b3f565b61018c565b6040519081526020015b60405180910390f35b6100c56100c0366004610b82565b610222565b60405190151581526020016100a9565b6100e86100e3366004610ba6565b610274565b6040516100a99190610c0c565b610108610103366004610d6b565b610308565b005b61011d610118366004610e15565b610354565b6040516100a99190610f1b565b610108610138366004610f2e565b61047e565b6100c561014b366004610f6a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b610108610187366004610f9d565b61048d565b60006001600160a01b0383166101fc5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000908152602081815260408083206001600160a01b03949094168352929052205490565b60006001600160e01b03198216636cdb3d1360e11b148061025357506001600160e01b031982166303a24d0760e21b145b8061026e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606002805461028390611002565b80601f01602080910402602001604051908101604052809291908181526020018280546102af90611002565b80156102fc5780601f106102d1576101008083540402835291602001916102fc565b820191906000526020600020905b8154815290600101906020018083116102df57829003601f168201915b50505050509050919050565b6001600160a01b0385163314806103245750610324853361014b565b6103405760405162461bcd60e51b81526004016101f39061103c565b61034d85858585856104d2565b5050505050565b606081518351146103b95760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016101f3565b6000835167ffffffffffffffff8111156103d5576103d5610c1f565b6040519080825280602002602001820160405280156103fe578160200160208202803683370190505b50905060005b8451811015610476576104498582815181106104225761042261108a565b602002602001015185838151811061043c5761043c61108a565b602002602001015161018c565b82828151811061045b5761045b61108a565b602090810291909101015261046f816110b6565b9050610404565b509392505050565b6104893383836106af565b5050565b6001600160a01b0385163314806104a957506104a9853361014b565b6104c55760405162461bcd60e51b81526004016101f39061103c565b61034d858585858561078f565b81518351146105345760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b60648201526084016101f3565b6001600160a01b03841661055a5760405162461bcd60e51b81526004016101f3906110cf565b3360005b845181101561064157600085828151811061057b5761057b61108a565b6020026020010151905060008583815181106105995761059961108a565b602090810291909101810151600084815280835260408082206001600160a01b038e1683529093529190912054909150818110156105e95760405162461bcd60e51b81526004016101f390611114565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b1682528120805484929061062690849061115e565b925050819055505050508061063a906110b6565b905061055e565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051610691929190611176565b60405180910390a46106a78187878787876108b9565b505050505050565b816001600160a01b0316836001600160a01b0316036107225760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016101f3565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166107b55760405162461bcd60e51b81526004016101f3906110cf565b3360006107c185610a1d565b905060006107ce85610a1d565b90506000868152602081815260408083206001600160a01b038c168452909152902054858110156108115760405162461bcd60e51b81526004016101f390611114565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061084e90849061115e565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46108ae848a8a8a8a8a610a68565b505050505050505050565b6001600160a01b0384163b156106a75760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906108fd90899089908890889088906004016111a4565b6020604051808303816000875af1925050508015610938575060408051601f3d908101601f1916820190925261093591810190611202565b60015b6109e45761094461121f565b806308c379a00361097d575061095861123b565b80610963575061097f565b8060405162461bcd60e51b81526004016101f39190610c0c565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016101f3565b6001600160e01b0319811663bc197c8160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b50505050505050565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110610a5757610a5761108a565b602090810291909101015292915050565b6001600160a01b0384163b156106a75760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190610aac908990899088908890889060040161130d565b6020604051808303816000875af1925050508015610ae7575060408051601f3d908101601f19168201909252610ae491810190611202565b60015b610af35761094461121f565b6001600160e01b0319811663f23a6e6160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b80356001600160a01b0381168114610b3a57600080fd5b919050565b60008060408385031215610b5257600080fd5b610b5b83610b23565b946020939093013593505050565b6001600160e01b031981168114610b7f57600080fd5b50565b600060208284031215610b9457600080fd5b8135610b9f81610b69565b9392505050565b600060208284031215610bb857600080fd5b5035919050565b6000815180845260005b81811015610be557602081850181015186830182015201610bc9565b81811115610bf7576000602083870101525b50601f01601f19169290920160200192915050565b602081526000610b9f6020830184610bbf565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715610c5b57610c5b610c1f565b6040525050565b600067ffffffffffffffff821115610c7c57610c7c610c1f565b5060051b60200190565b600082601f830112610c9757600080fd5b81356020610ca482610c62565b604051610cb18282610c35565b83815260059390931b8501820192828101915086841115610cd157600080fd5b8286015b84811015610cec5780358352918301918301610cd5565b509695505050505050565b600082601f830112610d0857600080fd5b813567ffffffffffffffff811115610d2257610d22610c1f565b604051610d39601f8301601f191660200182610c35565b818152846020838601011115610d4e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610d8357600080fd5b610d8c86610b23565b9450610d9a60208701610b23565b9350604086013567ffffffffffffffff80821115610db757600080fd5b610dc389838a01610c86565b94506060880135915080821115610dd957600080fd5b610de589838a01610c86565b93506080880135915080821115610dfb57600080fd5b50610e0888828901610cf7565b9150509295509295909350565b60008060408385031215610e2857600080fd5b823567ffffffffffffffff80821115610e4057600080fd5b818501915085601f830112610e5457600080fd5b81356020610e6182610c62565b604051610e6e8282610c35565b83815260059390931b8501820192828101915089841115610e8e57600080fd5b948201945b83861015610eb357610ea486610b23565b82529482019490820190610e93565b96505086013592505080821115610ec957600080fd5b50610ed685828601610c86565b9150509250929050565b600081518084526020808501945080840160005b83811015610f1057815187529582019590820190600101610ef4565b509495945050505050565b602081526000610b9f6020830184610ee0565b60008060408385031215610f4157600080fd5b610f4a83610b23565b915060208301358015158114610f5f57600080fd5b809150509250929050565b60008060408385031215610f7d57600080fd5b610f8683610b23565b9150610f9460208401610b23565b90509250929050565b600080600080600060a08688031215610fb557600080fd5b610fbe86610b23565b9450610fcc60208701610b23565b93506040860135925060608601359150608086013567ffffffffffffffff811115610ff657600080fd5b610e0888828901610cf7565b600181811c9082168061101657607f821691505b60208210810361103657634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016110c8576110c86110a0565b5060010190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60008219821115611171576111716110a0565b500190565b6040815260006111896040830185610ee0565b828103602084015261119b8185610ee0565b95945050505050565b6001600160a01b0386811682528516602082015260a0604082018190526000906111d090830186610ee0565b82810360608401526111e28186610ee0565b905082810360808401526111f68185610bbf565b98975050505050505050565b60006020828403121561121457600080fd5b8151610b9f81610b69565b600060033d11156112385760046000803e5060005160e01c5b90565b600060443d10156112495790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561127957505050505090565b82850191508151818111156112915750505050505090565b843d87010160208285010111156112ab5750505050505090565b6112ba60208286010187610c35565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061134790830184610bbf565b97965050505050505056fea26469706673582212202f31a5ed9841bb19ea3048d1ee82155c8ba6a9a7cec7bee194b0e339d260147f64736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100875760003560e01c80634e1273f41161005b5780634e1273f41461010a578063a22cb4651461012a578063e985e9c51461013d578063f242432a1461017957600080fd5b8062fdd58e1461008c57806301ffc9a7146100b25780630e89341c146100d55780632eb2c2d6146100f5575b600080fd5b61009f61009a366004610b3f565b61018c565b6040519081526020015b60405180910390f35b6100c56100c0366004610b82565b610222565b60405190151581526020016100a9565b6100e86100e3366004610ba6565b610274565b6040516100a99190610c0c565b610108610103366004610d6b565b610308565b005b61011d610118366004610e15565b610354565b6040516100a99190610f1b565b610108610138366004610f2e565b61047e565b6100c561014b366004610f6a565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205460ff1690565b610108610187366004610f9d565b61048d565b60006001600160a01b0383166101fc5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a2061646472657373207a65726f206973206e6f742061207660448201526930b634b21037bbb732b960b11b60648201526084015b60405180910390fd5b506000908152602081815260408083206001600160a01b03949094168352929052205490565b60006001600160e01b03198216636cdb3d1360e11b148061025357506001600160e01b031982166303a24d0760e21b145b8061026e57506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606002805461028390611002565b80601f01602080910402602001604051908101604052809291908181526020018280546102af90611002565b80156102fc5780601f106102d1576101008083540402835291602001916102fc565b820191906000526020600020905b8154815290600101906020018083116102df57829003601f168201915b50505050509050919050565b6001600160a01b0385163314806103245750610324853361014b565b6103405760405162461bcd60e51b81526004016101f39061103c565b61034d85858585856104d2565b5050505050565b606081518351146103b95760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e677468604482015268040dad2e6dac2e8c6d60bb1b60648201526084016101f3565b6000835167ffffffffffffffff8111156103d5576103d5610c1f565b6040519080825280602002602001820160405280156103fe578160200160208202803683370190505b50905060005b8451811015610476576104498582815181106104225761042261108a565b602002602001015185838151811061043c5761043c61108a565b602002602001015161018c565b82828151811061045b5761045b61108a565b602090810291909101015261046f816110b6565b9050610404565b509392505050565b6104893383836106af565b5050565b6001600160a01b0385163314806104a957506104a9853361014b565b6104c55760405162461bcd60e51b81526004016101f39061103c565b61034d858585858561078f565b81518351146105345760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b60648201526084016101f3565b6001600160a01b03841661055a5760405162461bcd60e51b81526004016101f3906110cf565b3360005b845181101561064157600085828151811061057b5761057b61108a565b6020026020010151905060008583815181106105995761059961108a565b602090810291909101810151600084815280835260408082206001600160a01b038e1683529093529190912054909150818110156105e95760405162461bcd60e51b81526004016101f390611114565b6000838152602081815260408083206001600160a01b038e8116855292528083208585039055908b1682528120805484929061062690849061115e565b925050819055505050508061063a906110b6565b905061055e565b50846001600160a01b0316866001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8787604051610691929190611176565b60405180910390a46106a78187878787876108b9565b505050505050565b816001600160a01b0316836001600160a01b0316036107225760405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b60648201526084016101f3565b6001600160a01b03838116600081815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0384166107b55760405162461bcd60e51b81526004016101f3906110cf565b3360006107c185610a1d565b905060006107ce85610a1d565b90506000868152602081815260408083206001600160a01b038c168452909152902054858110156108115760405162461bcd60e51b81526004016101f390611114565b6000878152602081815260408083206001600160a01b038d8116855292528083208985039055908a1682528120805488929061084e90849061115e565b909155505060408051888152602081018890526001600160a01b03808b16928c821692918816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46108ae848a8a8a8a8a610a68565b505050505050505050565b6001600160a01b0384163b156106a75760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906108fd90899089908890889088906004016111a4565b6020604051808303816000875af1925050508015610938575060408051601f3d908101601f1916820190925261093591810190611202565b60015b6109e45761094461121f565b806308c379a00361097d575061095861123b565b80610963575061097f565b8060405162461bcd60e51b81526004016101f39190610c0c565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d455243313135356044820152732932b1b2b4bb32b91034b6b83632b6b2b73a32b960611b60648201526084016101f3565b6001600160e01b0319811663bc197c8160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b50505050505050565b60408051600180825281830190925260609160009190602080830190803683370190505090508281600081518110610a5757610a5761108a565b602090810291909101015292915050565b6001600160a01b0384163b156106a75760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190610aac908990899088908890889060040161130d565b6020604051808303816000875af1925050508015610ae7575060408051601f3d908101601f19168201909252610ae491810190611202565b60015b610af35761094461121f565b6001600160e01b0319811663f23a6e6160e01b14610a145760405162461bcd60e51b81526004016101f3906112c5565b80356001600160a01b0381168114610b3a57600080fd5b919050565b60008060408385031215610b5257600080fd5b610b5b83610b23565b946020939093013593505050565b6001600160e01b031981168114610b7f57600080fd5b50565b600060208284031215610b9457600080fd5b8135610b9f81610b69565b9392505050565b600060208284031215610bb857600080fd5b5035919050565b6000815180845260005b81811015610be557602081850181015186830182015201610bc9565b81811115610bf7576000602083870101525b50601f01601f19169290920160200192915050565b602081526000610b9f6020830184610bbf565b634e487b7160e01b600052604160045260246000fd5b601f8201601f1916810167ffffffffffffffff81118282101715610c5b57610c5b610c1f565b6040525050565b600067ffffffffffffffff821115610c7c57610c7c610c1f565b5060051b60200190565b600082601f830112610c9757600080fd5b81356020610ca482610c62565b604051610cb18282610c35565b83815260059390931b8501820192828101915086841115610cd157600080fd5b8286015b84811015610cec5780358352918301918301610cd5565b509695505050505050565b600082601f830112610d0857600080fd5b813567ffffffffffffffff811115610d2257610d22610c1f565b604051610d39601f8301601f191660200182610c35565b818152846020838601011115610d4e57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600060a08688031215610d8357600080fd5b610d8c86610b23565b9450610d9a60208701610b23565b9350604086013567ffffffffffffffff80821115610db757600080fd5b610dc389838a01610c86565b94506060880135915080821115610dd957600080fd5b610de589838a01610c86565b93506080880135915080821115610dfb57600080fd5b50610e0888828901610cf7565b9150509295509295909350565b60008060408385031215610e2857600080fd5b823567ffffffffffffffff80821115610e4057600080fd5b818501915085601f830112610e5457600080fd5b81356020610e6182610c62565b604051610e6e8282610c35565b83815260059390931b8501820192828101915089841115610e8e57600080fd5b948201945b83861015610eb357610ea486610b23565b82529482019490820190610e93565b96505086013592505080821115610ec957600080fd5b50610ed685828601610c86565b9150509250929050565b600081518084526020808501945080840160005b83811015610f1057815187529582019590820190600101610ef4565b509495945050505050565b602081526000610b9f6020830184610ee0565b60008060408385031215610f4157600080fd5b610f4a83610b23565b915060208301358015158114610f5f57600080fd5b809150509250929050565b60008060408385031215610f7d57600080fd5b610f8683610b23565b9150610f9460208401610b23565b90509250929050565b600080600080600060a08688031215610fb557600080fd5b610fbe86610b23565b9450610fcc60208701610b23565b93506040860135925060608601359150608086013567ffffffffffffffff811115610ff657600080fd5b610e0888828901610cf7565b600181811c9082168061101657607f821691505b60208210810361103657634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602e908201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60408201526d195c881bdc88185c1c1c9bdd995960921b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016110c8576110c86110a0565b5060010190565b60208082526025908201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604082015264647265737360d81b606082015260800190565b6020808252602a908201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60408201526939103a3930b739b332b960b11b606082015260800190565b60008219821115611171576111716110a0565b500190565b6040815260006111896040830185610ee0565b828103602084015261119b8185610ee0565b95945050505050565b6001600160a01b0386811682528516602082015260a0604082018190526000906111d090830186610ee0565b82810360608401526111e28186610ee0565b905082810360808401526111f68185610bbf565b98975050505050505050565b60006020828403121561121457600080fd5b8151610b9f81610b69565b600060033d11156112385760046000803e5060005160e01c5b90565b600060443d10156112495790565b6040516003193d81016004833e81513d67ffffffffffffffff816024840111818411171561127957505050505090565b82850191508151818111156112915750505050505090565b843d87010160208285010111156112ab5750505050505090565b6112ba60208286010187610c35565b509095945050505050565b60208082526028908201527f455243313135353a204552433131353552656365697665722072656a656374656040820152676420746f6b656e7360c01b606082015260800190565b6001600160a01b03868116825285166020820152604081018490526060810183905260a06080820181905260009061134790830184610bbf565b97965050505050505056fea26469706673582212202f31a5ed9841bb19ea3048d1ee82155c8ba6a9a7cec7bee194b0e339d260147f64736f6c634300080d0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/tools/utils/src/abis/ERC165.json b/tools/utils/src/abis/ERC165.json new file mode 100644 index 000000000..e1bfd6b4f --- /dev/null +++ b/tools/utils/src/abis/ERC165.json @@ -0,0 +1,30 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC165", + "sourceName": "contracts/utils/introspection/ERC165.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x", + "deployedBytecode": "0x", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/tools/utils/src/abis/ERC20.json b/tools/utils/src/abis/ERC20.json new file mode 100644 index 000000000..e1f5a7ac6 --- /dev/null +++ b/tools/utils/src/abis/ERC20.json @@ -0,0 +1,297 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC20", + "sourceName": "contracts/token/ERC20/ERC20.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "subtractedValue", + "type": "uint256" + } + ], + "name": "decreaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "addedValue", + "type": "uint256" + } + ], + "name": "increaseAllowance", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b5060405162000aed38038062000aed8339810160408190526200003491620001db565b81516200004990600390602085019062000068565b5080516200005f90600490602084019062000068565b50505062000281565b828054620000769062000245565b90600052602060002090601f0160209004810192826200009a5760008555620000e5565b82601f10620000b557805160ff1916838001178555620000e5565b82800160010185558215620000e5579182015b82811115620000e5578251825591602001919060010190620000c8565b50620000f3929150620000f7565b5090565b5b80821115620000f35760008155600101620000f8565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013657600080fd5b81516001600160401b03808211156200015357620001536200010e565b604051601f8301601f19908116603f011681019082821181831017156200017e576200017e6200010e565b816040528381526020925086838588010111156200019b57600080fd5b600091505b83821015620001bf5785820183015181830184015290820190620001a0565b83821115620001d15760008385830101525b9695505050505050565b60008060408385031215620001ef57600080fd5b82516001600160401b03808211156200020757600080fd5b620002158683870162000124565b935060208501519150808211156200022c57600080fd5b506200023b8582860162000124565b9150509250929050565b600181811c908216806200025a57607f821691505b6020821081036200027b57634e487b7160e01b600052602260045260246000fd5b50919050565b61085c80620002916000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069a565b60405180910390f35b6100df6100da36600461070b565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610735565b61024a565b604051601281526020016100c3565b6100df61013136600461070b565b61026e565b6100f3610144366004610771565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df61017536600461070b565b61029f565b6100df61018836600461070b565b61031f565b6100f361019b366004610793565b61032d565b6060600380546101af906107c6565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c6565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b9190610800565b610358565b6060600480546101af906107c6565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f0565b600060208083528351808285015260005b818110156106c7578581018301518582016040015282016106ab565b818111156106d9576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461070657600080fd5b919050565b6000806040838503121561071e57600080fd5b610727836106ef565b946020939093013593505050565b60008060006060848603121561074a57600080fd5b610753846106ef565b9250610761602085016106ef565b9150604084013590509250925092565b60006020828403121561078357600080fd5b61078c826106ef565b9392505050565b600080604083850312156107a657600080fd5b6107af836106ef565b91506107bd602084016106ef565b90509250929050565b600181811c908216806107da57607f821691505b6020821081036107fa57634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561082157634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212208ea3918651cefe661c47475f544a91c156156839b9d304a33b7b43e599a312a064736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461012357806370a082311461013657806395d89b411461015f578063a457c2d714610167578063a9059cbb1461017a578063dd62ed3e1461018d57600080fd5b806306fdde03146100ae578063095ea7b3146100cc57806318160ddd146100ef57806323b872dd14610101578063313ce56714610114575b600080fd5b6100b66101a0565b6040516100c3919061069a565b60405180910390f35b6100df6100da36600461070b565b610232565b60405190151581526020016100c3565b6002545b6040519081526020016100c3565b6100df61010f366004610735565b61024a565b604051601281526020016100c3565b6100df61013136600461070b565b61026e565b6100f3610144366004610771565b6001600160a01b031660009081526020819052604090205490565b6100b6610290565b6100df61017536600461070b565b61029f565b6100df61018836600461070b565b61031f565b6100f361019b366004610793565b61032d565b6060600380546101af906107c6565b80601f01602080910402602001604051908101604052809291908181526020018280546101db906107c6565b80156102285780601f106101fd57610100808354040283529160200191610228565b820191906000526020600020905b81548152906001019060200180831161020b57829003601f168201915b5050505050905090565b600033610240818585610358565b5060019392505050565b60003361025885828561047c565b6102638585856104f6565b506001949350505050565b600033610240818585610281838361032d565b61028b9190610800565b610358565b6060600480546101af906107c6565b600033816102ad828661032d565b9050838110156103125760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6102638286868403610358565b6000336102408185856104f6565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166103ba5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610309565b6001600160a01b03821661041b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610309565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000610488848461032d565b905060001981146104f057818110156104e35760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610309565b6104f08484848403610358565b50505050565b6001600160a01b03831661055a5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610309565b6001600160a01b0382166105bc5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610309565b6001600160a01b038316600090815260208190526040902054818110156106345760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610309565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36104f0565b600060208083528351808285015260005b818110156106c7578581018301518582016040015282016106ab565b818111156106d9576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461070657600080fd5b919050565b6000806040838503121561071e57600080fd5b610727836106ef565b946020939093013593505050565b60008060006060848603121561074a57600080fd5b610753846106ef565b9250610761602085016106ef565b9150604084013590509250925092565b60006020828403121561078357600080fd5b61078c826106ef565b9392505050565b600080604083850312156107a657600080fd5b6107af836106ef565b91506107bd602084016106ef565b90509250929050565b600181811c908216806107da57607f821691505b6020821081036107fa57634e487b7160e01b600052602260045260246000fd5b50919050565b6000821982111561082157634e487b7160e01b600052601160045260246000fd5b50019056fea26469706673582212208ea3918651cefe661c47475f544a91c156156839b9d304a33b7b43e599a312a064736f6c634300080d0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/tools/utils/src/abis/ERC721.json b/tools/utils/src/abis/ERC721.json new file mode 100644 index 000000000..789fdef4b --- /dev/null +++ b/tools/utils/src/abis/ERC721.json @@ -0,0 +1,357 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "ERC721", + "sourceName": "contracts/token/ERC721/ERC721.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "string", + "name": "name_", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol_", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "approved", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "ApprovalForAll", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "getApproved", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "operator", + "type": "address" + } + ], + "name": "isApprovedForAll", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "ownerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "safeTransferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operator", + "type": "address" + }, + { + "internalType": "bool", + "name": "approved", + "type": "bool" + } + ], + "name": "setApprovalForAll", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "tokenURI", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x60806040523480156200001157600080fd5b506040516200138c3803806200138c8339810160408190526200003491620001db565b81516200004990600090602085019062000068565b5080516200005f90600190602084019062000068565b50505062000281565b828054620000769062000245565b90600052602060002090601f0160209004810192826200009a5760008555620000e5565b82601f10620000b557805160ff1916838001178555620000e5565b82800160010185558215620000e5579182015b82811115620000e5578251825591602001919060010190620000c8565b50620000f3929150620000f7565b5090565b5b80821115620000f35760008155600101620000f8565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200013657600080fd5b81516001600160401b03808211156200015357620001536200010e565b604051601f8301601f19908116603f011681019082821181831017156200017e576200017e6200010e565b816040528381526020925086838588010111156200019b57600080fd5b600091505b83821015620001bf5785820183015181830184015290820190620001a0565b83821115620001d15760008385830101525b9695505050505050565b60008060408385031215620001ef57600080fd5b82516001600160401b03808211156200020757600080fd5b620002158683870162000124565b935060208501519150808211156200022c57600080fd5b506200023b8582860162000124565b9150509250929050565b600181811c908216806200025a57607f821691505b6020821081036200027b57634e487b7160e01b600052602260045260246000fd5b50919050565b6110fb80620002916000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636352211e1161008c578063a22cb46511610066578063a22cb465146101b3578063b88d4fde146101c6578063c87b56dd146101d9578063e985e9c5146101ec57600080fd5b80636352211e1461017757806370a082311461018a57806395d89b41146101ab57600080fd5b806301ffc9a7146100d457806306fdde03146100fc578063081812fc14610111578063095ea7b31461013c57806323b872dd1461015157806342842e0e14610164575b600080fd5b6100e76100e2366004610c7f565b610228565b60405190151581526020015b60405180910390f35b61010461027a565b6040516100f39190610cf4565b61012461011f366004610d07565b61030c565b6040516001600160a01b0390911681526020016100f3565b61014f61014a366004610d3c565b610333565b005b61014f61015f366004610d66565b61044d565b61014f610172366004610d66565b61047e565b610124610185366004610d07565b610499565b61019d610198366004610da2565b6104f9565b6040519081526020016100f3565b61010461057f565b61014f6101c1366004610dbd565b61058e565b61014f6101d4366004610e0f565b61059d565b6101046101e7366004610d07565b6105d5565b6100e76101fa366004610eeb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160e01b031982166380ac58cd60e01b148061025957506001600160e01b03198216635b5e139f60e01b145b8061027457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461028990610f1e565b80601f01602080910402602001604051908101604052809291908181526020018280546102b590610f1e565b80156103025780601f106102d757610100808354040283529160200191610302565b820191906000526020600020905b8154815290600101906020018083116102e557829003601f168201915b5050505050905090565b600061031782610649565b506000908152600460205260409020546001600160a01b031690565b600061033e82610499565b9050806001600160a01b0316836001600160a01b0316036103b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806103cc57506103cc81336101fa565b61043e5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016103a7565b61044883836106ab565b505050565b6104573382610719565b6104735760405162461bcd60e51b81526004016103a790610f58565b610448838383610798565b6104488383836040518060200160405280600081525061059d565b6000818152600260205260408120546001600160a01b0316806102745760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b60006001600160a01b0382166105635760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016103a7565b506001600160a01b031660009081526003602052604090205490565b60606001805461028990610f1e565b6105993383836108fc565b5050565b6105a73383610719565b6105c35760405162461bcd60e51b81526004016103a790610f58565b6105cf848484846109ca565b50505050565b60606105e082610649565b60006105f760408051602081019091526000815290565b905060008151116106175760405180602001604052806000815250610642565b80610621846109fd565b604051602001610632929190610fa5565b6040516020818303038152906040525b9392505050565b6000818152600260205260409020546001600160a01b03166106a85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906106e082610499565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061072583610499565b9050806001600160a01b0316846001600160a01b0316148061076c57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806107905750836001600160a01b03166107858461030c565b6001600160a01b0316145b949350505050565b826001600160a01b03166107ab82610499565b6001600160a01b0316146107d15760405162461bcd60e51b81526004016103a790610fd4565b6001600160a01b0382166108335760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016103a7565b826001600160a01b031661084682610499565b6001600160a01b03161461086c5760405162461bcd60e51b81526004016103a790610fd4565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b816001600160a01b0316836001600160a01b03160361095d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016103a7565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6109d5848484610798565b6109e184848484610a90565b6105cf5760405162461bcd60e51b81526004016103a790611019565b60606000610a0a83610b91565b600101905060008167ffffffffffffffff811115610a2a57610a2a610df9565b6040519080825280601f01601f191660200182016040528015610a54576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610a5e57509392505050565b60006001600160a01b0384163b15610b8657604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610ad490339089908890889060040161106b565b6020604051808303816000875af1925050508015610b0f575060408051601f3d908101601f19168201909252610b0c918101906110a8565b60015b610b6c573d808015610b3d576040519150601f19603f3d011682016040523d82523d6000602084013e610b42565b606091505b508051600003610b645760405162461bcd60e51b81526004016103a790611019565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610790565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610bd05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610bfc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610c1a57662386f26fc10000830492506010015b6305f5e1008310610c32576305f5e100830492506008015b6127108310610c4657612710830492506004015b60648310610c58576064830492506002015b600a83106102745760010192915050565b6001600160e01b0319811681146106a857600080fd5b600060208284031215610c9157600080fd5b813561064281610c69565b60005b83811015610cb7578181015183820152602001610c9f565b838111156105cf5750506000910152565b60008151808452610ce0816020860160208601610c9c565b601f01601f19169290920160200192915050565b6020815260006106426020830184610cc8565b600060208284031215610d1957600080fd5b5035919050565b80356001600160a01b0381168114610d3757600080fd5b919050565b60008060408385031215610d4f57600080fd5b610d5883610d20565b946020939093013593505050565b600080600060608486031215610d7b57600080fd5b610d8484610d20565b9250610d9260208501610d20565b9150604084013590509250925092565b600060208284031215610db457600080fd5b61064282610d20565b60008060408385031215610dd057600080fd5b610dd983610d20565b915060208301358015158114610dee57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215610e2557600080fd5b610e2e85610d20565b9350610e3c60208601610d20565b925060408501359150606085013567ffffffffffffffff80821115610e6057600080fd5b818701915087601f830112610e7457600080fd5b813581811115610e8657610e86610df9565b604051601f8201601f19908116603f01168101908382118183101715610eae57610eae610df9565b816040528281528a6020848701011115610ec757600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215610efe57600080fd5b610f0783610d20565b9150610f1560208401610d20565b90509250929050565b600181811c90821680610f3257607f821691505b602082108103610f5257634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60008351610fb7818460208801610c9c565b835190830190610fcb818360208801610c9c565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061109e90830184610cc8565b9695505050505050565b6000602082840312156110ba57600080fd5b815161064281610c6956fea26469706673582212203444012838d8a4d94e0f3add6d8bb2fb39f1578fcb587501af32ec2cd13620e164736f6c634300080d0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100cf5760003560e01c80636352211e1161008c578063a22cb46511610066578063a22cb465146101b3578063b88d4fde146101c6578063c87b56dd146101d9578063e985e9c5146101ec57600080fd5b80636352211e1461017757806370a082311461018a57806395d89b41146101ab57600080fd5b806301ffc9a7146100d457806306fdde03146100fc578063081812fc14610111578063095ea7b31461013c57806323b872dd1461015157806342842e0e14610164575b600080fd5b6100e76100e2366004610c7f565b610228565b60405190151581526020015b60405180910390f35b61010461027a565b6040516100f39190610cf4565b61012461011f366004610d07565b61030c565b6040516001600160a01b0390911681526020016100f3565b61014f61014a366004610d3c565b610333565b005b61014f61015f366004610d66565b61044d565b61014f610172366004610d66565b61047e565b610124610185366004610d07565b610499565b61019d610198366004610da2565b6104f9565b6040519081526020016100f3565b61010461057f565b61014f6101c1366004610dbd565b61058e565b61014f6101d4366004610e0f565b61059d565b6101046101e7366004610d07565b6105d5565b6100e76101fa366004610eeb565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b60006001600160e01b031982166380ac58cd60e01b148061025957506001600160e01b03198216635b5e139f60e01b145b8061027457506301ffc9a760e01b6001600160e01b03198316145b92915050565b60606000805461028990610f1e565b80601f01602080910402602001604051908101604052809291908181526020018280546102b590610f1e565b80156103025780601f106102d757610100808354040283529160200191610302565b820191906000526020600020905b8154815290600101906020018083116102e557829003601f168201915b5050505050905090565b600061031782610649565b506000908152600460205260409020546001600160a01b031690565b600061033e82610499565b9050806001600160a01b0316836001600160a01b0316036103b05760405162461bcd60e51b815260206004820152602160248201527f4552433732313a20617070726f76616c20746f2063757272656e74206f776e656044820152603960f91b60648201526084015b60405180910390fd5b336001600160a01b03821614806103cc57506103cc81336101fa565b61043e5760405162461bcd60e51b815260206004820152603d60248201527f4552433732313a20617070726f76652063616c6c6572206973206e6f7420746f60448201527f6b656e206f776e6572206f7220617070726f76656420666f7220616c6c00000060648201526084016103a7565b61044883836106ab565b505050565b6104573382610719565b6104735760405162461bcd60e51b81526004016103a790610f58565b610448838383610798565b6104488383836040518060200160405280600081525061059d565b6000818152600260205260408120546001600160a01b0316806102745760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b60006001600160a01b0382166105635760405162461bcd60e51b815260206004820152602960248201527f4552433732313a2061646472657373207a65726f206973206e6f7420612076616044820152683634b21037bbb732b960b91b60648201526084016103a7565b506001600160a01b031660009081526003602052604090205490565b60606001805461028990610f1e565b6105993383836108fc565b5050565b6105a73383610719565b6105c35760405162461bcd60e51b81526004016103a790610f58565b6105cf848484846109ca565b50505050565b60606105e082610649565b60006105f760408051602081019091526000815290565b905060008151116106175760405180602001604052806000815250610642565b80610621846109fd565b604051602001610632929190610fa5565b6040516020818303038152906040525b9392505050565b6000818152600260205260409020546001600160a01b03166106a85760405162461bcd60e51b8152602060048201526018602482015277115490cdcc8c4e881a5b9d985b1a59081d1bdad95b88125160421b60448201526064016103a7565b50565b600081815260046020526040902080546001600160a01b0319166001600160a01b03841690811790915581906106e082610499565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60008061072583610499565b9050806001600160a01b0316846001600160a01b0316148061076c57506001600160a01b0380821660009081526005602090815260408083209388168352929052205460ff165b806107905750836001600160a01b03166107858461030c565b6001600160a01b0316145b949350505050565b826001600160a01b03166107ab82610499565b6001600160a01b0316146107d15760405162461bcd60e51b81526004016103a790610fd4565b6001600160a01b0382166108335760405162461bcd60e51b8152602060048201526024808201527f4552433732313a207472616e7366657220746f20746865207a65726f206164646044820152637265737360e01b60648201526084016103a7565b826001600160a01b031661084682610499565b6001600160a01b03161461086c5760405162461bcd60e51b81526004016103a790610fd4565b600081815260046020908152604080832080546001600160a01b03199081169091556001600160a01b0387811680865260038552838620805460001901905590871680865283862080546001019055868652600290945282852080549092168417909155905184937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b816001600160a01b0316836001600160a01b03160361095d5760405162461bcd60e51b815260206004820152601960248201527f4552433732313a20617070726f766520746f2063616c6c65720000000000000060448201526064016103a7565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6109d5848484610798565b6109e184848484610a90565b6105cf5760405162461bcd60e51b81526004016103a790611019565b60606000610a0a83610b91565b600101905060008167ffffffffffffffff811115610a2a57610a2a610df9565b6040519080825280601f01601f191660200182016040528015610a54576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084610a5e57509392505050565b60006001600160a01b0384163b15610b8657604051630a85bd0160e11b81526001600160a01b0385169063150b7a0290610ad490339089908890889060040161106b565b6020604051808303816000875af1925050508015610b0f575060408051601f3d908101601f19168201909252610b0c918101906110a8565b60015b610b6c573d808015610b3d576040519150601f19603f3d011682016040523d82523d6000602084013e610b42565b606091505b508051600003610b645760405162461bcd60e51b81526004016103a790611019565b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050610790565b506001949350505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b8310610bd05772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310610bfc576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc100008310610c1a57662386f26fc10000830492506010015b6305f5e1008310610c32576305f5e100830492506008015b6127108310610c4657612710830492506004015b60648310610c58576064830492506002015b600a83106102745760010192915050565b6001600160e01b0319811681146106a857600080fd5b600060208284031215610c9157600080fd5b813561064281610c69565b60005b83811015610cb7578181015183820152602001610c9f565b838111156105cf5750506000910152565b60008151808452610ce0816020860160208601610c9c565b601f01601f19169290920160200192915050565b6020815260006106426020830184610cc8565b600060208284031215610d1957600080fd5b5035919050565b80356001600160a01b0381168114610d3757600080fd5b919050565b60008060408385031215610d4f57600080fd5b610d5883610d20565b946020939093013593505050565b600080600060608486031215610d7b57600080fd5b610d8484610d20565b9250610d9260208501610d20565b9150604084013590509250925092565b600060208284031215610db457600080fd5b61064282610d20565b60008060408385031215610dd057600080fd5b610dd983610d20565b915060208301358015158114610dee57600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215610e2557600080fd5b610e2e85610d20565b9350610e3c60208601610d20565b925060408501359150606085013567ffffffffffffffff80821115610e6057600080fd5b818701915087601f830112610e7457600080fd5b813581811115610e8657610e86610df9565b604051601f8201601f19908116603f01168101908382118183101715610eae57610eae610df9565b816040528281528a6020848701011115610ec757600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b60008060408385031215610efe57600080fd5b610f0783610d20565b9150610f1560208401610d20565b90509250929050565b600181811c90821680610f3257607f821691505b602082108103610f5257634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252602d908201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560408201526c1c881bdc88185c1c1c9bdd9959609a1b606082015260800190565b60008351610fb7818460208801610c9c565b835190830190610fcb818360208801610c9c565b01949350505050565b60208082526025908201527f4552433732313a207472616e736665722066726f6d20696e636f72726563742060408201526437bbb732b960d91b606082015260800190565b60208082526032908201527f4552433732313a207472616e7366657220746f206e6f6e20455243373231526560408201527131b2b4bb32b91034b6b83632b6b2b73a32b960711b606082015260800190565b6001600160a01b038581168252841660208201526040810183905260806060820181905260009061109e90830184610cc8565b9695505050505050565b6000602082840312156110ba57600080fd5b815161064281610c6956fea26469706673582212203444012838d8a4d94e0f3add6d8bb2fb39f1578fcb587501af32ec2cd13620e164736f6c634300080d0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/tools/utils/src/metadata.ts b/tools/utils/src/metadata.ts index bdc65ba69..d882fb6d8 100644 --- a/tools/utils/src/metadata.ts +++ b/tools/utils/src/metadata.ts @@ -22,10 +22,10 @@ const AIRSWAP_SYMBOL = 'AST' const DEFAULT_NAME = 'Unknown NFT' const DEFAULT_IPFS_URI = 'https://ipfs.io/ipfs/' -import { abi as ERC165_ABI } from '@openzeppelin/contracts/build/contracts/ERC165.json' -import { abi as ERC20_ABI } from '@openzeppelin/contracts/build/contracts/ERC20.json' -import { abi as ERC721_ABI } from '@openzeppelin/contracts/build/contracts/ERC721.json' -import { abi as ERC1155_ABI } from '@openzeppelin/contracts/build/contracts/ERC1155.json' +import { abi as ERC165_ABI } from './abis/ERC165.json' +import { abi as ERC20_ABI } from './abis/ERC20.json' +import { abi as ERC721_ABI } from './abis/ERC721.json' +import { abi as ERC1155_ABI } from './abis/ERC1155.json' export async function getKnownTokens( chainId: number diff --git a/tools/utils/src/swap-erc20.ts b/tools/utils/src/swap-erc20.ts index c41783e78..98568fece 100644 --- a/tools/utils/src/swap-erc20.ts +++ b/tools/utils/src/swap-erc20.ts @@ -7,7 +7,7 @@ import { SignTypedDataVersion, } from '@metamask/eth-sig-util' -import { abi as ERC20_ABI } from '@openzeppelin/contracts/build/contracts/ERC20.json' +import { abi as ERC20_ABI } from './abis/ERC20.json' const erc20Interface = new ethers.utils.Interface(ERC20_ABI) import { From 620e34ebb6a72efb512c7945c674b2c0f6ca4221 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 16 May 2024 16:13:58 -0400 Subject: [PATCH 40/43] Updated copyright date --- source/delegate/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/delegate/LICENSE b/source/delegate/LICENSE index 25fb212c5..f963da81e 100644 --- a/source/delegate/LICENSE +++ b/source/delegate/LICENSE @@ -1,4 +1,4 @@ -Copyright 2023 AirSwap +Copyright 2024 AirSwap Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), From f0033c88e0f8b8ee69a0d822d7d3b37916cf8a2e Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 16 May 2024 17:18:07 -0400 Subject: [PATCH 41/43] PR comments, added swapERC20 setter and fixed ownership initialization --- source/delegate/README.md | 22 +++++++++---------- source/delegate/contracts/Delegate.sol | 18 +++++++++++---- .../contracts/interfaces/IDelegate.sol | 5 +++-- source/delegate/package.json | 4 ++-- source/delegate/test/Delegate.js | 18 ++++++++++++--- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/source/delegate/README.md b/source/delegate/README.md index 37de1296a..ed1a9091b 100644 --- a/source/delegate/README.md +++ b/source/delegate/README.md @@ -1,4 +1,4 @@ -# Pool +# Delegate [AirSwap](https://www.airswap.io/) is an open-source peer-to-peer trading network. @@ -21,16 +21,16 @@ Environment variables are set in an `.env` file in the repository root. -| Command | Description | -| :--------------- | :--------------------------------------- | -| `yarn` | Install dependencies | -| `yarn clean` | Delete the contract `build` folder | -| `yarn compile` | Compile all contracts to `build` folder | -| `yarn coverage` | Report test coverage | -| `yarn test` | Run all tests in `test` folder | -| `yarn test:ci` | Run CI tests in `test` folder | -| `yarn deploy` | Deploy on a network using --network flag | -| `yarn verify` | Verify on a network using --network flag | +| Command | Description | +| :-------------- | :--------------------------------------- | +| `yarn` | Install dependencies | +| `yarn clean` | Delete the contract `build` folder | +| `yarn compile` | Compile all contracts to `build` folder | +| `yarn coverage` | Report test coverage | +| `yarn test` | Run all tests in `test` folder | +| `yarn test:ci` | Run CI tests in `test` folder | +| `yarn deploy` | Deploy on a network using --network flag | +| `yarn verify` | Verify on a network using --network flag | ## Running Tests diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 8f98c2524..a894ff621 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -27,6 +27,7 @@ contract Delegate is IDelegate, Ownable { * @notice Contract Constructor */ constructor(ISwapERC20 _swapERC20) { + _initializeOwner(msg.sender); swapERC20 = _swapERC20; } @@ -106,11 +107,11 @@ contract Delegate is IDelegate, Ownable { if ( _senderAmount > (_signerAmount * rule.senderAmount) / rule.signerAmount ) { - revert InsufficientSignerAmount(); + revert InvalidSignerAmount(); } if (rule.senderAmount < _senderAmount) { - revert InsufficientDelegateAllowance(); + revert InvalidSenderAmount(); } SafeTransferLib.safeTransferFrom( @@ -143,7 +144,7 @@ contract Delegate is IDelegate, Ownable { } /** - * @notice Authorize a signatory + * @notice Authorize a wallet to manage rules * @param _manager address Wallet of the signatory to authorize * @dev Emits an Authorize event */ @@ -154,7 +155,7 @@ contract Delegate is IDelegate, Ownable { } /** - * @notice Revoke the signatory + * @notice Revoke a manager * @dev Emits a Revoke event */ function revoke() external { @@ -162,4 +163,13 @@ contract Delegate is IDelegate, Ownable { delete authorized[msg.sender]; emit Revoke(_tmp, msg.sender); } + + /** + * @notice Sets the SwapERC20 contract + * @param _swapERC20 ISwapERC20 The SwapERC20 contract + */ + function setSwapERC20Contract(ISwapERC20 _swapERC20) external onlyOwner { + if (address(_swapERC20) == address(0)) revert InvalidAddress(); + swapERC20 = _swapERC20; + } } diff --git a/source/delegate/contracts/interfaces/IDelegate.sol b/source/delegate/contracts/interfaces/IDelegate.sol index a05c03509..825ff2690 100644 --- a/source/delegate/contracts/interfaces/IDelegate.sol +++ b/source/delegate/contracts/interfaces/IDelegate.sol @@ -13,8 +13,9 @@ interface IDelegate { uint256 signerAmount; } - error InsufficientDelegateAllowance(); - error InsufficientSignerAmount(); + error InvalidAddress(); + error InvalidSenderAmount(); + error InvalidSignerAmount(); error ManagerInvalid(); error SenderInvalid(); error TransferFromFailed(); diff --git a/source/delegate/package.json b/source/delegate/package.json index 3ecb87a1c..5ca45656f 100644 --- a/source/delegate/package.json +++ b/source/delegate/package.json @@ -1,7 +1,7 @@ { "name": "@airswap/delegate", - "version": "4.1.4", - "description": "AirSwap: Trade intent delegates", + "version": "4.3.0-beta.0", + "description": "AirSwap: Delegate On-chain Trading Rules", "license": "MIT", "repository": { "type": "git", diff --git a/source/delegate/test/Delegate.js b/source/delegate/test/Delegate.js index 4391d0d68..130b1ed30 100644 --- a/source/delegate/test/Delegate.js +++ b/source/delegate/test/Delegate.js @@ -17,6 +17,7 @@ const DEFAULT_SIGNER_AMOUNT = '10000' const PROTOCOL_FEE = '5' const REBATE_SCALE = '10' const REBATE_MAX = '100' +const UPDATE_SWAP_ERC20_ADDRESS = '0x0000000000000000000000000000000000001337' describe('Delegate Unit', () => { let deployer @@ -129,10 +130,21 @@ describe('Delegate Unit', () => { setUpApprovals() }) - describe('Constructor', async () => { + describe('Constructor and admin functions', async () => { it('swap ERC20 address is set', async () => { expect(await delegate.swapERC20()).to.equal(swapERC20.address) }) + + it('sets the swapERC20Contract address', async () => { + await delegate.setSwapERC20Contract(UPDATE_SWAP_ERC20_ADDRESS) + expect(await delegate.swapERC20()).to.equal(UPDATE_SWAP_ERC20_ADDRESS) + }) + + it('only the owner can set the swapERC20Contract address', async () => { + await expect( + delegate.connect(anyone).setSwapERC20Contract(UPDATE_SWAP_ERC20_ADDRESS) + ).to.be.revertedWith('Unauthorized') + }) }) describe('Rules', async () => { @@ -386,7 +398,7 @@ describe('Delegate Unit', () => { await expect( delegate.connect(signer).swap(sender.address, ...order) - ).to.be.revertedWith('InsufficientDelegateAllowance') + ).to.be.revertedWith('InvalidSenderAmount') }) it('fails to swap with insufficient signer amount on Rule', async () => { @@ -425,7 +437,7 @@ describe('Delegate Unit', () => { await expect( delegate.connect(signer).swap(sender.address, ...order) - ).to.be.revertedWith('InsufficientSignerAmount') + ).to.be.revertedWith('InvalidSignerAmount') }) }) }) From becd52d21b8203e2eef7434b6272c6daac778463 Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Thu, 16 May 2024 17:28:31 -0400 Subject: [PATCH 42/43] zeroed out all fields in the rule when unsetting --- source/delegate/contracts/Delegate.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index a894ff621..7d70abd58 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -85,7 +85,12 @@ contract Delegate is IDelegate, Ownable { if (_senderWallet != msg.sender) revert SenderInvalid(); } Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; + rule.sender = address(0); + rule.senderToken = address(0); rule.senderAmount = 0; + rule.signerToken = address(0); + rule.signerAmount = 0; + emit UnsetRule(_senderWallet, _senderToken, _signerToken); } From 97d3d82c5e17a013f467716d9ea4487c165d366f Mon Sep 17 00:00:00 2001 From: Smart Contrart Date: Fri, 17 May 2024 22:38:05 -0400 Subject: [PATCH 43/43] Refactored rule reset on unset --- source/delegate/contracts/Delegate.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/source/delegate/contracts/Delegate.sol b/source/delegate/contracts/Delegate.sol index 7d70abd58..c005d7691 100644 --- a/source/delegate/contracts/Delegate.sol +++ b/source/delegate/contracts/Delegate.sol @@ -85,11 +85,7 @@ contract Delegate is IDelegate, Ownable { if (_senderWallet != msg.sender) revert SenderInvalid(); } Rule storage rule = rules[_senderWallet][_senderToken][_signerToken]; - rule.sender = address(0); - rule.senderToken = address(0); - rule.senderAmount = 0; - rule.signerToken = address(0); - rule.signerAmount = 0; + delete rules[_senderWallet][_senderToken][_signerToken]; emit UnsetRule(_senderWallet, _senderToken, _signerToken); }