diff --git a/contracts/spikes/core/chi/ChiGasSaver.sol b/contracts/spikes/core/chi/ChiGasSaver.sol deleted file mode 100644 index 1ade7124..00000000 --- a/contracts/spikes/core/chi/ChiGasSaver.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity 0.8.4; - -// TODO whats the best way to test this? -abstract contract IFreeFromUpTo { - function freeFromUpTo(address from, uint256 value) external virtual returns (uint256 freed); -} - -contract ChiGasSaver { - - address chiToken; - - constructor(address _chiToken) { - chiToken = _chiToken; - } - - modifier saveGas(address sponsor) { - uint256 gasStart = gasleft(); - _; - uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; - - IFreeFromUpTo(chiToken).freeFromUpTo(sponsor, (gasSpent + 14154) / 41947); - } -} diff --git a/contracts/spikes/core/chi/ChiToken.sol b/contracts/spikes/core/chi/ChiToken.sol deleted file mode 100644 index 8c5bf063..00000000 --- a/contracts/spikes/core/chi/ChiToken.sol +++ /dev/null @@ -1,428 +0,0 @@ -// SPDX-License-Identifier: MIT - -// see: https://github.com/1inch-exchange/chi/blob/master/ChiToken.full.sol - -// File: @openzeppelin/contracts/math/Math.sol - -pragma solidity 0.8.4; - -/** - * @dev Standard math utilities missing in the Solidity language. - */ -library Math { - /** - * @dev Returns the largest of two numbers. - */ - function max(uint256 a, uint256 b) internal pure returns (uint256) { - return a >= b ? a : b; - } - - /** - * @dev Returns the smallest of two numbers. - */ - function min(uint256 a, uint256 b) internal pure returns (uint256) { - return a < b ? a : b; - } - - /** - * @dev Returns the average of two numbers. The result is rounded towards - * zero. - */ - function average(uint256 a, uint256 b) internal pure returns (uint256) { - // (a + b) / 2 can overflow, so we distribute - return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); - } -} - -// File: @openzeppelin/contracts/math/SafeMath.sol - -/** - * @dev Wrappers over Solidity"s arithmetic operations with added overflow - * checks. - * - * Arithmetic operations in Solidity wrap on overflow. This can easily result - * in bugs, because programmers usually assume that an overflow raises an - * error, which is the standard behavior in high level programming languages. - * `SafeMath` restores this intuition by reverting the transaction when an - * operation overflows. - * - * Using this library instead of the unchecked operations eliminates an entire - * class of bugs, so it"s recommended to use it always. - */ -library SafeMath { - /** - * @dev Returns the addition of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity"s `+` operator. - * - * Requirements: - * - Addition cannot overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - require(c >= a, "SafeMath: addition overflow"); - - return c; - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting on - * overflow (when the result is negative). - * - * Counterpart to Solidity"s `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - return sub(a, b, "SafeMath: subtraction overflow"); - } - - /** - * @dev Returns the subtraction of two unsigned integers, reverting with custom message on - * overflow (when the result is negative). - * - * Counterpart to Solidity"s `-` operator. - * - * Requirements: - * - Subtraction cannot overflow. - */ - function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b <= a, errorMessage); - uint256 c = a - b; - - return c; - } - - /** - * @dev Returns the multiplication of two unsigned integers, reverting on - * overflow. - * - * Counterpart to Solidity"s `*` operator. - * - * Requirements: - * - Multiplication cannot overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - // Gas optimization: this is cheaper than requiring "a" not being zero, but the - // benefit is lost if "b" is also tested. - // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 - if (a == 0) { - return 0; - } - - uint256 c = a * b; - require(c / a == b, "SafeMath: multiplication overflow"); - - return c; - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity"s `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - return div(a, b, "SafeMath: division by zero"); - } - - /** - * @dev Returns the integer division of two unsigned integers. Reverts with custom message on - * division by zero. The result is rounded towards zero. - * - * Counterpart to Solidity"s `/` operator. Note: this function uses a - * `revert` opcode (which leaves remaining gas untouched) while Solidity - * uses an invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - // Solidity only automatically asserts when dividing by 0 - require(b > 0, errorMessage); - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn"t hold - - return c; - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts when dividing by zero. - * - * Counterpart to Solidity"s `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b) internal pure returns (uint256) { - return mod(a, b, "SafeMath: modulo by zero"); - } - - /** - * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), - * Reverts with custom message when dividing by zero. - * - * Counterpart to Solidity"s `%` operator. This function uses a `revert` - * opcode (which leaves remaining gas untouched) while Solidity uses an - * invalid opcode to revert (consuming all remaining gas). - * - * Requirements: - * - The divisor cannot be zero. - */ - function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { - require(b != 0, errorMessage); - return a % b; - } -} - -// File: @openzeppelin/contracts/token/ERC20/IERC20.sol - -/** - * @dev Interface of the ERC20 standard as defined in the EIP. - */ -interface IERC20 { - /** - * @dev Returns the amount of tokens in existence. - */ - function totalSupply() external view returns (uint256); - - /** - * @dev Returns the amount of tokens owned by `account`. - */ - function balanceOf(address account) external view returns (uint256); - - /** - * @dev Moves `amount` tokens from the caller"s account to `recipient`. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transfer(address recipient, uint256 amount) external returns (bool); - - /** - * @dev Returns the remaining number of tokens that `spender` will be - * allowed to spend on behalf of `owner` through {transferFrom}. This is - * zero by default. - * - * This value changes when {approve} or {transferFrom} are called. - */ - function allowance(address owner, address spender) external view returns (uint256); - - /** - * @dev Sets `amount` as the allowance of `spender` over the caller"s tokens. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * IMPORTANT: Beware that changing an allowance with this method brings the risk - * that someone may use both the old and the new allowance by unfortunate - * transaction ordering. One possible solution to mitigate this race - * condition is to first reduce the spender"s allowance to 0 and set the - * desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * - * Emits an {Approval} event. - */ - function approve(address spender, uint256 amount) external returns (bool); - - /** - * @dev Moves `amount` tokens from `sender` to `recipient` using the - * allowance mechanism. `amount` is then deducted from the caller"s - * allowance. - * - * Returns a boolean value indicating whether the operation succeeded. - * - * Emits a {Transfer} event. - */ - function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); - - /** - * @dev Emitted when `value` tokens are moved from one account (`from`) to - * another (`to`). - * - * Note that `value` may be zero. - */ - event Transfer(address indexed from, address indexed to, uint256 value); - - /** - * @dev Emitted when the allowance of a `spender` for an `owner` is set by - * a call to {approve}. `value` is the new allowance. - */ - event Approval(address indexed owner, address indexed spender, uint256 value); -} - -// File: contracts/ChiToken.sol - -abstract contract ERC20WithoutTotalSupply is IERC20 { - using SafeMath for uint256; - - mapping(address => uint256) private _balances; - mapping(address => mapping(address => uint256)) private _allowances; - - function balanceOf(address account) public view override returns (uint256) { - return _balances[account]; - } - - function allowance(address owner, address spender) public view override returns (uint256) { - return _allowances[owner][spender]; - } - - function transfer(address recipient, uint256 amount) public override returns (bool) { - _transfer(msg.sender, recipient, amount); - return true; - } - - function approve(address spender, uint256 amount) public override returns (bool) { - _approve(msg.sender, spender, amount); - return true; - } - - function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) { - _transfer(sender, recipient, amount); - uint256 allowed = _allowances[sender][msg.sender]; - if ((allowed >> 255) == 0) { - _approve(sender, msg.sender, allowed.sub(amount, "ERC20: transfer amount exceeds allowance")); - } - return true; - } - - function _transfer(address sender, address recipient, uint256 amount) internal { - _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); - _balances[recipient] = _balances[recipient].add(amount); - emit Transfer(sender, recipient, amount); - } - - function _approve(address owner, address spender, uint256 amount) internal { - _allowances[owner][spender] = amount; - emit Approval(owner, spender, amount); - } - - function _mint(address account, uint256 amount) internal { - _balances[account] = _balances[account].add(amount); - emit Transfer(address(0), account, amount); - } - - function _burn(address account, uint256 amount) internal { - _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); - emit Transfer(account, address(0), amount); - } - - function _burnFrom(address account, uint256 amount) internal { - _burn(account, amount); - uint256 allowed = _allowances[account][msg.sender]; - if ((allowed >> 255) == 0) { - _approve(account, msg.sender, allowed.sub(amount, "ERC20: burn amount exceeds allowance")); - } - } -} - - -contract ChiToken is IERC20, ERC20WithoutTotalSupply { - string constant public name = "Chi Token by 1inch"; - string constant public symbol = "CHI"; - uint8 constant public decimals = 0; - - uint256 public totalMinted; - uint256 public totalBurned; - - function totalSupply() public view override returns (uint256) { - return totalMinted - totalBurned; - } - - function mint(uint256 value) public { - uint256 offset = totalMinted; - assembly { - mstore(0, 0x746d4946c0e9F43F4Dee607b0eF1fA1c3318585733ff6000526015600bf30000) - - for {let i := div(value, 32)} i {i := sub(i, 1)} { - pop(create2(0, 0, 30, add(offset, 0))) pop(create2(0, 0, 30, add(offset, 1))) - pop(create2(0, 0, 30, add(offset, 2))) pop(create2(0, 0, 30, add(offset, 3))) - pop(create2(0, 0, 30, add(offset, 4))) pop(create2(0, 0, 30, add(offset, 5))) - pop(create2(0, 0, 30, add(offset, 6))) pop(create2(0, 0, 30, add(offset, 7))) - pop(create2(0, 0, 30, add(offset, 8))) pop(create2(0, 0, 30, add(offset, 9))) - pop(create2(0, 0, 30, add(offset, 10))) pop(create2(0, 0, 30, add(offset, 11))) - pop(create2(0, 0, 30, add(offset, 12))) pop(create2(0, 0, 30, add(offset, 13))) - pop(create2(0, 0, 30, add(offset, 14))) pop(create2(0, 0, 30, add(offset, 15))) - pop(create2(0, 0, 30, add(offset, 16))) pop(create2(0, 0, 30, add(offset, 17))) - pop(create2(0, 0, 30, add(offset, 18))) pop(create2(0, 0, 30, add(offset, 19))) - pop(create2(0, 0, 30, add(offset, 20))) pop(create2(0, 0, 30, add(offset, 21))) - pop(create2(0, 0, 30, add(offset, 22))) pop(create2(0, 0, 30, add(offset, 23))) - pop(create2(0, 0, 30, add(offset, 24))) pop(create2(0, 0, 30, add(offset, 25))) - pop(create2(0, 0, 30, add(offset, 26))) pop(create2(0, 0, 30, add(offset, 27))) - pop(create2(0, 0, 30, add(offset, 28))) pop(create2(0, 0, 30, add(offset, 29))) - pop(create2(0, 0, 30, add(offset, 30))) pop(create2(0, 0, 30, add(offset, 31))) - offset := add(offset, 32) - } - - for {let i := and(value, 0x1F)} i {i := sub(i, 1)} { - pop(create2(0, 0, 30, offset)) - offset := add(offset, 1) - } - } - - _mint(msg.sender, value); - totalMinted = offset; - } - - function computeAddress2(uint256 salt) public pure returns (address child) { - assembly { - let data := mload(0x40) - mstore(data, 0xff0000000000004946c0e9F43F4Dee607b0eF1fA1c0000000000000000000000) - mstore(add(data, 21), salt) - mstore(add(data, 53), 0x3c1644c68e5d6cb380c36d1bf847fdbc0c7ac28030025a2fc5e63cce23c16348) - child := and(keccak256(data, 85), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) - } - } - - function _destroyChildren(uint256 value) internal { - assembly { - let i := sload - (totalBurned.slot) - let end := add(i, value) - sstore(totalBurned.slot, end) - - let data := mload(0x40) - mstore(data, 0xff0000000000004946c0e9F43F4Dee607b0eF1fA1c0000000000000000000000) - mstore(add(data, 53), 0x3c1644c68e5d6cb380c36d1bf847fdbc0c7ac28030025a2fc5e63cce23c16348) - let ptr := add(data, 21) - for {} lt(i, end) {i := add(i, 1)} { - mstore(ptr, i) - pop(call(gas(), keccak256(data, 85), 0, 0, 0, 0, 0)) - } - } - } - - function free(uint256 value) public returns (uint256) { - if (value > 0) { - _burn(msg.sender, value); - _destroyChildren(value); - } - return value; - } - - function freeUpTo(uint256 value) public returns (uint256) { - return free(Math.min(value, balanceOf(msg.sender))); - } - - function freeFrom(address from, uint256 value) public returns (uint256) { - if (value > 0) { - _burnFrom(from, value); - _destroyChildren(value); - } - return value; - } - - function freeFromUpTo(address from, uint256 value) public returns (uint256) { - return freeFrom(from, Math.min(Math.min(value, balanceOf(from)), allowance(from, msg.sender))); - } -} diff --git a/contracts/spikes/core/chi/README.md b/contracts/spikes/core/chi/README.md deleted file mode 100644 index 2a573030..00000000 --- a/contracts/spikes/core/chi/README.md +++ /dev/null @@ -1,7 +0,0 @@ -https://github.com/1inch-exchange/chi/blob/master/test/ChiToken.js - -https://etherscan.io/address/0x0000000000004946c0e9F43F4Dee607b0eF1fA1c - -https://1inch-exchange.medium.com/1inch-introduces-chi-gastoken-d0bd5bb0f92b - -https://github.com/emilianobonassi/gas-saver diff --git a/test/spike/core/chi/KnownOriginDigitalAssetV3.gasSaver.test.js b/test/spike/core/chi/KnownOriginDigitalAssetV3.gasSaver.test.js deleted file mode 100644 index e796636f..00000000 --- a/test/spike/core/chi/KnownOriginDigitalAssetV3.gasSaver.test.js +++ /dev/null @@ -1,111 +0,0 @@ -const {BN, constants, expectEvent, expectRevert, balance} = require('@openzeppelin/test-helpers'); -const {ZERO_ADDRESS} = constants; - -const _ = require('lodash'); - -const web3 = require('web3'); -const {ether} = require('@openzeppelin/test-helpers'); - -const {expect} = require('chai'); - -const KnownOriginDigitalAssetV3 = artifacts.require('KnownOriginDigitalAssetV3'); -const KODAV3Marketplace = artifacts.require('KODAV3PrimaryMarketplace'); -const KOAccessControls = artifacts.require('KOAccessControls'); -const SelfServiceAccessControls = artifacts.require('SelfServiceAccessControls'); -const ChiToken = artifacts.require('ChiToken'); - -const {validateEditionAndToken} = require('../../../test-helpers'); - -contract('KODA CHI Token Tests', function (accounts) { - const [owner, minter, koCommission, contract, collectorA, collectorB, collectorC, collectorD] = accounts; - - const TOKEN_URI = 'ipfs://ipfs/Qmd9xQFBfqMZLG7RA2rXor7SA7qyJ1Pk2F2mSYzRQ2siMv'; - - const STARTING_EDITION = '10000'; - - const ETH_ONE = ether('1'); - - const firstEditionTokenId = new BN('11000'); - const secondEditionTokenId = new BN('12000'); - const thirdEditionTokenId = new BN('13000'); - const nonExistentTokenId = new BN('99999999999'); - - beforeEach(async () => { - const legacyAccessControls = await SelfServiceAccessControls.new(); - // setup access controls - this.accessControls = await KOAccessControls.new(legacyAccessControls.address, {from: owner}); - - // grab the roles - this.CONTRACT_ROLE = await this.accessControls.CONTRACT_ROLE(); - - this.chiToken = await ChiToken.new(); - - // generate some chi tokens - await this.chiToken.mint(200, {from: owner}); - await this.chiToken.mint(200, {from: contract}); - - expect(await this.chiToken.totalSupply()).to.be.bignumber.equal('400'); - - // check balances - expect(await this.chiToken.balanceOf(owner)).to.be.bignumber.equal('200'); - expect(await this.chiToken.balanceOf(contract)).to.be.bignumber.equal('200'); - - // Create token V3 - this.token = await KnownOriginDigitalAssetV3.new( - this.accessControls.address, - ZERO_ADDRESS, // no royalties address - this.chiToken.address, - STARTING_EDITION, - {from: owner} - ); - - // Approve the marketplace to spend them - await this.chiToken.approve(this.token.address, 200, {from: contract}); - await this.chiToken.approve(this.token.address, 200, {from: owner}); - - // confirm they have allowance - expect(await this.chiToken.allowance(contract, this.token.address)).to.be.bignumber.equal('200'); - expect(await this.chiToken.allowance(owner, this.token.address)).to.be.bignumber.equal('200'); - - // Set contract roles - await this.accessControls.grantRole(this.CONTRACT_ROLE, this.token.address, {from: owner}); - await this.accessControls.grantRole(this.CONTRACT_ROLE, contract, {from: owner}); - - // Create marketplace and enable in whitelist - this.marketplace = await KODAV3Marketplace.new(this.accessControls.address, this.token.address, koCommission, {from: owner}); - await this.accessControls.grantRole(this.CONTRACT_ROLE, this.marketplace.address, {from: owner}); - }); - - describe.skip('mintTokenWithGasSaver(to, uri) vs mintToken(to, uri)', () => { - - context('mintTokenWithGasSaver()', async () => { - beforeEach(async () => { - ({logs: this.logs} = await this.token.mintTokenWithGasSaver(owner, TOKEN_URI, {from: contract})); - }); - - it('GAS tokens have been burnt', async () => { - expect(await this.chiToken.balanceOf(owner)).to.be.bignumber.equal('197'); - }); - - it('emits a Transfer event', async () => { - expectEvent.inLogs(this.logs, 'Transfer', {from: ZERO_ADDRESS, to: owner, tokenId: firstEditionTokenId}); - }); - }); - - context('mintToken()', async () => { - beforeEach(async () => { - ({logs: this.logs} = await this.token.mintToken(owner, TOKEN_URI, {from: contract})); - }); - - it('GAS tokens have NOT been burnt', async () => { - expect(await this.chiToken.balanceOf(owner)).to.be.bignumber.equal('200'); - }); - - it('emits a Transfer event', () => { - expectEvent.inLogs(this.logs, 'Transfer', {from: ZERO_ADDRESS, to: owner, tokenId: firstEditionTokenId}); - }); - }); - - }); - -});