From 2688f14d0a71c2073b8798b91dff85bfd11781d6 Mon Sep 17 00:00:00 2001 From: Victor Porton Date: Wed, 17 Feb 2021 16:34:36 +0200 Subject: [PATCH] 3267: Future salaries - editorial updates (#3273) EIP-3267 changes by author --- EIPS/eip-future_salaries.md | 28 +- .../eip-3267/contracts/BaseBidOnAddresses.sol | 131 +++++ assets/eip-3267/contracts/BaseLock.sol | 510 ++++++++++++++++++ .../contracts/BaseRestorableSalary.sol | 174 ++++++ assets/eip-3267/contracts/BaseSalary.sol | 239 ++++++++ assets/eip-3267/contracts/BidOnAddresses.sol | 69 +++ assets/eip-3267/contracts/DAOInterface.sol | 13 + .../contracts/DefaultDAOInterface.sol | 16 + assets/eip-3267/contracts/ERC1155/ERC1155.sol | 414 ++++++++++++++ .../ERC1155/ERC1155TokenReceiver.sol | 14 + .../contracts/ERC1155/ERC1155WithTotals.sol | 100 ++++ .../eip-3267/contracts/ERC1155/IERC1155.sol | 30 ++ .../ERC1155/IERC1155TokenReceiver.sol | 57 ++ assets/eip-3267/contracts/ERC1155/README.md | 12 + assets/eip-3267/contracts/README.md | 15 + assets/eip-3267/contracts/Salary.sol | 28 + assets/eip-3267/contracts/SalaryWithDAO.sol | 126 +++++ assets/eip-3267/science-salaries.pdf | Bin 0 -> 99222 bytes 18 files changed, 1968 insertions(+), 8 deletions(-) create mode 100644 assets/eip-3267/contracts/BaseBidOnAddresses.sol create mode 100644 assets/eip-3267/contracts/BaseLock.sol create mode 100644 assets/eip-3267/contracts/BaseRestorableSalary.sol create mode 100644 assets/eip-3267/contracts/BaseSalary.sol create mode 100644 assets/eip-3267/contracts/BidOnAddresses.sol create mode 100644 assets/eip-3267/contracts/DAOInterface.sol create mode 100644 assets/eip-3267/contracts/DefaultDAOInterface.sol create mode 100644 assets/eip-3267/contracts/ERC1155/ERC1155.sol create mode 100644 assets/eip-3267/contracts/ERC1155/ERC1155TokenReceiver.sol create mode 100644 assets/eip-3267/contracts/ERC1155/ERC1155WithTotals.sol create mode 100644 assets/eip-3267/contracts/ERC1155/IERC1155.sol create mode 100644 assets/eip-3267/contracts/ERC1155/IERC1155TokenReceiver.sol create mode 100644 assets/eip-3267/contracts/ERC1155/README.md create mode 100644 assets/eip-3267/contracts/README.md create mode 100644 assets/eip-3267/contracts/Salary.sol create mode 100644 assets/eip-3267/contracts/SalaryWithDAO.sol create mode 100644 assets/eip-3267/science-salaries.pdf diff --git a/EIPS/eip-future_salaries.md b/EIPS/eip-future_salaries.md index d1e1ca1d..8329a3ca 100644 --- a/EIPS/eip-future_salaries.md +++ b/EIPS/eip-future_salaries.md @@ -13,7 +13,7 @@ created: 2021-02-13 Transfer a part of Ethereum transfer/mining fees to Future Salaries contract ## Abstract -Transfer a part (exact fractions - TBD) of mining/transfer fees to the `DonateETH` contract configured to transfer to `SalaryWithDAO` contract. +Transfer a part (exact fractions - TBD) of mining/transfer fees + (probably: TBD) some minted ETH to the `DonateETH` contract configured to transfer to `SalaryWithDAO` contract. ## Motivation This proposal solves two problems at once: @@ -27,29 +27,41 @@ Paradoxically, it will directly benefit miners/validators, see the discussion. ## Specification (TBD) -`SalaryWithDAO` = `TBD` +`SalaryWithDAO` = `TBD` (`address`) -`DefaultDAOInterface` = `TBD` +`DefaultDAOInterface` = `TBD` (`address`) -Prior to `FORK_BLOCK_NUMBER`, [SalaryWithDAO](https://github.com/vporton/future-contracts/blob/master/contracts/SalaryWithDAO.sol) and [DefaultDAOInterface](https://github.com/vporton/future-contracts/blob/master/contracts/DefaultDAOInterface.sol) contracts will be deployed to the network and exist at the above specified addresses. +`MintPerPeriod` = `TBD` (`uint256`) -Change the Ethereum clients to transfer at every ETH transfer and every ETH mine a fixed (the exact number - TBD) fraction of the transferred/mined ETH to a fixed account (decide the account number, it can be for example `0x00000000000000000000000000000000000000001` or even `0x00000000000000000000000000000000000000000` or a random account). Every some time (e.g. first block every UTC day - TBD how often) transfer the entire ETH from this account to the contract `DonateETH`. +`TransferFraction` = `TBD` (0..1) + +`MineFraction` = `TBD` (0..1) + +[The contracts source](../assets/eip-3267/contracts) + +Prior to `FORK_BLOCK_NUMBER`, `SalaryWithDAO` and `DefaultDAOInterface` contracts will be deployed to the network and exist at the above specified addresses. + +Change the Ethereum clients to transfer at every ETH transfer and every ETH mine a fixed fraction `TransferFraction` of the transferred ETH and `MineFraction` of the mined ETH to a fixed account (decide the account number, it can be for example `0x00000000000000000000000000000000000000001` or even `0x00000000000000000000000000000000000000000` or a random account). + +Change the Ethereum clients to mint `MintPerPeriod` ETH to the contract `DonateETH` every some time (e.g. the first transaction of the first block every UTC day - TBD how often). + +Change the Ethereum clients to every some time (e.g. the second transaction of the first block every UTC day - TBD how often) transfer the entire ETH from this account to the contract `DonateETH`. Because this EIP solves a similar problem, cancel any other EIPs that burn ETH (except gas fees) during transfers or mining. (TBD: We should transfer more ETH in this EIP than we burned accordingly older accepted EIPs, because this EIP has the additional advantages of: 1. funding common goods; 2. better aligning values of ETH and values of tokens). ## Rationale The Future Salaries is the _only_ known system of distributing significant funds to common good producers. (Quadratic funding aimed to do a similar thing, but in practice as we see on GitCoin it favors a few developers, ignores project of highly advanced scientific research that is hard to explain to an average developer, and encourages colluding, and it just highly random due to small number of donors. Also quadratic funding simply does not gather enough funds to cover common good needs). So this EIP is the only known way to recover the economy. -The economical model of Future Salaries is described in [this research article preprint](https://github.com/vporton/gitcoin-web/blob/future/app/assets/docs/science-salaries.pdf). +The economical model of Future Salaries is described in [this research article preprint](../assets/eip-3267/science-salaries.pdf). -Funding multiple oracles with different finish time would alleviate the future trouble that the circulating ETH (or other tokens) supply would suddenly increase when the oracle finishes. It would effectively exclude some ZIL from the circulation forever. +Funding multiple oracles with different finish time would alleviate the future trouble that the circulating ETH (or other tokens) supply would suddenly increase when the oracle finishes. It would effectively exclude some ETH from the circulation forever. ## Backwards Compatibility Because transferring to the aforementioned account is neither mining nor a transaction, we get a new kinds of ETH transfers, so there may be some (expected moderate impact) troubles with applications that have made assumptions about ETH transfers all occurring either as miner payments or transactions. ## Security Considerations The security considerations are: -- The DAO that controls account restoration may switch to a non-effective or biased way of voting (for example to being controlled by one human) thus distributing funds unfairly. This problem could be solved by a future fork of Zilliqa that would "confiscate" control from the DAO. +- The DAO that controls account restoration may switch to a non-effective or biased way of voting (for example to being controlled by one human) thus distributing funds unfairly. This problem could be solved by a future fork of Ethereum that would "confiscate" control from the DAO. See more in the discussion. diff --git a/assets/eip-3267/contracts/BaseBidOnAddresses.sol b/assets/eip-3267/contracts/BaseBidOnAddresses.sol new file mode 100644 index 00000000..f39deebf --- /dev/null +++ b/assets/eip-3267/contracts/BaseBidOnAddresses.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; +import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol"; +import { BaseLock } from "./BaseLock.sol"; + +/// @title Bidding on Ethereum addresses +/// @author Victor Porton +/// @notice Not audited, not enough tested. +/// This allows anyone claim conditional tokens in order for him to transfer money from the future. +/// See `docs/future-money.rst`. +abstract contract BaseBidOnAddresses is BaseLock { + using ABDKMath64x64 for int128; + using SafeMath for uint256; + + /// A condition score was stored in the chain by an oracle. + /// @param oracleId The oracle ID. + /// @param condition The conditional (customer addresses). + /// @param numerator The relative score provided by the oracle. + event ReportedNumerator( + uint64 indexed oracleId, + uint256 indexed condition, + uint256 numerator + ); + + /// Some condition scores were stored in the chain by an oracle. + /// @param oracleId The oracle ID. + /// @param conditions The conditionals (customer addresses). + /// @param numerators The relative scores provided by the oracle. + event ReportedNumeratorsBatch( + uint64 indexed oracleId, + uint64[] indexed conditions, + uint256[] numerators + ); + + // Whether an oracle finished its work. + mapping(uint64 => bool) private oracleFinishedMap; + // Mapping (oracleId => (condition => numerator)) for payout numerators. + mapping(uint64 => mapping(uint256 => uint256)) private payoutNumeratorsMap; + // Mapping (oracleId => denominator) for payout denominators. + mapping(uint256 => uint) private payoutDenominatorMap; + + /// Constructor. + /// @param _uri Our ERC-1155 tokens description URI. + constructor(string memory _uri) BaseLock(_uri) { } + + /// Retrieve the last stored payout numerator (relative score of a condition). + /// @param _oracleId The oracle ID. + /// @param _condition The condition (the original receiver of a conditional token). + /// The result can't change if the oracle has finished. + function payoutNumerator(uint64 _oracleId, uint256 _condition) public view returns (uint256) { + return payoutNumeratorsMap[_oracleId][_condition]; + } + + /// Retrieve the last stored payout denominator (the sum of all numerators of the oracle). + /// @param _oracleId The oracle ID. + /// The result can't change if the oracle has finished. + function payoutDenominator(uint64 _oracleId) public view returns (uint256) { + return payoutDenominatorMap[_oracleId]; + } + + /// Called by the oracle owner for reporting results of conditions. + /// @param _oracleId The oracle ID. + /// @param _condition The condition. + /// @param _numerator The relative score of the condition. + /// Note: We could make oracles easily verificable by a hash of all the data, but + /// - It may need allowing to set a numerator only once. + /// - It may be not necessary because future technology will allow to aggregate blockchains. + function reportNumerator(uint64 _oracleId, uint256 _condition, uint256 _numerator) external + _isOracle(_oracleId) + _oracleNotFinished(_oracleId) // otherwise an oracle can break data consistency + { + _updateNumerator(_oracleId, _numerator, _condition); + emit ReportedNumerator(_oracleId, _condition, _numerator); + } + + /// Called by the oracle owner for reporting results of several conditions. + /// @param _oracleId The oracle ID. + /// @param _conditions The conditions. + /// @param _numerators The relative scores of the condition. + function reportNumeratorsBatch(uint64 _oracleId, uint64[] calldata _conditions, uint256[] calldata _numerators) external + _isOracle(_oracleId) + _oracleNotFinished(_oracleId) // otherwise an oracle can break data consistency + { + require(_conditions.length == _numerators.length, "Length mismatch."); + for (uint _i = 0; _i < _conditions.length; ++_i) { + _updateNumerator(_oracleId, _numerators[_i], _conditions[_i]); + } + emit ReportedNumeratorsBatch(_oracleId, _conditions, _numerators); + } + + /// Need to be called after all numerators were reported. + /// @param _oracleId The oracle ID. + /// + /// You should set grace period end time before calling this method. + /// + /// TODO: Maybe it makes sense to allow to set finish time in a point of the future? + function finishOracle(uint64 _oracleId) external + _isOracle(_oracleId) + { + oracleFinishedMap[_oracleId] = true; + emit OracleFinished(_oracleId); + } + + /// Check if an oracle has finished. + /// @param _oracleId The oracle ID. + /// @return `true` if it has finished. + function isOracleFinished(uint64 _oracleId) public view override returns (bool) { + return oracleFinishedMap[_oracleId]; + } + + function _updateNumerator(uint64 _oracleId, uint256 _numerator, uint256 _condition) private { + payoutDenominatorMap[_oracleId] = payoutDenominatorMap[_oracleId].add(_numerator).sub(payoutNumeratorsMap[_oracleId][_condition]); + payoutNumeratorsMap[_oracleId][_condition] = _numerator; + } + + // Virtuals // + + function _calcRewardShare(uint64 _oracleId, uint256 _condition) internal virtual override view returns (int128) { + uint256 _numerator = payoutNumeratorsMap[_oracleId][_condition]; + uint256 _denominator = payoutDenominatorMap[_oracleId]; + return ABDKMath64x64.divu(_numerator, _denominator); + } + + // Modifiers // + + modifier _oracleNotFinished(uint64 _oracleId) { + require(!isOracleFinished(_oracleId), "Oracle is finished."); + _; + } +} diff --git a/assets/eip-3267/contracts/BaseLock.sol b/assets/eip-3267/contracts/BaseLock.sol new file mode 100644 index 00000000..ca661791 --- /dev/null +++ b/assets/eip-3267/contracts/BaseLock.sol @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol"; +import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol"; +import { ERC1155WithTotals } from "./ERC1155/ERC1155WithTotals.sol"; +import { ERC1155Holder } from "@openzeppelin/contracts/token/ERC1155/ERC1155Holder.sol"; +import { IERC1155 } from "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/ERC721Holder.sol"; + +/// @title A base class to lock collaterals and distribute them proportional to an oracle result. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +/// +/// One can also donate/bequest a smart wallet (explain how). +/// +/// We have two kinds of ERC-1155 token IDs: +/// - conditional tokens: numbers < 2**64 +/// - a combination of a collateral contract address and collateral token ID +/// (a counter of donated amount of collateral tokens, don't confuse with collateral tokens themselves) +/// +/// Inheriting from here don't forget to create `createOracle()` external method. +abstract contract BaseLock is + ERC1155WithTotals, + ERC1155Holder, // You are recommended to use `donate()` function instead. + ERC721Holder // It can be used through an ERC-1155 wrapper. +{ + using ABDKMath64x64 for int128; + using SafeMath for uint256; + + /// Emitted when an oracle is created. + /// @param oracleId The ID of the created oracle. + event OracleCreated(uint64 oracleId); + + /// Emitted when an oracle owner is set. + /// @param oracleOwner Who created an oracle + /// @param oracleId The ID of the oracle. + event OracleOwnerChanged(address indexed oracleOwner, uint64 indexed oracleId); + + /// Emitted when an oracle owner is set. + /// @param sender Who created the condition + /// @param customer The owner of the condition. + /// @param condition The created condition ID. + event ConditionCreated(address indexed sender, address indexed customer, uint256 indexed condition); + + /// Emitted when a collateral is donated. + /// @param collateralContractAddress The ERC-1155 contract of the donated token. + /// @param collateralTokenId The ERC-1155 ID of the donated token. + /// @param sender Who donated. + /// @param amount The amount donated. + /// @param to Whose account the donation is assigned to. + /// @param data Additional transaction data. + event DonateCollateral( + IERC1155 indexed collateralContractAddress, + uint256 indexed collateralTokenId, + address indexed sender, + uint256 amount, + address to, + bytes data + ); + + /// Emitted when an oracle is marked as having finished its work. + /// @param oracleId The oracle ID. + event OracleFinished(uint64 indexed oracleId); + + /// Emitted when collateral is withdrawn. + /// @param contractAddress The ERC-1155 contract of the collateral token. + /// @param collateralTokenId The ERC-1155 token ID of the collateral. + /// @param oracleId The oracle ID for which withdrawal is done. + /// @param user Who has withdrawn. + /// @param amount The amount withdrawn. + event CollateralWithdrawn( + IERC1155 indexed contractAddress, + uint256 indexed collateralTokenId, + uint64 indexed oracleId, + address user, + uint256 amount + ); + + // Next ID. + uint64 public maxOracleId; // It doesn't really need to be public. + uint64 public maxConditionId; // It doesn't really need to be public. + + // Mapping (oracleId => oracle owner). + mapping(uint64 => address) private oracleOwnersMap; + // Mapping (oracleId => time) the max time for first withdrawal. + mapping(uint64 => uint) private gracePeriodEnds; + // The user lost the right to transfer conditional tokens: (user => (conditionalToken => bool)). + mapping(address => mapping(uint256 => bool)) private userUsedRedeemMap; + // Mapping (token => (original user => amount)) used to calculate withdrawal of collateral amounts. + mapping(uint256 => mapping(address => uint256)) public lastCollateralBalanceFirstRoundMap; + // Mapping (token => (original user => amount)) used to calculate withdrawal of collateral amounts. + mapping(uint256 => mapping(address => uint256)) public lastCollateralBalanceSecondRoundMap; + /// Mapping (oracleId => amount user withdrew in first round) (see `docs/Calculations.md`). + mapping(uint64 => uint256) public usersWithdrewInFirstRound; + + // Mapping (condition ID => original account) + mapping(uint256 => address) public conditionOwners; + + /// Constructor. + /// @param _uri Our ERC-1155 tokens description URI. + constructor(string memory _uri) ERC1155WithTotals(_uri) { + _registerInterface( + BaseLock(0).onERC1155Received.selector ^ + BaseLock(0).onERC1155BatchReceived.selector ^ + BaseLock(0).onERC721Received.selector + ); + } + + /// This function makes no sense, because it would produce a condition with zero tokens. + // function createCondition() public returns (uint64) { + // return _createCondition(); + // } + + /// Modify the owner of an oracle. + /// @param _newOracleOwner New owner. + /// @param _oracleId The oracle whose owner to change. + function changeOracleOwner(address _newOracleOwner, uint64 _oracleId) public _isOracle(_oracleId) { + oracleOwnersMap[_oracleId] = _newOracleOwner; + emit OracleOwnerChanged(_newOracleOwner, _oracleId); + } + + /// Set the end time of the grace period. + /// + /// The first withdrawal can be done *only* during the grace period. + /// The second withdrawal can be done after the end of the grace period and only if the first withdrawal was done. + /// + /// The intention of the grace period is to check which of users are active ("alive"). + function updateGracePeriodEnds(uint64 _oracleId, uint _time) public _isOracle(_oracleId) { + gracePeriodEnds[_oracleId] = _time; + } + + /// Donate funds in an ERC-1155 token. + /// + /// First, the collateral token need to be approved to be spent by this contract from the address `_from`. + /// + /// It also mints a token (with a different ID), that counts donations in that token. + /// + /// @param _collateralContractAddress The collateral ERC-1155 contract address. + /// @param _collateralTokenId The collateral ERC-1155 token ID. + /// @param _oracleId The oracle ID to whose ecosystem to donate to. + /// @param _amount The amount to donate. + /// @param _from From whom to take the donation. + /// @param _to On whose account the donation amount is assigned. + /// @param _data Additional transaction data. + function donate( + IERC1155 _collateralContractAddress, + uint256 _collateralTokenId, + uint64 _oracleId, + uint256 _amount, + address _from, + address _to, + bytes calldata _data) public + { + uint _donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId); + _mint(_to, _donatedPerOracleCollateralTokenId, _amount, _data); + uint _donatedCollateralTokenId = _collateralDonatedTokenId(_collateralContractAddress, _collateralTokenId); + _mint(_to, _donatedCollateralTokenId, _amount, _data); + emit DonateCollateral(_collateralContractAddress, _collateralTokenId, _from, _amount, _to, _data); + _collateralContractAddress.safeTransferFrom(_from, address(this), _collateralTokenId, _amount, _data); // last against reentrancy attack + } + + /// Gather a DeFi profit of a token previous donated to this contact. + /// @param _collateralContractAddress The collateral ERC-1155 contract address. + /// @param _collateralTokenId The collateral ERC-1155 token ID. + /// @param _oracleId The oracle ID to whose ecosystem to donate to. + /// @param _data Additional transaction data. + /// TODO: Batch calls in several tokens and/or to several oracles for less gas usage? + function gatherDeFiProfit( + IERC1155 _collateralContractAddress, + uint256 _collateralTokenId, + uint64 _oracleId, + bytes calldata _data) external + { + uint _donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId); + uint _donatedCollateralTokenId = _collateralDonatedTokenId(_collateralContractAddress, _collateralTokenId); + + // We consider an overflow an error and just revert: + // FIXME: Impossible due to reentrancy vulnerability? (Really? It's a view!) + uint256 _difference = + _collateralContractAddress.balanceOf(address(this), _collateralTokenId).sub( + balanceOf(address(this), _donatedCollateralTokenId)); + uint256 _amount = // rounding down to prevent overflows + _difference * + balanceOf(address(this), _donatedPerOracleCollateralTokenId) / + balanceOf(address(this), _donatedCollateralTokenId); + + // Last to avoid reentrancy vulnerability. + donate( + _collateralContractAddress, + _collateralTokenId, + _oracleId, + _amount, + address(this), + address(this), + _data); + } + + /// Calculate how much collateral is owed to a user. + /// @param _collateralContractAddress The ERC-1155 collateral token contract. + /// @param _collateralTokenId The ERC-1155 collateral token ID. + /// @param _oracleId From which oracle's "account" to withdraw. + /// @param _condition The condition (the original receiver of a conditional token). + /// @param _user The user to which we may owe. + function collateralOwing( + IERC1155 _collateralContractAddress, + uint256 _collateralTokenId, + uint64 _oracleId, + uint256 _condition, + address _user + ) external view returns(uint256) { + bool _inFirstRound = _isInFirstRound(_oracleId); + (, uint256 _donated) = + _collateralOwingBase(_collateralContractAddress, _collateralTokenId, _oracleId, _condition, _user, _inFirstRound); + return _donated; + } + + /// Transfer to `msg.sender` the collateral ERC-1155 token. + /// + /// The amount transferred is proportional to the score of `_condition` by the oracle. + /// @param _collateralContractAddress The ERC-1155 collateral token contract. + /// @param _collateralTokenId The ERC-1155 collateral token ID. + /// @param _oracleId From which oracle's "account" to withdraw. + /// @param _condition The condition. + /// @param _data Additional data. + /// + /// Notes: + /// - It is made impossible to withdraw somebody's other collateral, as otherwise we can't mark non-active + /// accounts in grace period. + /// - We can't transfer to somebody other than `msg.sender` because anybody can transfer + /// (needed for multi-level transfers). + /// - After this function is called, it becomes impossible to transfer the corresponding conditional token + /// of `msg.sender` (to prevent its repeated withdrawal). + function withdrawCollateral( + IERC1155 _collateralContractAddress, + uint256 _collateralTokenId, + uint64 _oracleId, + uint256 _condition, + bytes calldata _data) external + { + require(isOracleFinished(_oracleId), "too early"); // to prevent the denominator or the numerators change meantime + bool _inFirstRound = _isInFirstRound(_oracleId); + userUsedRedeemMap[msg.sender][_condition] = true; + // _burn(msg.sender, _condition, conditionalBalance); // Burning it would break using the same token for multiple markets. + (uint _donatedPerOracleCollateralTokenId, uint256 _owingDonated) = + _collateralOwingBase(_collateralContractAddress, _collateralTokenId, _oracleId, _condition, msg.sender, _inFirstRound); + + // Against rounding errors. Not necessary because of rounding down. + // if(_owing > balanceOf(address(this), _collateralTokenId)) _owing = balanceOf(address(this), _collateralTokenId); + + if (_owingDonated != 0) { + uint256 _newTotal = totalSupply(_donatedPerOracleCollateralTokenId); + if (_inFirstRound) { + lastCollateralBalanceFirstRoundMap[_donatedPerOracleCollateralTokenId][msg.sender] = _newTotal; + } else { + lastCollateralBalanceSecondRoundMap[_donatedPerOracleCollateralTokenId][msg.sender] = _newTotal; + } + } + if (!_inFirstRound) { + usersWithdrewInFirstRound[_oracleId] = usersWithdrewInFirstRound[_oracleId].add(_owingDonated); + } + // Last to prevent reentrancy attack: + _collateralContractAddress.safeTransferFrom(address(this), msg.sender, _collateralTokenId, _owingDonated, _data); + emit CollateralWithdrawn( + _collateralContractAddress, + _collateralTokenId, + _oracleId, + msg.sender, + _owingDonated + ); + } + + /// An ERC-1155 function. + /// + /// We disallow transfers of conditional tokens after redeem `_to` prevent "gathering" them before redeeming + /// each oracle. + function safeTransferFrom( + address _from, + address _to, + uint256 _id, + uint256 _value, + bytes calldata _data + ) + public override + { + _checkTransferAllowed(_id, _from); + _baseSafeTransferFrom(_from, _to, _id, _value, _data); + } + + /// An ERC-1155 function. + /// + /// We disallow transfers of conditional tokens after redeem `_to` prevent "gathering" them before redeeming + /// each oracle. + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) + public override + { + for(uint _i = 0; _i < _ids.length; ++_i) { + _checkTransferAllowed(_ids[_i], _from); + } + _baseSafeBatchTransferFrom(_from, _to, _ids, _values, _data); + } + + // Getters // + + /// Get the oracle owner. + /// @param _oracleId The oracle ID. + function oracleOwner(uint64 _oracleId) public view returns (address) { + return oracleOwnersMap[_oracleId]; + } + + /// Is the oracle marked as having finished its work? + /// + /// `oracleId` is the oracle ID. + function isOracleFinished(uint64 /*oracleId*/) public virtual view returns (bool) { + return true; + } + + /// Are transfers of a conditinal token locked? + /// + /// This is used to prevent its repeated withdrawal. + /// @param _user Querying if locked for this user. + /// @param _condition The condition (the original receiver of a conditional token). + function isConditionalLocked(address _user, uint256 _condition) public view returns (bool) { + return userUsedRedeemMap[_user][_condition]; + } + + /// Retrieve the end of the grace period. + /// @param _oracleId For which oracle. + function gracePeriodEnd(uint64 _oracleId) public view returns (uint) { + return gracePeriodEnds[_oracleId]; + } + + // Virtual functions // + + /// Current address of a user. + /// @param _originalAddress The original address of the user. + function originalToCurrentAddress(address _originalAddress) internal virtual returns (address) { + return _originalAddress; + } + + /// Mint a conditional to a customer. + function _mintToCustomer(address _customer, uint256 _condition, uint256 _amount, bytes calldata _data) + internal virtual + { + require(conditionOwners[_condition] == _customer, "Other's salary get attempt."); + _mint(originalToCurrentAddress(_customer), _condition, _amount, _data); + } + + /// Calculate the share of a condition in an oracle's market. + /// @param _oracleId The oracle ID. + /// @return Uses `ABDKMath64x64` number ID. + function _calcRewardShare(uint64 _oracleId, uint256 _condition) internal virtual view returns (int128); + + function _calcMultiplier(uint64 _oracleId, uint256 _condition, int128 _oracleShare) internal virtual view returns (int128) { + int128 _rewardShare = _calcRewardShare(_oracleId, _condition); + return _oracleShare.mul(_rewardShare); + } + + function _doTransfer(uint256 _id, address _from, address _to, uint256 _value) internal virtual { + _balances[_id][_from] = _balances[_id][_from].sub(_value); + _balances[_id][_to] = _value.add(_balances[_id][_to]); + } + + // Internal // + + /// Generate the ERC-1155 token ID that counts amount of donations per oracle for a ERC-1155 collateral token. + /// @param _collateralContractAddress The ERC-1155 contract of the collateral token. + /// @param _collateralTokenId The ERC-1155 ID of the collateral token. + /// @param _oracleId The oracle ID. + /// Note: It does not conflict with other tokens kinds, because the only other one is the uint64 conditional. + function _collateralDonatedPerOracleTokenId(IERC1155 _collateralContractAddress, uint256 _collateralTokenId, uint64 _oracleId) + internal pure returns (uint256) + { + return uint256(keccak256(abi.encodePacked(_collateralContractAddress, _collateralTokenId, _oracleId))); + } + + /// Generate the ERC-1155 token ID that counts amount of donations for a ERC-1155 collateral token. + /// @param _collateralContractAddress The ERC-1155 contract of the collateral token. + /// @param _collateralTokenId The ERC-1155 ID of the collateral token. + /// Note: It does not conflict with other tokens kinds, because the only other one is the uint64 conditional. + function _collateralDonatedTokenId(IERC1155 _collateralContractAddress, uint256 _collateralTokenId) + internal pure returns (uint256) + { + return uint256(keccak256(abi.encodePacked(_collateralContractAddress, _collateralTokenId))); + } + + function _checkTransferAllowed(uint256 _id, address _from) internal view { + require(!userUsedRedeemMap[_from][_id], "You can't trade conditional tokens after redeem."); + } + + function _baseSafeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes memory _data) private { + require(_to != address(0), "ERC1155: target address must be non-zero"); + require( + _from == msg.sender || _operatorApprovals[_from][msg.sender] == true, + "ERC1155: need operator approval for 3rd party transfers." + ); + + _doTransfer(_id, _from, _to, _value); + + emit TransferSingle(msg.sender, _from, _to, _id, _value); + + _doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data); + } + + function _baseSafeBatchTransferFrom( + address _from, + address _to, + uint256[] memory _ids, + uint256[] memory _values, + bytes memory _data + ) + private + { + require(_ids.length == _values.length, "ERC1155: IDs and _values must have same lengths"); + require(_to != address(0), "ERC1155: target address must be non-zero"); + require( + _from == msg.sender || _operatorApprovals[_from][msg.sender] == true, + "ERC1155: need operator approval for 3rd party transfers." + ); + + for (uint256 _i = 0; _i < _ids.length; ++_i) { + uint256 _id = _ids[_i]; + uint256 _value = _values[_i]; + + _doTransfer(_id, _from, _to, _value); + } + + emit TransferBatch(msg.sender, _from, _to, _ids, _values); + + _doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data); + } + + function _createOracle() internal returns (uint64) { + uint64 _oracleId = ++maxOracleId; + oracleOwnersMap[_oracleId] = msg.sender; + emit OracleCreated(_oracleId); + emit OracleOwnerChanged(msg.sender, _oracleId); + return _oracleId; + } + + /// Start with 1, not 0, to avoid glitch with `conditionalTokens` variable. + /// + /// TODO: Use uint64 variables instead? + function _createCondition(address _customer) internal returns (uint256) { + return _doCreateCondition(_customer); + } + + /// Start with 1, not 0, to avoid glitch with `conditionalTokens` variable. + /// + /// TODO: Use uint64 variables instead? + function _doCreateCondition(address _customer) internal virtual returns (uint256) { + uint64 _condition = ++maxConditionId; + + conditionOwners[_condition] = _customer; + + emit ConditionCreated(msg.sender, _customer, _condition); + + return _condition; + } + + function _collateralOwingBase( + IERC1155 _collateralContractAddress, + uint256 _collateralTokenId, + uint64 _oracleId, + uint256 _condition, + address _user, + bool _inFirstRound + ) + private view returns (uint _donatedPerOracleCollateralTokenId, uint256 _donated) + { + uint256 _conditionalBalance = balanceOf(_user, _condition); + uint256 _totalConditionalBalance = + _inFirstRound ? totalSupply(_condition) : usersWithdrewInFirstRound[_oracleId]; + _donatedPerOracleCollateralTokenId = _collateralDonatedPerOracleTokenId(_collateralContractAddress, _collateralTokenId, _oracleId); + // Rounded to below for no out-of-funds: + int128 _oracleShare = ABDKMath64x64.divu(_conditionalBalance, _totalConditionalBalance); + uint256 _newDividendsDonated = + totalSupply(_donatedPerOracleCollateralTokenId) - + (_inFirstRound + ? lastCollateralBalanceFirstRoundMap[_donatedPerOracleCollateralTokenId][_user] + : lastCollateralBalanceSecondRoundMap[_donatedPerOracleCollateralTokenId][_user]); + int128 _multiplier = _calcMultiplier(_oracleId, _condition, _oracleShare); + _donated = _multiplier.mulu(_newDividendsDonated); + } + + function _isInFirstRound(uint64 _oracleId) internal view returns (bool) { + return block.timestamp <= gracePeriodEnds[_oracleId]; + } + + function _isConditional(uint256 _tokenId) internal pure returns (bool) { + // Zero 2**-192 probability that tokenId < (1<<64) if it's not a conditional. + // Note to auditor: It's a hack, check for no errors carefully. + return _tokenId < (1<<64); + } + + modifier _isOracle(uint64 _oracleId) { + require(oracleOwnersMap[_oracleId] == msg.sender, "Not the oracle owner."); + _; + } + + modifier checkIsConditional(uint256 _tokenId) { + require(_isConditional(_tokenId), "It's not your conditional."); + _; + } +} diff --git a/assets/eip-3267/contracts/BaseRestorableSalary.sol b/assets/eip-3267/contracts/BaseRestorableSalary.sol new file mode 100644 index 00000000..2916b6c8 --- /dev/null +++ b/assets/eip-3267/contracts/BaseRestorableSalary.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "./Salary.sol"; + +/// @author Victor Porton +/// @notice Not audited, not enough tested. +/// A base class for salary with receiver accounts that can be restored by an "attorney". +abstract contract BaseRestorableSalary is BaseSalary { + // INVARIANT: `_originalAddress(newToOldAccount[newAccount]) == _originalAddress(newAccount)` + // if `newToOldAccount[newAccount] != address(0)` for every `newAccount` + // INVARIANT: originalAddresses and originalToCurrentAddresses are mutually inverse. + // That is: + // - `originalAddresses[originalToCurrentAddresses[x]] == x` if `originalToCurrentAddresses[x] != address(0)` + // - `originalToCurrentAddresses[originalAddresses[x]] == x` if `originalAddresses[x] != address(0)` + + /// Mapping (current address => very first address an account had). + mapping(address => address) public originalAddresses; + + /// Mapping (very first address an account had => current address). + mapping(address => address) public originalToCurrentAddresses; + + // Mapping from old to new account addresses (created after every change of an address). + mapping(address => address) public newToOldAccount; + + /// Constructor. + /// @param _uri Our ERC-1155 tokens description URI. + constructor (string memory _uri) BaseSalary(_uri) { } + + /// Below copied from https://github.com/vporton/restorable-funds/blob/f6192fd23cad529b84155d52ae202430cd97db23/contracts/RestorableERC1155.sol + + /// Give the user the "permission" to move funds from `_oldAccount` to `_newAccount`. + /// + /// This function is intended to be called by an attorney or the user to move to a new account. + /// @param _oldAccount is a current address. + /// @param _newAccount is a new address. + function permitRestoreAccount(address _oldAccount, address _newAccount) public { + if (msg.sender != _oldAccount) { + checkAllowedRestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs + } + _avoidZeroAddressManipulatins(_oldAccount, _newAccount); + address _orig = _originalAddress(_oldAccount); + + // We don't disallow joining several accounts together to consolidate salaries for different projects. + // require(originalAddresses[_newAccount] == 0, "Account is taken.") + + newToOldAccount[_newAccount] = _oldAccount; + originalAddresses[_newAccount] = _orig; + originalToCurrentAddresses[_orig] = _newAccount; + // Auditor: Check that the above invariant hold. + emit AccountRestored(_oldAccount, _newAccount); + } + + /// Retire the user's "permission" to move funds from `_oldAccount` to `_newAccount`. + /// + /// This function is intended to be called by an attorney. + /// @param _oldAccount is an old current address. + /// @param _newAccount is a new address. + /// (In general) it isn't allowed to be called by `msg.sender == _oldAccount`, + /// because it would allow to keep stealing the salary by hijacked old account. + function dispermitRestoreAccount(address _oldAccount, address _newAccount) public { + checkAllowedUnrestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs + _avoidZeroAddressManipulatins(_oldAccount, _newAccount); + newToOldAccount[_newAccount] = address(0); + originalToCurrentAddresses[_oldAccount] = address(0); + originalAddresses[_newAccount] = address(0); + // Auditor: Check that the above invariants hold. + emit AccountUnrestored(_oldAccount, _newAccount); + } + + /// Move the entire balance of a token from an old account to a new account of the same user. + /// @param _oldAccount Old account. + /// @param _newAccount New account. + /// @param _token The ERC-1155 token ID. + /// This function can be called by the affected user. + /// + /// Remark: We don't need to create new tokens like as on a regular transfer, + /// because it isn't a transfer to a trader. + function restoreFunds(address _oldAccount, address _newAccount, uint256 _token) public + checkMovedOwner(_oldAccount, _newAccount) + { + uint256 _amount = _balances[_token][_oldAccount]; + + _balances[_token][_newAccount] = _balances[_token][_oldAccount]; + _balances[_token][_oldAccount] = 0; + + emit TransferSingle(_msgSender(), _oldAccount, _newAccount, _token, _amount); + } + + /// Move the entire balance of tokens from an old account to a new account of the same user. + /// @param _oldAccount Old account. + /// @param _newAccount New account. + /// @param _tokens The ERC-1155 token IDs. + /// This function can be called by the affected user. + /// + /// Remark: We don't need to create new tokens like as on a regular transfer, + /// because it isn't a transfer to a trader. + function restoreFundsBatch(address _oldAccount, address _newAccount, uint256[] calldata _tokens) public + checkMovedOwner(_oldAccount, _newAccount) + { + uint256[] memory _amounts = new uint256[](_tokens.length); + for (uint _i = 0; _i < _tokens.length; ++_i) { + uint256 _token = _tokens[_i]; + uint256 _amount = _balances[_token][_oldAccount]; + _amounts[_i] = _amount; + + _balances[_token][_newAccount] = _balances[_token][_oldAccount]; + _balances[_token][_oldAccount] = 0; + } + + emit TransferBatch(_msgSender(), _oldAccount, _newAccount, _tokens, _amounts); + } + + // Internal functions // + + function _avoidZeroAddressManipulatins(address _oldAccount, address _newAccount) internal view { + // To avoid make-rich-quick manipulations with lost funds: + require(_oldAccount != address(0) && _newAccount != address(0) && + originalAddresses[_newAccount] != address(0) && newToOldAccount[_newAccount] != address(0), + "Trying to get nobody's funds."); + } + + // Virtual functions // + + /// Check if `msg.sender` is an attorney allowed to restore a user's account. + function checkAllowedRestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) public virtual; + + /// Check if `msg.sender` is an attorney allowed to unrestore a user's account. + function checkAllowedUnrestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) public virtual; + + /// Find the original address of a given account. + /// This function is internal, because it can be calculated off-chain. + /// @param _account The current address. + function _originalAddress(address _account) internal view virtual returns (address) { + address _newAddress = originalAddresses[_account]; + return _newAddress != address(0) ? _newAddress : _account; + } + + // Find the current address for an original address. + // @param _conditional The original address. + function originalToCurrentAddress(address _customer) internal virtual override returns (address) { + address current = originalToCurrentAddresses[_customer]; + return current != address(0) ? current : _customer; + } + + // TODO: Is the following function useful to save gas in other contracts? + // function getCurrent(address _account) public returns (uint256) { + // address _original = originalAddresses[_account]; + // return _original == 0 ? 0 : originalToCurrentAddress(_original); + // } + + // Modifiers // + + /// Check that `_newAccount` is the user that has the right to restore funds from `_oldAccount`. + /// + /// We also allow funds restoration by attorneys for convenience of users. + /// This is not an increased security risk, because a dishonest attorney can anyway transfer money to himself. + modifier checkMovedOwner(address _oldAccount, address _newAccount) virtual { + if (_msgSender() != _newAccount) { + checkAllowedRestoreAccount(_oldAccount, _newAccount); // only authorized "attorneys" or attorney DAOs + } + + for (address _account = _oldAccount; _account != _newAccount; _account = newToOldAccount[_account]) { + require(_account != address(0), "Not a moved owner"); + } + + _; + } + + // Events // + + event AccountRestored(address indexed oldAccount, address indexed newAccount); + + event AccountUnrestored(address indexed oldAccount, address indexed newAccount); +} diff --git a/assets/eip-3267/contracts/BaseSalary.sol b/assets/eip-3267/contracts/BaseSalary.sol new file mode 100644 index 00000000..276b9736 --- /dev/null +++ b/assets/eip-3267/contracts/BaseSalary.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "./BaseBidOnAddresses.sol"; + +/// @title Base class for a "salary" that is paid one token per second using minted conditionals. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +/// It was considered to allow the DAO to adjust registration date to pay salary retrospectively, +/// but this seems giving too much rights to the DAO similarly as if it had the right to declare anyone dead. +/// +/// It would cause this effect: A scientist who is already great may register then his date is moved back +/// in time and instantly he or she receives a very big sum of money to his account. +/// If it is done erroneously, there may be no way to move the registration date again forward in time, +/// because the tokens may be already withdrawn. And it cannot be done in a fully decentralized way because +/// it needs oracles. So errors are seem inevitable. +/// On the other hand, somebody malicious may create and register in my system a pool of Ethereum addresses that +/// individuals can receive from them as if they themselves registered in the past. +/// So it in some cases (if the registration date is past the contract deployment) this issue is impossible to +/// mitigate. +/// +/// The salary is paid in minted tokens groups into "chains": +/// the original salary token and anyone can replace it by another token, next in the chain. +contract BaseSalary is BaseBidOnAddresses { + /// Salary receiver registered. + /// @param customer The customer address. + /// @param oracleId The oracle ID for which he registers. + /// @param data Additional data. + event CustomerRegistered( + address indexed customer, + uint64 indexed oracleId, + uint256 indexed condition, + bytes data + ); + + /// Salary tokens minted. + /// @param customer The customer address. + /// @param oracleId The oracle ID. + /// @param amount The minted amount. + /// @param data Additional data. + event SalaryMinted( + address indexed customer, + uint64 indexed oracleId, + uint256 indexed condition, + uint256 amount, + bytes data + ); + + /// Salary token recreated (salary recalculation request). + /// @param customer The customer address. + /// @param originalCondition The original token ID. + /// @param newCondition The new token ID. + event ConditionReCreate( + address indexed customer, + uint256 indexed originalCondition, + uint256 indexed newCondition + ); + + // Mapping (condition ID => registration time). + mapping(uint256 => uint) public conditionCreationDates; + // Mapping (condition ID => salary block time). + mapping(uint256 => uint) public lastSalaryDates; + /// Mapping (condition ID => account) - salary recipients. + mapping(uint256 => address) public salaryReceivers; + + /// Mapping (condition ID => first condition ID in the chain) + /// + /// I call _chain_ of conditions the list of conditions resulting from creating and recreating conditions. + mapping(uint256 => uint256) public firstConditionInChain; + /// Mapping (first condition ID in the chain => last condition ID in the chain) + /// + /// I call _chain_ of conditions the list of conditions resulting from creating and recreating conditions. + mapping(uint256 => uint256) public firstToLastConditionInChain; + + /// Constructor. + /// @param _uri The ERC-1155 token URI. + constructor(string memory _uri) BaseBidOnAddresses(_uri) { } + + /// Mint a salary token. + /// @param _oracleId The oracle ID. + /// @param _condition The condition ID. + /// @param _data Additional data. + /// This method can be called only by the salary receiver. + function mintSalary(uint64 _oracleId, uint256 _condition, bytes calldata _data) + ensureLastConditionInChain(_condition) external + { + uint _lastSalaryDate = lastSalaryDates[_condition]; + require(_lastSalaryDate != 0, "You are not registered."); + // Note: Even if you withdraw once per 20 years, you will get only 630,720,000 tokens. + // This number is probably not to big to be displayed well in UIs. + uint256 _amount = (block.timestamp - _lastSalaryDate) * 10**18; // one token per second + _mintToCustomer(msg.sender, firstToLastConditionInChain[_condition], _amount, _data); + lastSalaryDates[_condition] = block.timestamp; + emit SalaryMinted(msg.sender, _oracleId, _condition, _amount, _data); + } + + /// Make a new condition that replaces the old one. + /// + /// In other words, it is a request to recalculate somebody's salary. + /// + /// Anyone can request to recalculate anyone's salary. + /// + /// It's also useful to punish someone for decreasing his work performance or an evil act. + /// This is to be called among other when a person dies. + /// + /// Recalculation is also forced when a salary receiver transfers away his current salary token. + /// It is useful to remove a trader's incentive to kill the issuer to reduce the circulating supply. + /// + /// Issue to solve later: Should we recommend: + /// - calling this function on each new project milestone? + /// - calling this function regularly (e.g. every week)? + /// + /// This function also withdraws the old token. + function recreateCondition(uint256 _condition) public returns (uint256) { + return _recreateCondition(_condition); + } + + function _doCreateCondition(address _customer) internal virtual override returns (uint256) { + uint256 _condition = super._doCreateCondition(_customer); + salaryReceivers[_condition] = _customer; + conditionCreationDates[_condition] = block.timestamp; + firstConditionInChain[_condition] = _condition; + firstToLastConditionInChain[_condition] = _condition; + return _condition; + } + + /// Make a new condition that replaces the old one. + /// The same can be done by transferring to yourself 0 tokens, but this method uses less gas. + /// + /// We need to create a new condition every time when an outgoimg transfer of a conditional token happens. + /// Otherwise an investor would gain if he kills a scientist to reduce the circulating supply of his token to increase the price. + /// Allowing old tokens to be exchangeable for new ones? (Allowing the reverse swap would create killer's gain.) + /// Additional benefit of this solution: We can have different rewards at different stages of project, + /// what may be beneficial for early startups funding. + /// + /// Problem to be solved later: There should be an advice to switch to a new token at each milestone of a project? + /// + /// Anyone can create a ERC-1155 contract that allows to use any of the tokens in the list + /// by locking any of the tokens in the list as a new "general" token. We should recommend customers not to + /// use such contracts, because it creates for them the killer exploit. + /// + /// If we would exchange the old and new tokens for the same amounts of collaterals, then it would be + /// effectively the same token and therefore minting more new token would possibly devalue the old one, + /// thus triggering the killer's exploit again. So we make old and new completely independent. + /// + /// Old token is 1:1 converted to the new token. + /// + /// Remark: To make easy to exchange the token even if it is recreated, we can make a wrapper or locker + /// token that uses `firstConditionInChain[]` to aggregate several tokens together. + /// A similar wrapper (the customer need to `setApprovalForAll()` on it) that uses + /// `firstToLastConditionInChain[]` can be used to transfer away recreated tokens + /// even if an evil DAO tries to frontrun the customer by recreating his tokens very often. + /// TODO: Test that it's possible to create such a locker. + /// + /// Note: That wrapper could be carelessly used to create the investor's killing customer incentive + /// by the customer using it to transfer to an investor. Even if the customer uses it only for + /// exchanges, an investor can buy at an exchange and be a killer. + /// To make it safe, it must stop accepting any new tokens after a transfer. + /// It can determine if a token is new just comparing by `<` operator. + /// It's strongly recommended that an app that uses this contract provides its own swap/exchange UI + /// and warns the user not to use arbitrary exchanges as being an incentive to kill the user. + /// + /// We allow anybody (not just the account owner or DAO) to recreate a condition, because: + /// - Exchanges can create a "composite" token that allows to withdraw any of the tokens in the chain + /// up to a certain period of time (using on-chain `conditionCreationDates`). + /// - Therefore somebody's token can be withdrawn even if its ID changes arbitrarily often. + /// + /// @param _condition The condition ID. + function _recreateCondition(uint256 _condition) + internal ensureFirstConditionInChain(_condition) returns (uint256) + { + address _customer = salaryReceivers[_condition]; + uint256 _oldCondition = firstToLastConditionInChain[_condition]; + uint256 _newCondition = _doCreateCondition(_customer); + firstConditionInChain[_newCondition] = _condition; + + uint256 _amount = _balances[_oldCondition][_customer]; + _balances[_newCondition][_customer] = _amount; + _balances[_oldCondition][_customer] = 0; + + // TODO: Should we swap two following lines? + emit TransferSingle(msg.sender, _customer, address(0), _condition, _amount); + emit TransferSingle(msg.sender, address(0), _customer, _newCondition, _amount); + + lastSalaryDates[_newCondition] = lastSalaryDates[_condition]; + // TODO: Should we here set `lastSalaryDates[_condition] = 0` to save storage space? // TODO: It would also eliminate the need to check in mint function. + + emit ConditionReCreate(_customer, _condition, _newCondition); + return _newCondition; + } + + /// Check if it is the first condition in a chain of conditions. + /// @param _id The condition ID. + /// + /// Must be called with `_id != 0`. + function isFirstConditionInChain(uint256 _id) internal view returns (bool) { + return firstConditionInChain[_id] == _id; + } + + /// Check if it is the last condition in a chain of conditions. + /// @param _id The condition ID. + /// + /// Must be called with `_id != 0`. + /// + /// TODO: Should make this function public? + function isLastConditionInChain(uint256 _id) internal view returns (bool) { + return firstToLastConditionInChain[firstConditionInChain[_id]] == _id; + } + + function _doTransfer(uint256 _id, address _from, address _to, uint256 _value) internal virtual override { + super._doTransfer(_id, _from, _to, _value); + + if (_id != 0 && salaryReceivers[_id] == msg.sender) { + if (isLastConditionInChain(_id)) { // correct because `_id != 0` + _recreateCondition(_id); + } + } + } + + function _registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data) + virtual internal returns (uint256) + { + uint256 _condition = _doCreateCondition(_customer); + lastSalaryDates[_condition] = block.timestamp; + emit CustomerRegistered(msg.sender, _oracleId, _condition, _data); + return _condition; + } + + modifier ensureFirstConditionInChain(uint256 _id) { + // TODO: Is `_id != 0` check needed? + require(_isConditional(_id) && _id != 0 && isFirstConditionInChain(_id), "Only for the last salary token."); + _; + } + + modifier ensureLastConditionInChain(uint256 _id) { + // TODO: Is `_id != 0` check needed? + require(_isConditional(_id) && _id != 0 && isLastConditionInChain(_id), "Only for the last salary token."); + _; + } +} diff --git a/assets/eip-3267/contracts/BidOnAddresses.sol b/assets/eip-3267/contracts/BidOnAddresses.sol new file mode 100644 index 00000000..baeb637c --- /dev/null +++ b/assets/eip-3267/contracts/BidOnAddresses.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "./BaseBidOnAddresses.sol"; + +/// @title Bidding on Ethereum addresses +/// @author Victor Porton +/// @notice Not audited, not enough tested. +/// This allows anyone to claim 1000 conditional tokens in order for him to transfer money from the future. +/// See `docs/future-money.rst` and anyone to donate. +/// +/// We have two kinds of ERC-1155 token IDs: +/// - conditional tokens: numbers < 2**64 +/// - a combination of a collateral contract address and collateral token ID +/// (a counter of donated amount of collateral tokens, don't confuse with collateral tokens themselves) +/// +/// In functions of this contact `condition` is always a customer's original address. +/// +/// We receive funds in ERC-1155, see also https://github.com/vporton/wrap-tokens +contract BidOnAddresses is BaseBidOnAddresses { + uint constant INITIAL_CUSTOMER_BALANCE = 1000 * 10**18; // an arbitrarily chosen value + + /// Customer registered. + /// @param sender `msg.sender`. + /// @param customer The customer address. + /// @param data Additional data. + event CustomerRegistered( + address indexed sender, + address indexed customer, + uint256 indexed condition, + bytes data + ); + + /// @param _uri The ERC-1155 token URI. + constructor(string memory _uri) BaseBidOnAddresses(_uri) { + _registerInterface( + BidOnAddresses(0).onERC1155Received.selector ^ + BidOnAddresses(0).onERC1155BatchReceived.selector + ); + } + + /// Anyone can register anyone. + /// + /// This can be called both before or after the oracle finish. However registering after the finish is useless. + /// + /// We check that `oracleId` exists (we don't want "spammers" to register themselves for a million oracles). + /// + /// We allow anyone to register anyone. This is useful for being registered by robots. + /// At first it seems to be harmful to make somebody a millionaire unwillingly (he then needs a fortress and bodyguards), + /// but: Salary tokens will be worth real money, only if the registered person publishes his works together + /// with his Ethereum address. So, he can be made rich against his will only by impersonating him. But if somebody + /// impersonates him, then they are able to present him richer than he is anyway, so making him vulnerable to + /// kidnappers anyway. So having somebody registered against his will seems not to be a problem at all + /// (except that he will see superfluous worthless tokens in Etherscan data of his account.) + /// + /// An alternative way would be to make registration gasless but requiring a registrant signature. + /// This is not very good, probably: + /// - It requires to install MetaMask. + /// - It bothers the person to sign something, when he could just be hesitant to get what he needs. + /// - It somehow complicates this contract. + /// @param _customer The address of the customer. // TODO: current or original + /// @param _oracleId The oracle ID. + /// @param _data Additional data. + function registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data) external { + require(_oracleId <= maxOracleId, "Oracle doesn't exist."); + uint256 _condition = _createCondition(_customer); + _mintToCustomer(_customer, _condition, INITIAL_CUSTOMER_BALANCE, _data); + emit CustomerRegistered(msg.sender, _customer, _condition, _data); + } +} diff --git a/assets/eip-3267/contracts/DAOInterface.sol b/assets/eip-3267/contracts/DAOInterface.sol new file mode 100644 index 00000000..86417857 --- /dev/null +++ b/assets/eip-3267/contracts/DAOInterface.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; + +/// @notice The "DAO plugin" interface. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +interface DAOInterface { + /// Check if `msg.sender` is an attorney allowed to restore a given account. + function checkAllowedRestoreAccount(address _oldAccount, address _newAccount) external; + + /// Check if `msg.sender` is an attorney allowed to unrestore a given account. + function checkAllowedUnrestoreAccount(address _oldAccount, address _newAccount) external; +} diff --git a/assets/eip-3267/contracts/DefaultDAOInterface.sol b/assets/eip-3267/contracts/DefaultDAOInterface.sol new file mode 100644 index 00000000..79cf6838 --- /dev/null +++ b/assets/eip-3267/contracts/DefaultDAOInterface.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "./DAOInterface.sol"; + +/// @notice "Default" contract for `DAOInterface`. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +contract DefaultDAOInterface is DAOInterface { + function checkAllowedRestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) external pure override { + revert("unimplemented"); + } + + function checkAllowedUnrestoreAccount(address /*_oldAccount*/, address /*_newAccount*/) external pure override { + revert("unimplemented"); + } +} diff --git a/assets/eip-3267/contracts/ERC1155/ERC1155.sol b/assets/eip-3267/contracts/ERC1155/ERC1155.sol new file mode 100644 index 00000000..de4637f9 --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/ERC1155.sol @@ -0,0 +1,414 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >=0.6.0 <0.8.0; + +import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155MetadataURI.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import "@openzeppelin/contracts/GSN/Context.sol"; +import "@openzeppelin/contracts/introspection/ERC165.sol"; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; + +/** + * + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { + using SafeMath for uint256; + using Address for address; + + // Mapping from token ID to account balances + mapping (uint256 => mapping(address => uint256)) internal _balances; + + // Mapping from account to operator approvals + mapping (address => mapping(address => bool)) internal _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /* + * bytes4(keccak256('balanceOf(address,uint256)')) == 0x00fdd58e + * bytes4(keccak256('balanceOfBatch(address[],uint256[])')) == 0x4e1273f4 + * bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465 + * bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5 + * bytes4(keccak256('safeTransferFrom(address,address,uint256,uint256,bytes)')) == 0xf242432a + * bytes4(keccak256('safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)')) == 0x2eb2c2d6 + * + * => 0x00fdd58e ^ 0x4e1273f4 ^ 0xa22cb465 ^ + * 0xe985e9c5 ^ 0xf242432a ^ 0x2eb2c2d6 == 0xd9b67a26 + */ + bytes4 private constant _INTERFACE_ID_ERC1155 = 0xd9b67a26; + + /* + * bytes4(keccak256('uri(uint256)')) == 0x0e89341c + */ + bytes4 private constant _INTERFACE_ID_ERC1155_METADATA_URI = 0x0e89341c; + + /** + * @dev See {_setURI}. + */ + constructor (string memory uri_) { + _setURI(uri_); + + // register the supported interfaces to conform to ERC1155 via ERC165 + _registerInterface(_INTERFACE_ID_ERC1155); + + // register the supported interfaces to conform to ERC1155MetadataURI via ERC165 + _registerInterface(_INTERFACE_ID_ERC1155_METADATA_URI); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256) external view override returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: balance query for the zero address"); + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) + public + view + virtual + override + returns (uint256[] memory) + { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + require(accounts[i] != address(0), "ERC1155: batch balance query for the zero address"); + batchBalances[i] = _balances[ids[i]][accounts[i]]; + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + require(_msgSender() != operator, "ERC1155: setting approval status for self"); + + _operatorApprovals[_msgSender()][operator] = approved; + emit ApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) + public + virtual + override + { + require(to != address(0), "ERC1155: transfer to the zero address"); + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not owner nor approved" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data); + + _balances[id][from] = _balances[id][from].sub(amount, "ERC1155: insufficient balance for transfer"); + _balances[id][to] = _balances[id][to].add(amount); + + emit TransferSingle(operator, from, to, id, amount); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + public + virtual + override + { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: transfer caller is not owner nor approved" + ); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + _balances[id][from] = _balances[id][from].sub( + amount, + "ERC1155: insufficient balance for transfer" + ); + _balances[id][to] = _balances[id][to].add(amount); + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `account`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address account, uint256 id, uint256 amount, bytes memory data) internal virtual { + require(account != address(0), "ERC1155: mint to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data); + + _balances[id][account] = _balances[id][account].add(amount); + emit TransferSingle(operator, address(0), account, id, amount); + + _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint i = 0; i < ids.length; i++) { + _balances[ids[i]][to] = amounts[i].add(_balances[ids[i]][to]); + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `account` + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens of token type `id`. + */ + function _burn(address account, uint256 id, uint256 amount) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, account, address(0), _asSingletonArray(id), _asSingletonArray(amount), ""); + + _balances[id][account] = _balances[id][account].sub( + amount, + "ERC1155: burn amount exceeds balance" + ); + + emit TransferSingle(operator, account, address(0), id, amount); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual { + require(account != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, account, address(0), ids, amounts, ""); + + for (uint i = 0; i < ids.length; i++) { + _balances[ids[i]][account] = _balances[ids[i]][account].sub( + amounts[i], + "ERC1155: burn amount exceeds balance" + ); + } + + emit TransferBatch(operator, account, address(0), ids, amounts); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + internal virtual + { } + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) + internal + { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver(to).onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) + internal + { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) { + if (response != IERC1155Receiver(to).onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/assets/eip-3267/contracts/ERC1155/ERC1155TokenReceiver.sol b/assets/eip-3267/contracts/ERC1155/ERC1155TokenReceiver.sol new file mode 100644 index 00000000..7e888ba6 --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/ERC1155TokenReceiver.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; + +import "./IERC1155TokenReceiver.sol"; +import "@openzeppelin/contracts/introspection/ERC165.sol"; + +abstract contract ERC1155TokenReceiver is ERC165, IERC1155TokenReceiver { + constructor() { + _registerInterface( + ERC1155TokenReceiver(0).onERC1155Received.selector ^ + ERC1155TokenReceiver(0).onERC1155BatchReceived.selector + ); + } +} diff --git a/assets/eip-3267/contracts/ERC1155/ERC1155WithTotals.sol b/assets/eip-3267/contracts/ERC1155/ERC1155WithTotals.sol new file mode 100644 index 00000000..95bf2285 --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/ERC1155WithTotals.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "@openzeppelin/contracts/math/SafeMath.sol"; +import { ERC1155 } from "./ERC1155.sol"; + +/// @title A base contract for an ERC-1155 contract with calculation of totals. +abstract contract ERC1155WithTotals is ERC1155 { + using SafeMath for uint256; + + // Mapping (token => total). + mapping(uint256 => uint256) private totalBalances; + + /// Construct a token contract with given description URI. + /// @param uri_ Description URI. + constructor (string memory uri_) ERC1155(uri_) { } + + // Overrides // + + // Need also update totals - commented out + // function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual override { + // return super._mintBatch(_originalAddress(to), ids, amounts, data); + // } + + // Need also update totals - commented out + // function _burnBatch(address account, uint256[] memory ids, uint256[] memory amounts) internal virtual override { + // return super._burnBatch(_originalAddress(account), ids, amounts); + // } + + /// Total supply of a token (conforms to `IERC1155Views`). + /// @param id Token ID. + /// @return Total supply. + function totalSupply(uint256 id) public view returns (uint256) { + return totalBalances[id]; + } + + /// Mint a token. + /// @param to Whom to mint to. + /// @param id Token ID. + /// @param value Amount to mint. + /// @param data Additional data. + function _mint(address to, uint256 id, uint256 value, bytes memory data) internal override { + require(to != address(0), "ERC1155: mint to the zero address"); + + _doMint(to, id, value); + emit TransferSingle(msg.sender, address(0), to, id, value); + + _doSafeTransferAcceptanceCheck(msg.sender, address(0), to, id, value, data); + } + + /// Mint zero or more tokens. + /// @param to Whom to mint to. + /// @param ids Token IDs. + /// @param values Amounts to mint. + /// @param data Additional data. + function _batchMint(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal { + require(to != address(0), "ERC1155: batch mint to the zero address"); + require(ids.length == values.length, "ERC1155: IDs and values must have same lengths"); + + for(uint i = 0; i < ids.length; i++) { + _doMint(to, ids[i], values[i]); + } + + emit TransferBatch(msg.sender, address(0), to, ids, values); + + _doSafeBatchTransferAcceptanceCheck(msg.sender, address(0), to, ids, values, data); + } + + /// Burn a token. + /// @param owner Whose tokens to burn. + /// @param id Token ID. + /// @param value Amount to mint. + function _burn(address owner, uint256 id, uint256 value) internal override { + _doBurn(owner, id, value); + emit TransferSingle(msg.sender, owner, address(0), id, value); + } + + /// Burn zero or more tokens. + /// @param owner Whose tokens to burn. + /// @param ids Token IDs. + /// @param values Amounts to mint. + function _batchBurn(address owner, uint256[] memory ids, uint256[] memory values) internal { + require(ids.length == values.length, "ERC1155: IDs and values must have same lengths"); + + for(uint i = 0; i < ids.length; i++) { + _doBurn(owner, ids[i], values[i]); + } + + emit TransferBatch(msg.sender, owner, address(0), ids, values); + } + + function _doMint(address to, uint256 id, uint256 value) private { + totalBalances[id] = totalBalances[id].add(value); + _balances[id][to] = _balances[id][to] + value; // The previous didn't overflow, therefore this doesn't overflow. + } + + function _doBurn(address from, uint256 id, uint256 value) private { + _balances[id][from] = _balances[id][from].sub(value); + totalBalances[id] = totalBalances[id] - value; // The previous didn't overflow, therefore this doesn't overflow. + } +} \ No newline at end of file diff --git a/assets/eip-3267/contracts/ERC1155/IERC1155.sol b/assets/eip-3267/contracts/ERC1155/IERC1155.sol new file mode 100644 index 00000000..2ecf0f18 --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/IERC1155.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; + +import "@openzeppelin/contracts/introspection/IERC165.sol"; + +/** + @title ERC-1155 Multi Token Standard basic interface + @dev See https://eips.ethereum.org/EIPS/eip-1155 + */ +abstract contract IERC1155 is IERC165 { + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + event URI(string value, uint256 indexed id); + + function balanceOf(address owner, uint256 id) public view virtual returns (uint256); + + function balanceOfBatch(address[] memory owners, uint256[] memory ids) public view virtual returns (uint256[] memory); + + function setApprovalForAll(address operator, bool approved) external virtual; + + function isApprovedForAll(address owner, address operator) external view virtual returns (bool); + + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external virtual; + + function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external virtual; +} diff --git a/assets/eip-3267/contracts/ERC1155/IERC1155TokenReceiver.sol b/assets/eip-3267/contracts/ERC1155/IERC1155TokenReceiver.sol new file mode 100644 index 00000000..f737f41c --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/IERC1155TokenReceiver.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; + +import "@openzeppelin/contracts/introspection/IERC165.sol"; + +/** + @title ERC-1155 Multi Token Receiver Interface + @dev See https://eips.ethereum.org/EIPS/eip-1155 +*/ +abstract contract IERC1155TokenReceiver is IERC165 { + + /** + @dev Handles the receipt of a single ERC1155 token type. This function is + called at the end of a `safeTransferFrom` after the balance has been updated. + To accept the transfer, this must return + `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + (i.e. 0xf23a6e61, or its own function selector). + @param operator The address which initiated the transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param id The ID of the token being transferred + @param value The amount of tokens being transferred + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) + external virtual + returns(bytes4); + + /** + @dev Handles the receipt of a multiple ERC1155 token types. This function + is called at the end of a `safeBatchTransferFrom` after the balances have + been updated. To accept the transfer(s), this must return + `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + (i.e. 0xbc197c81, or its own function selector). + @param operator The address which initiated the batch transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param ids An array containing ids of each token being transferred (order and length must match values array) + @param values An array containing amounts of each token being transferred (order and length must match ids array) + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) + external virtual + returns(bytes4); +} diff --git a/assets/eip-3267/contracts/ERC1155/README.md b/assets/eip-3267/contracts/ERC1155/README.md new file mode 100644 index 00000000..8f69c423 --- /dev/null +++ b/assets/eip-3267/contracts/ERC1155/README.md @@ -0,0 +1,12 @@ +--- +sections: + - title: Core + contracts: + - IERC1155 + - ERC1155 + - IERC1155TokenReceiver +--- + +This set of interfaces and contracts are all related to the [ERC1155 Multi Token Standard](https://eips.ethereum.org/EIPS/eip-1155). + +The EIP consists of two interfaces which fulfill different roles, found here as `IERC1155` and `IERC1155TokenReceiver`. Only `IERC1155` is required for a contract to be ERC1155 compliant. The basic functionality is implemented in `ERC1155`. diff --git a/assets/eip-3267/contracts/README.md b/assets/eip-3267/contracts/README.md new file mode 100644 index 00000000..a22a26bb --- /dev/null +++ b/assets/eip-3267/contracts/README.md @@ -0,0 +1,15 @@ +This directory contains contract sources for EIP 3267 draft. + +The audit of the contracts was paid for, now it is in progress. +(There are some FIXME/TODO comments for the auditors.) + +The contracts are to be compiled with Solidity 0.7.6. + +Dependencies (Node.js packages): + +- @openzeppelin/contracts 3.3.0 +- abdk-libraries-solidity 2.4.0 + +The contracts to be deployed are: +- SalaryWithDAO +- DefaultDAOInterface diff --git a/assets/eip-3267/contracts/Salary.sol b/assets/eip-3267/contracts/Salary.sol new file mode 100644 index 00000000..5cbc23d5 --- /dev/null +++ b/assets/eip-3267/contracts/Salary.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import "./BaseSalary.sol"; + +/// @title "Salary" that is paid one token per second using minted conditionals. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +contract Salary is BaseSalary { + /// @param _uri The ERC-1155 token URI. + constructor(string memory _uri) BaseSalary(_uri) { } + + /// Register a salary recipient. + /// + /// Can be called both before or after the oracle finish. However registering after the finish is useless. + /// + /// Anyone can register anyone (useful for robots registering a person). + /// + /// Registering another person is giving him money against his will (forcing to hire bodyguards, etc.), + /// but if one does not want, he can just not associate this address with his identity in his publications. + /// @param _customer The original address. + /// @param _oracleId The oracle ID. + /// @param _data The current data. + function registerCustomer(address _customer, uint64 _oracleId, bytes calldata _data) + virtual public returns (uint256) + { + return _registerCustomer(_customer, _oracleId, _data); + } +} \ No newline at end of file diff --git a/assets/eip-3267/contracts/SalaryWithDAO.sol b/assets/eip-3267/contracts/SalaryWithDAO.sol new file mode 100644 index 00000000..6b6fc231 --- /dev/null +++ b/assets/eip-3267/contracts/SalaryWithDAO.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +pragma solidity ^0.7.1; +import { ABDKMath64x64 } from "abdk-libraries-solidity/ABDKMath64x64.sol"; +import "./BaseRestorableSalary.sol"; +import "./DAOInterface.sol"; + +/// Salary system with a "DAO" that can assign attorneys to restore lost Ethereum accounts. +/// @author Victor Porton +/// @notice Not audited, not enough tested. +contract SalaryWithDAO is BaseRestorableSalary { + using ABDKMath64x64 for int128; + + /// The DAO interface. + DAOInterface public daoPlugin; + + /// When set to true, your account can't be moved to new address (by the DAO). + /// + /// By default new users are not under DAO control to avoid front-running of resigning control + /// by an evil DAO. + /// + /// Mapping (current address => under control) + mapping (address => bool) public underDAOControl; + + /// Mapping (current address => account has at least one salary). + mapping (address => bool) public accountHasSalary; + + // DAO share will be zero to prevent theft by voters and because it can be done instead by future voting. + // int128 public daoShare = int128(0).div(1); // zero by default + + /// Constructor. + /// @param _daoPlugin The DAO interface. + /// @param _uri The ERC-1155 token URI. + constructor(DAOInterface _daoPlugin, string memory _uri) + BaseRestorableSalary(_uri) + { + daoPlugin = _daoPlugin; + } + + /// Create an oracle for caclcualting salary amounts. + function createOracle() external returns (uint64) { + return _createOracle(); + } + + /// Register a salary recipient. + /// + /// Can be called both before or after the oracle finish. However registering after the finish is useless. + /// + /// Anyone can register anyone (useful for robots registering a person). + /// + /// Registering another person is giving him money against his will (forcing to hire bodyguards, etc.), + /// but if one does not want, he can just not associate this address with his identity in his publications. + /// @param _customer The original address. + /// @param _oracleId The oracle ID. + /// @param _underDAOControl If the registered address will be under DAO control. + /// @param _data The current data. + function registerCustomer(address _customer, uint64 _oracleId, bool _underDAOControl, bytes calldata _data) + virtual public returns (uint256) + { + address _orig = _originalAddress(_customer); + // Auditor: Check that this value is set to false, when (and if) necessary. + accountHasSalary[_customer] = true; + underDAOControl[_customer] = _underDAOControl; // We don't trigger and event to reduce gas usage. + return super._registerCustomer(_orig, _oracleId, _data); + } + + /// A user can agree for DAO control. Then his account can be restored by DAO for the expense + /// of the DAO assigned personnel or software being able to steal his funds. + /// + /// Be exteremely careful calling this method: If you refuse and lose your key, your funds are lost! + /// + /// Fishers may trick one to resign mistakenly. However, it's no much worse than just fishing for + /// withdrawing the salary token, because a user could just register anew and notify traders/oracles + /// that it's the same person. + function setDAOControl(bool _underControl) public { + address _orig = _originalAddress(msg.sender); + require(accountHasSalary[_orig], "Cannot resign account receiving a salary."); + underDAOControl[_orig] = _underControl; // We don't trigger and event to reduce gas usage. + } + + /// The DAO can replace itself. + function setDAO(DAOInterface _daoPlugin) public onlyDAO { + daoPlugin = _daoPlugin; + } + + /// Set the token URI. + function setURI(string memory _newuri) public onlyDAO { + _setURI(_newuri); + } + + // Overrides /// + + function checkAllowedRestoreAccount(address _oldAccount, address _newAccount) + public virtual override isUnderDAOControl(_oldAccount) + { + daoPlugin.checkAllowedRestoreAccount(_oldAccount, _newAccount); + } + + /// Allow the user to unrestore by himself? + /// We won't not allow it to `_oldAccount` because it may be a stolen private key. + /// We could allow it to `_newAccount`, but this makes no much sense, because + /// it would only prevent the user to do a theft by himself, let only DAO could be allowed to do. + function checkAllowedUnrestoreAccount(address _oldAccount, address _newAccount) + public virtual override isUnderDAOControl(_oldAccount) + { + daoPlugin.checkAllowedUnrestoreAccount(_oldAccount, _newAccount); + } + + // Internal // + + function _isDAO() internal view returns (bool) { + return msg.sender == address(daoPlugin); + } + + // Modifiers // + + modifier onlyDAO() { + require(_isDAO(), "Only DAO can do."); + _; + } + + /// @param _customer The current address. + modifier isUnderDAOControl(address _customer) { + require(underDAOControl[_customer], "Not under DAO control."); + _; + } +} diff --git a/assets/eip-3267/science-salaries.pdf b/assets/eip-3267/science-salaries.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a6a243c68ce9d140984c5732c5d14d949b31de8a GIT binary patch literal 99222 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