Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/ren pool factory abi #45

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/node_modules/
/artifacts/**/*.json
!/artifacts/contracts/RenPool.sol/RenPool.json
!/artifacts/contracts/RenPoolFactory.sol/RenPoolFactory.json
!/artifacts/@renproject/gateway-sol/contracts/Gateway/interfaces/IERC20Standard.sol/IERC20Standard.json
!/artifacts/interfaces/IDarknodeRegistry.sol/IDarknodeRegistry.json
/cache/
Expand Down
100 changes: 95 additions & 5 deletions artifacts/contracts/RenPool.sol/RenPool.json

Large diffs are not rendered by default.

124 changes: 124 additions & 0 deletions artifacts/contracts/RenPoolFactory.sol/RenPoolFactory.json

Large diffs are not rendered by default.

96 changes: 63 additions & 33 deletions contracts/RenPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ contract RenPool {

uint256 public bond;
uint256 public totalPooled;
uint256 public totalWithdrawalRequested;
uint256 public ownerFee; // Percentage
uint256 public nodeOperatorFee; // Percentage

bool public isLocked;
// ^ we could use enum instead POOL_STATUS = { OPEN /* 0 */, CLOSE /* 1 */ }
bool public isRegistered;

mapping(address => uint256) public balances;
mapping(address => uint256) public withdrawRequests;
mapping(address => uint256) public withdrawalRequests;
mapping(address => uint256) public nonces;

IERC20 public renToken;
Expand All @@ -39,6 +41,9 @@ contract RenPool {

event RenDeposited(address indexed _from, uint256 _amount);
event RenWithdrawn(address indexed _from, uint256 _amount);
event RenWithdrawalRequested(address indexed _from, uint256 _amount);
event RenWithdrawalRequestFulfilled(address indexed _from, uint256 _amount);
event RenWithdrawalRequestCancelled(address indexed _from, uint256 _amount);
event EthDeposited(address indexed _from, uint256 _amount);
event EthWithdrawn(address indexed _from, uint256 _amount);
event PoolLocked();
Expand Down Expand Up @@ -78,31 +83,33 @@ contract RenPool {
gatewayRegistry = IGatewayRegistry(_gatewayRegistryAddr);
bond = _bond;
isLocked = false;
isRegistered = false;
totalPooled = 0;
totalWithdrawalRequested = 0;
ownerFee = 5;
nodeOperatorFee = 5;
}

modifier onlyNodeOperator() {
require (
msg.sender == nodeOperator,
"RenPool: Caller is not node operator"
"RenPool: Unauthorized"
);
_;
}

modifier onlyOwnerNodeOperator() {
require (
msg.sender == owner || msg.sender == nodeOperator,
"RenPool: Caller is not owner nor node operator"
"RenPool: Unauthorized"
);
_;
}

modifier onlyOwner() {
require (
msg.sender == owner,
"RenPool: Caller is not owner"
"RenPool: Unauthorized"
);
_;
}
Expand All @@ -116,8 +123,13 @@ contract RenPool {
emit PoolLocked();
}

function _deregisterDarknode() private {
darknodeRegistry.deregister(darknodeID);
isRegistered = false;
}

function unlockPool() external onlyOwnerNodeOperator {
require(renToken.balanceOf(address(this)) > 0, "Pool balance is zero");
require(renToken.balanceOf(address(this)) > 0, "RenPool: Pool balance is zero");
isLocked = false;
emit PoolUnlocked();
}
Expand Down Expand Up @@ -159,76 +171,93 @@ contract RenPool {
address sender = msg.sender;
uint256 senderBalance = balances[sender];

require(senderBalance > 0 && senderBalance >= _amount, "Insufficient funds");
require(!isLocked, "Pool is locked");
require(_amount > 0, "RenPool: Invalid amount");
require(senderBalance >= _amount, "RenPool: Insufficient funds");
require(!isLocked, "RenPool: Pool is locked");

totalPooled -= _amount;
balances[sender] -= _amount;

require(
renToken.transfer(sender, _amount),
"Withdraw failed"
"RenPool: Withdraw failed"
);

emit RenWithdrawn(sender, _amount);
}

/**
* @notice Requesting a withdraw in case the pool is locked. The amount
* that needs to be withdrawn will be replaced by another user using the
* fulfillWithdrawRequest method.
* @notice Requesting a withdraw in case the pool is locked. The amount
* that needs to be withdrawn will be replaced by another user using the
* fulfillWithdrawalRequest method.
*
* @param _amount The amount of REN to be withdrawn.
*
* @dev Users can have up to a single request active. In case of several
* calls to this method, only the last request will be preserved.
*/
function requestWithdraw(uint256 _amount) external {
function requestWithdrawal(uint256 _amount) external {
address sender = msg.sender;
uint256 senderBalance = balances[sender];

require(senderBalance > 0 && senderBalance >= _amount, "Insufficient funds");
require(isLocked, "Pool is not locked");
require(_amount > 0, "RenPool: Invalid amount");
require(senderBalance >= _amount, "RenPool: Insufficient funds");
require(isLocked, "RenPool: Pool is not locked");

withdrawalRequests[sender] = _amount;
totalWithdrawalRequested += _amount;

withdrawRequests[sender] = _amount;
if(isRegistered && totalWithdrawalRequested > bond / 2) {
_deregisterDarknode();
}

// TODO emit event
emit RenWithdrawalRequested(sender, _amount);
}

/**
* @notice User wanting to fullill the withdraw request will pay the amount
* @notice User wanting to fulfill the withdraw request will pay the amount
* the user wanting to withdraw his money.
*
* @param _target The amount of REN to be withdrawn.
*/
function fulfillWithdrawRequest(address _target) external {
function fulfillWithdrawalRequest(address _target) external {
address sender = msg.sender;
uint256 amount = withdrawRequests[_target];
// ^ This could not be defined plus make sure amount > 0
// TODO: make sure user cannot fullfil his own request
// TODO: add test for when _target doesn't have an associated withdrawRequest
uint256 amount = withdrawalRequests[_target];

require(isLocked, "Pool is not locked");
require(amount > 0, "RenPool: invalid amount");
require(isLocked, "RenPool: Pool is not locked");

balances[sender] += amount;
balances[_target] -= amount;
delete withdrawRequests[_target];
totalWithdrawalRequested -= amount;

delete withdrawalRequests[_target];

// Transfer funds from sender to _target
require(
renToken.transferFrom(sender, address(this), amount),
"Deposit failed"
"RenPool: Deposit failed"
);
require(
renToken.transfer(_target, amount),
"Refund failed"
"RenPool: Refund failed"
);

// TODO emit event
emit RenWithdrawalRequestFulfilled(sender, amount);
}

// TODO: cancelWithdrawRequest
// TODO: getWithdrawRequests
function cancelWithdrawalRequest() external {
address sender = msg.sender;
uint256 amount = withdrawalRequests[sender];

require(amount > 0, "RenPool: invalid amount");

totalWithdrawalRequested -= amount;

delete withdrawalRequests[sender];

emit RenWithdrawalRequestCancelled(sender, amount);
}

/**
* @notice Return REN balance for the given address.
Expand All @@ -244,11 +273,11 @@ contract RenPool {
* registering the darknode.
*/
function approveBondTransfer() external onlyNodeOperator {
require(isLocked, "Pool is not locked");
require(isLocked, "RenPool: Pool is not locked");

require(
renToken.approve(address(darknodeRegistry), bond),
"Bond transfer failed"
"RenPool: Bond transfer failed"
);
}

Expand All @@ -266,10 +295,11 @@ contract RenPool {
* other darknodes and traders to encrypt messages to the trader.
*/
function registerDarknode(address _darknodeID, bytes calldata _publicKey) external onlyNodeOperator {
require(isLocked, "Pool is not locked");
require(isLocked, "RenPool: Pool is not locked");

darknodeRegistry.register(_darknodeID, _publicKey);

isRegistered = true;
darknodeID = _darknodeID;
publicKey = _publicKey;
}
Expand All @@ -283,7 +313,7 @@ contract RenPool {
* to being able to call refund.
*/
function deregisterDarknode() external onlyOwnerNodeOperator {
darknodeRegistry.deregister(darknodeID);
_deregisterDarknode();
}

/**
Expand Down
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type Artifact = {
};

export const RenPool: Artifact;
export const RenPoolFactory: Artifact;
export const IERC20Standard: Artifact;
export const IDarknodeRegistry: Artifact;

Expand Down
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
const RenPool = require('./artifacts/contracts/RenPool.sol/RenPool.json');
const RenPool= require('./artifacts/contracts/RenPool.sol/RenPool.json');
const RenPoolFactory = require('./artifacts/contracts/RenPoolFactory.sol/RenPoolFactory.json');
const IERC20Standard = require('./artifacts/@renproject/gateway-sol/contracts/Gateway/interfaces/IERC20Standard.sol/IERC20Standard.json');
const IDarknodeRegistry = require('./artifacts/interfaces/IDarknodeRegistry.sol/IDarknodeRegistry.json');
const deployments = require('./ren-deployments.js');

module.exports = {
RenPool,
RenPoolFactory,
IERC20Standard,
IDarknodeRegistry,
deployments,
Expand Down
68 changes: 35 additions & 33 deletions scripts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,32 +40,34 @@ async function faucet(renToken, account) {
}

async function main() {
print(`${chalk.italic('\u{1F680} RenPool contract deployment')}`);
print(`${chalk.italic('\u{1F680} RenPoolFactory contract deployment')}`);
print(`Using network ${chalk.bold(hre.network.name)} (${chalk.bold(hre.network.config.chainId)})`);

print(`Getting signers to deploy RenPool contract`);
print(`Getting signers to deploy RenPoolFactory contract`);
const [owner] = await ethers.getSigners();
const nodeOperator = owner;

print(`Deploying ${chalk.bold('RenPool')} contract`);
const RenPool = await ethers.getContractFactory('RenPool');
const renPool = await RenPool.connect(nodeOperator).deploy(
renTokenAddr,
darknodeRegistryAddr,
darknodePaymentAddr,
claimRewardsAddr,
gatewayRegistryAddr,
owner.address,
nodeOperator.address,
POOL_BOND);
await renPool.deployed();

print(`Deployed to ${chalk.bold(renPool.address)} TX ${chalk.bold(renPool.deployTransaction.hash)}`);
// const nodeOperator = owner;

print(`Deploying ${chalk.bold('RenPoolFactory')} contract`);
const RenPoolFactory = await ethers.getContractFactory('RenPoolFactory');
const renPoolFactory = await RenPoolFactory.connect(owner).deploy();
await renPoolFactory.deployed();
// const renPool = await RenPoolFactory.connect(nodeOperator).deploy(
// renTokenAddr,
// darknodeRegistryAddr,
// darknodePaymentAddr,
// claimRewardsAddr,
// gatewayRegistryAddr,
// owner.address,
// nodeOperator.address,
// POOL_BOND);
// await renPool.deployed();

print(`Deployed to ${chalk.bold(renPoolFactory.address)} TX ${chalk.bold(renPoolFactory.deployTransaction.hash)}`);

const renToken = new ethers.Contract(renTokenAddr, RenToken.abi, owner);

if (hre.network.name === 'hardhat') {
print('Skipping RenPool contract Etherscan verification')
print('Skipping RenPoolFactory contract Etherscan verification')

await provider.request({ method: 'hardhat_impersonateAccount', params: [topRenTokenHolderAddr] });

Expand All @@ -88,26 +90,26 @@ async function main() {
} else {
print('Waiting before verification');
await sleep(30000);
const balance = await renPool.balanceOf(owner.address);
print(` Owner's balance is ${chalk.yellow(balance)}`);
// const balance = await renPool.balanceOf(owner.address);
// print(` Owner's balance is ${chalk.yellow(balance)}`);

print('Verifying RenPool smart contract in Etherscan')
print('Verifying RenPoolFactory smart contract in Etherscan')

await hre.run("verify:verify", {
address: renPool.address,
constructorArguments: [
renTokenAddr,
darknodeRegistryAddr,
darknodePaymentAddr,
claimRewardsAddr,
gatewayRegistryAddr,
owner.address,
POOL_BOND
],
address: renPoolFactory.address,
constructorArguments: []
// renTokenAddr,
// darknodeRegistryAddr,
// darknodePaymentAddr,
// claimRewardsAddr,
// gatewayRegistryAddr,
// owner.address,
// POOL_BOND
// ],
});
}

return { renPool, renToken, faucet };
return { renPoolFactory, renToken, faucet };
}

if (require.main === module) {
Expand Down
Loading