forked from DecentralizedClimateFoundation/DCIPs
127 lines
5.0 KiB
Solidity
127 lines
5.0 KiB
Solidity
|
// SPDX-License-Identifier: CC0-1.0
|
||
|
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.");
|
||
|
_;
|
||
|
}
|
||
|
}
|