// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAction {
/**
* @dev Emit add fund event on chain
*/
function addFundWithAction(address _clientAddress, address _tokenAddress, uint256 _tokenValue, string memory _data) external returns(bool);
/**
* @dev Emit remove fund event on chain
*/
function withdrawFund(string memory _ticketId, address _clientAddress, address _tokenAddress, uint256 _withdrawValue, uint256 _inDebtValue) external returns(bool);
/**
* @dev Emit queue fund event on chain
*/
function queueWithdraw(string memory _ticketId, address _clientAddress, address _tokenAddress, uint256 _tokenValue) external returns(bool);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* Interface of the money pool functions
*/
interface IMoneyPoolRaw {
/**
* @dev Returns client's withdraw nonce.
*/
function clientNonce(address _clientAddress) external view returns(uint256);
/**
* @dev Returns contract total assets of the type.
*/
function totalLockedAssets(address _tokenAddress) external view returns(uint256);
/**
* @dev Returns total SATIS token in the contract.
*/
function satisTokenBalance(address _tokenAddress) external view returns(uint256);
/**
* @dev Get queued value for the list of clients
*/
function getClientQueueValue(address[] memory _clientAddressList, address _tokenAddress) external view returns(uint256[] memory);
/**
* @dev Get reserved value for the list of clients
*/
function getInstantWithdrawReserve(string[] memory _ticketIdList, address _tokenAddress) external view returns(uint256[] memory);
/**
* @dev Returns pool's owner address.
*/
function owner() external view returns(address);
/**
* @dev Verify if an address is a worker.
*/
function verifyWorker(address _workerAddress) external view returns(bool);
/**
* @dev Add and lock fund.
*/
function addFundWithAction(address _clientAddress, address _tokenAddress, uint256 _addValue) external returns(bool);
/**
* @dev Verify and withdraw fund.
*/
function verifyAndWithdrawFund(bytes memory _targetSignature, address _clientAddress, address _tokenAddress, uint256 _withdrawValue, uint256 _inDebtValue, uint256 _tier, uint256 _chainId, address _poolAddress, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce) external returns(bool _isDone);
/**
* @dev Verify and queue.
*/
function verifyAndQueue(bytes memory _targetSignature, address _clientAddress, address _tokenAddress, uint256 _withdrawValue, uint256 _inDebtValue, uint256 _tier, uint256 _chainId, address _poolAddress, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce) external returns(bool _isDone);
/**
* @dev Verify and redeem SATIS token in Sigma Mining.
*/
function verifyAndRedeemToken(bytes memory _targetSignature, address _clientAddress, address _tokenAddress, uint256 _redeemValue, uint256 _inDebtValue, uint256 _tier, uint256 _chainId, address _poolAddress, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce) external returns(bool _isDone);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../lib_and_interface/IMoneyPoolRaw.sol";
import "../lib_and_interface/IAction.sol";
/**
* This contract is a simple money pool for deposit.
* It supports transfer and withdrawal of assets (ETH and ERC20 tokens).
* (In most of the Layer 2 implementations, wrapped Ether is used instead).
*
* This contract uses Openzeppelin's library for ERC20 tokens.
* When deploying on certain L2s (such as Optimism), it requires a slight modification
* of the original ERC20 token library, since some OVMs do not support ETH functions.
*/
// import '@openzeppelin/contracts/token/ERC20/SafeERC20.sol';
// import '@openzeppelin/contracts/math/SafeMath.sol';
contract MoneyPoolV2 {
address public owner;
address public actionContractAddress;
mapping (string => address) public poolAddressList;
mapping (address => bool) public workerList;
/**
* Events that will be triggered when assets are deposited.
* The log files will record the sender, recipient and transaction data.
*/
event ChangeOwnership(address newAdminAddress);
event ChangePoolAddress(address[] newlyAddedPoolAddressList);
event AddWorkers(address[] addWorkerList);
event RemoveWorkers(address[] removeWorkerList);
modifier isOwner() {
require (msg.sender == owner, "Not an admin");
_;
}
modifier isWorker() {
require (workerList[msg.sender] == true, "Not a worker");
_;
}
/**
* @dev Sets the value for {owner}, {workerList} and {poolList}
*/
constructor(string[] memory _poolNameList, address[] memory _poolAddressList, address _actionContractAddress) {
require(_actionContractAddress != address(0), "Zero address for action contract");
require(_poolNameList.length == _poolAddressList.length, "Lists' length is different");
owner = msg.sender;
workerList[owner] = true;
for(uint256 i=0; i < _poolAddressList.length; i++) {
poolAddressList[_poolNameList[i]] = _poolAddressList[i];
}
actionContractAddress = _actionContractAddress;
}
/**
* @dev Get client's nonce in a pool.
*/
function getClientNonce(address _clientAddress, string memory _poolName) external view returns(uint256 clientNonce) {
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
clientNonce = poolContract.clientNonce(_clientAddress);
}
/**
* @dev Get client's locked balance in a pool.
*/
function getLiquidityAmountInPool(address _tokenAddress, string memory _poolName) external view returns(uint256 liquidityInPool) {
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
liquidityInPool = poolContract.totalLockedAssets(_tokenAddress);
}
/**
* @dev Get the particular pool's owner.
*/
function getPoolOwner(string memory _poolName) external view returns(address poolOwner) {
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
poolOwner = poolContract.owner();
}
/**
* @dev Check if an address is a worker.
*/
function verifyWorker(address _workerAddress) public view returns(bool _isWorker) {
_isWorker = workerList[_workerAddress];
}
/**
* @dev Get a pool's address with its name.
*/
function getPoolAddress(string memory _poolName) public view returns(address _poolAddress) {
_poolAddress = poolAddressList[_poolName];
}
/**
* @dev Transfer the ownership of this contract.
*/
function transferOwnershipMoneyPoolProxy(address _newOwner) external isOwner {
require(_newOwner != address(0), "Zero address for new owner");
workerList[owner] = false;
owner = _newOwner;
workerList[owner] = true;
emit ChangeOwnership(owner);
}
/**
* @dev Add workers to this contract.
*/
function addWorkers(address[] memory _addWorkerList) external isOwner {
for(uint256 i=0; i < _addWorkerList.length; i++) {
workerList[_addWorkerList[i]] = true;
}
emit AddWorkers(_addWorkerList);
}
/**
* @dev Remove workers from this contract.
*/
function removeWorkers(address[] memory _removeWorkerList) external isOwner {
for(uint256 i=0; i < _removeWorkerList.length; i++) {
workerList[_removeWorkerList[i]] = false;
}
emit RemoveWorkers(_removeWorkerList);
}
/**
* @dev Append and overwrite pool address list. Set address to 0x0 for deleting pool.
*/
function changePool(string[] memory _newPoolNameList, address[] memory _newPoolAddressList) external isWorker {
require(_newPoolNameList.length == _newPoolAddressList.length, "Lists' length is different");
for(uint256 i=0; i < _newPoolAddressList.length; i++) {
poolAddressList[_newPoolNameList[i]] = _newPoolAddressList[i];
}
emit ChangePoolAddress(_newPoolAddressList);
}
/**
* @dev Change action contract address for new event output format.
*/
function changeActionContract(address _newActionContractAddress) external isWorker {
require(_newActionContractAddress != address(0), "Zero address for new action contract");
actionContractAddress = _newActionContractAddress;
}
/**
* @dev Transfers fund to the pool contract
*/
function addFundWithAction(address _tokenAddress, uint256 _tokenValue, string memory _data, string memory _poolName) external returns(bool _isDone) {
require(poolAddressList[_poolName] != address(0), "No such pool");
bool _addDone = false;
if (_tokenValue > 0) {
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
_addDone = poolContract.addFundWithAction(msg.sender, _tokenAddress, _tokenValue);
} else {
_addDone = true;
}
IAction actionContract = IAction(actionContractAddress);
bool _eventDone = actionContract.addFundWithAction(msg.sender, _tokenAddress, _tokenValue, _data);
_isDone = _addDone && _eventDone;
}
/**
* @dev Tier 1 withdrawal
*/
function verifyAndWithdrawFund(bytes memory _targetSignature, address _tokenAddress, uint256 _withdrawValue, uint256 _inDebtValue, uint256 _tier, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce, string memory _poolName) external returns(bool _isDone) {
require(_tier == 1, "Wrong function called for withdraw tier");
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
poolContract.verifyAndWithdrawFund(_targetSignature, msg.sender, _tokenAddress, _withdrawValue, _inDebtValue, _tier, block.chainid, poolAddressList[_poolName], _expBlockNo, _ticketId, _nonce);
IAction actionContract = IAction(actionContractAddress);
actionContract.withdrawFund(_ticketId, msg.sender, _tokenAddress, _withdrawValue, _inDebtValue);
_isDone = true;
}
/**
* @dev Tier 2 withdrawal
*/
function verifyAndQueue(bytes memory _targetSignature, address _tokenAddress, uint256 _queueValue, uint256 _inDebtValue, uint256 _tier, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce, string memory _poolName) external returns(bool _isDone) {
require(_tier == 2, "Wrong function called for withdraw tier");
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
poolContract.verifyAndQueue(_targetSignature, msg.sender, _tokenAddress, _queueValue, _inDebtValue, _tier, block.chainid, poolAddressList[_poolName], _expBlockNo, _ticketId, _nonce);
IAction actionContract = IAction(actionContractAddress);
actionContract.queueWithdraw(_ticketId, msg.sender, _tokenAddress, _queueValue);
_isDone = true;
}
/**
* @dev Tier 3 withdrawal
*/
function verifyAndPartialWithdrawFund(bytes memory _targetSignature, address _tokenAddress, uint256 _partialWithdrawValue, uint256 _inDebtValue, uint256 _tier, uint256 _expBlockNo, string memory _ticketId, uint256 _nonce, string memory _poolName) external returns(bool _isDone) {
require(_tier == 3, "Wrong function called for withdraw tier");
require(poolAddressList[_poolName] != address(0), "No such pool");
IMoneyPoolRaw poolContract = IMoneyPoolRaw(poolAddressList[_poolName]);
poolContract.verifyAndWithdrawFund(_targetSignature, msg.sender, _tokenAddress, _partialWithdrawValue, _inDebtValue, _tier, block.chainid, poolAddressList[_poolName], _expBlockNo, _ticketId, _nonce);
IAction actionContract = IAction(actionContractAddress);
actionContract.withdrawFund(_ticketId, msg.sender, _tokenAddress, _partialWithdrawValue, _inDebtValue);
_isDone = true;
}
}
{
"compilationTarget": {
"contracts/v2/satis_core/MoneyPoolProxy.sol": "MoneyPoolV2"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"internalType":"string[]","name":"_poolNameList","type":"string[]"},{"internalType":"address[]","name":"_poolAddressList","type":"address[]"},{"internalType":"address","name":"_actionContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"addWorkerList","type":"address[]"}],"name":"AddWorkers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdminAddress","type":"address"}],"name":"ChangeOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"newlyAddedPoolAddressList","type":"address[]"}],"name":"ChangePoolAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"removeWorkerList","type":"address[]"}],"name":"RemoveWorkers","type":"event"},{"inputs":[],"name":"actionContractAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenValue","type":"uint256"},{"internalType":"string","name":"_data","type":"string"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"addFundWithAction","outputs":[{"internalType":"bool","name":"_isDone","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_addWorkerList","type":"address[]"}],"name":"addWorkers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newActionContractAddress","type":"address"}],"name":"changeActionContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"_newPoolNameList","type":"string[]"},{"internalType":"address[]","name":"_newPoolAddressList","type":"address[]"}],"name":"changePool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_clientAddress","type":"address"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"getClientNonce","outputs":[{"internalType":"uint256","name":"clientNonce","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"getLiquidityAmountInPool","outputs":[{"internalType":"uint256","name":"liquidityInPool","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_poolName","type":"string"}],"name":"getPoolAddress","outputs":[{"internalType":"address","name":"_poolAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_poolName","type":"string"}],"name":"getPoolOwner","outputs":[{"internalType":"address","name":"poolOwner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"poolAddressList","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_removeWorkerList","type":"address[]"}],"name":"removeWorkers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"transferOwnershipMoneyPoolProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_targetSignature","type":"bytes"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_partialWithdrawValue","type":"uint256"},{"internalType":"uint256","name":"_inDebtValue","type":"uint256"},{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_expBlockNo","type":"uint256"},{"internalType":"string","name":"_ticketId","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"verifyAndPartialWithdrawFund","outputs":[{"internalType":"bool","name":"_isDone","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_targetSignature","type":"bytes"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_queueValue","type":"uint256"},{"internalType":"uint256","name":"_inDebtValue","type":"uint256"},{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_expBlockNo","type":"uint256"},{"internalType":"string","name":"_ticketId","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"verifyAndQueue","outputs":[{"internalType":"bool","name":"_isDone","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_targetSignature","type":"bytes"},{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_withdrawValue","type":"uint256"},{"internalType":"uint256","name":"_inDebtValue","type":"uint256"},{"internalType":"uint256","name":"_tier","type":"uint256"},{"internalType":"uint256","name":"_expBlockNo","type":"uint256"},{"internalType":"string","name":"_ticketId","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"string","name":"_poolName","type":"string"}],"name":"verifyAndWithdrawFund","outputs":[{"internalType":"bool","name":"_isDone","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_workerAddress","type":"address"}],"name":"verifyWorker","outputs":[{"internalType":"bool","name":"_isWorker","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"workerList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]