Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 113 additions & 133 deletions contracts/GlqStakingContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ struct GlqStaker {
uint256 block_number;
uint256 amount;
uint256 index_at;
bool already_withdrawn;
}

struct GraphLinqApyStruct {
Expand All @@ -33,10 +32,7 @@ contract GlqStakingContract {
uint256 amount_registered
);

/*
** Address of the GLQ token hash: 0x9F9c8ec3534c3cE16F928381372BfbFBFb9F4D24
*/
address private _glqTokenAddress;
event ReceivedFunds(uint256 amount);

/*
** Manager of the contract to add/remove APYs bonuses into the staking contract
Expand All @@ -48,31 +44,91 @@ contract GlqStakingContract {
*/
uint256 private _totalGlqIncentive;

GlqStaker[] private _stakers;
GlqStaker[] public _stakers;
uint256 private _stakersIndex;
uint256 private _totalStaked;
bool private _emergencyWithdraw;

mapping(address => uint256) private _indexStaker;
uint256 private _blocksPerYear;
GraphLinqApyStruct private _apyStruct;
mapping(address => uint256) private _migrationClaim;
uint256 public _indexWithdrawed;


constructor(address glqAddr, address manager) {
_glqTokenAddress = glqAddr;
constructor(address manager) {
_glqDeployerManager = manager;

_totalStaked = 0;
_stakersIndex = 1;

_blocksPerYear = 2250000;
_blocksPerYear = 2102400;

// default t1: 30%, t2: 15%, t3: 7.5%
_apyStruct = GraphLinqApyStruct(50*1e18, 25*1e18, 12500000000000000000);
_apyStruct = GraphLinqApyStruct(35*1e18, 15*1e18, 8*1e18);
}

// new add incentive
receive() external payable {
emit ReceivedFunds(msg.value);
_totalGlqIncentive += msg.value;
}

function setIndexWithdrawed(uint256 indexWithdrawed) public {
require(address(msg.sender) == _glqDeployerManager, "unauthorized access");
_indexWithdrawed = indexWithdrawed;
}

function setMigrationStaker(GlqStaker[] memory stakers, uint256 offset) external {
for (uint i = 0; i < stakers.length; i++)
{
_stakers.push(stakers[i]);
_indexStaker[stakers[i].wallet] = offset+1;
_totalStaked = _totalStaked.add(stakers[i].amount);
offset++;
}
_stakersIndex = offset+1;
}

/*
** Setting GLQ claimable from ETH side
*/
function setClaimMigration(address[] memory addresses, uint256[] memory amounts, uint256 len) public {
require(address(msg.sender) == _glqDeployerManager, "unauthorized access");
for (uint i = 0; i < len; i++) {
_migrationClaim[addresses[i]] = amounts[i];
}
}

/*
** Claim your GLQ from the chain migration
*/
function claimFromMigration() public {
address payable sender = payable(msg.sender);
require(_migrationClaim[sender] > 0, "Nothing to claim from the Ethereum network stake.");

uint256 amount = _migrationClaim[sender];
_migrationClaim[sender] = 0;
sender.transfer(amount);
}

/*
** Return how much is claimable from the ETH Migration
*/
function getClaimFromMigration(address wallet) public view returns(uint256) {
return _migrationClaim[wallet];
}

/* Getter ---- Read-Only */


/*
** Return the staker info from wallet index
*/
function getStaker(address wallet) public view returns (GlqStaker memory) {
uint256 index = _indexStaker[wallet];
return _stakers[index-1];
}

/*
** Return the sender wallet position from the tier system
*/
Expand All @@ -83,10 +139,17 @@ contract GlqStakingContract {
index != 0,
"You dont have any tier rank currently in the Staking contract."
);
GlqStaker memory staker = _stakers[index-1];

if (staker.index_at == 0) {
return currentTier;
}

uint256 walletAggregatedIndex = (index).mul(1e18);
uint256 len = _stakers.length + _indexWithdrawed;

// Total length of stakers
uint256 totalIndex = _stakers.length.mul(1e18);
uint256 totalIndex = len.mul(1e18);
// 15% of hodlers in T1
uint256 t1MaxIndex = totalIndex.div(100).mul(15);
// 55% of hodlers in T2
Expand All @@ -106,6 +169,10 @@ contract GlqStakingContract {
*/
function getPosition(address wallet) public view returns (uint256) {
uint256 index = _indexStaker[wallet];
GlqStaker memory staker = _stakers[index-1];
if (staker.index_at == 0) {
return _stakers.length;
}
return index;
}

Expand All @@ -115,7 +182,7 @@ contract GlqStakingContract {
function getGlqToClaim(address wallet) public view returns(uint256) {
uint256 index = _indexStaker[wallet];
require (index > 0, "Invalid staking index");
GlqStaker storage staker = _stakers[index - 1];
GlqStaker storage staker = _stakers[index-1];

uint256 calculatedApr = getWaitingPercentAPR(wallet);
return staker.amount.mul(calculatedApr).div(100).div(1e18);
Expand Down Expand Up @@ -188,10 +255,14 @@ contract GlqStakingContract {
uint256 len = _stakers.length;
address[] memory addresses = new address[](3);
uint256[] memory amounts = new uint256[](3);
uint256 found = 0;

for (uint i = 0; i < len && i <= 2; i++) {
addresses[i] = _stakers[i].wallet;
amounts[i] = _stakers[i].amount;
for (uint i = 0; i < len && found <= 2; i++) {
if (_stakers[i].amount != 0) {
addresses[i] = _stakers[i].wallet;
amounts[i] = _stakers[i].amount;
found++;
}
}

return (addresses, amounts);
Expand Down Expand Up @@ -231,17 +302,6 @@ contract GlqStakingContract {
/* Setter - Read & Modifications */


/*
** Enable emergency withdraw by GLQ Deployer
*/
function setEmergencyWithdraw(bool state) public {
require (
msg.sender == _glqDeployerManager,
"Only the Glq Deployer can change the state of the emergency withdraw"
);
_emergencyWithdraw = state;
}

/*
** Set numbers of blocks spent per year to calculate claim rewards
*/
Expand All @@ -263,147 +323,75 @@ contract GlqStakingContract {
_apyStruct = newApy;
}

/*
** Add GLQ liquidity in the staking contract for stakers rewards
*/
function addIncentive(uint256 glqAmount) public {
IERC20 glqToken = IERC20(_glqTokenAddress);
require(
msg.sender == _glqDeployerManager,
"Only the Glq Deployer can add incentive into the smart-contract");
require(
glqToken.balanceOf(msg.sender) >= glqAmount,
"Insufficient funds from the deployer contract");
require(
glqToken.transferFrom(msg.sender, address(this), glqAmount) == true,
"Error transferFrom on the contract"
);
_totalGlqIncentive += glqAmount;
}

/*
** Remove GLQ liquidity from the staking contract for stakers rewards
*/
function removeIncentive(uint256 glqAmount) public {
IERC20 glqToken = IERC20(_glqTokenAddress);
address payable deployer = payable(_glqDeployerManager);
require(
msg.sender == _glqDeployerManager,
"Only the Glq Deployer can remove incentive from the smart-contract");
require(
glqToken.balanceOf(address(this)) >= glqAmount,
"Insufficient funds from the deployer contract");
require(
glqToken.transfer(msg.sender, glqAmount) == true,
"Error transfer on the contract"
);

_totalGlqIncentive -= glqAmount;
deployer.transfer(glqAmount);
}


/*
** Deposit GLQ in the staking contract to stake & earn
*/
function depositGlq(uint256 glqAmount) public {
IERC20 glqToken = IERC20(_glqTokenAddress);
require(
glqToken.balanceOf(msg.sender) >= glqAmount,
"Insufficient funds from the sender");
require(
glqToken.transferFrom(msg.sender, address(this), glqAmount) == true,
"Error transferFrom on the contract"
);

function depositGlq() public payable {
require (msg.value >= 10000*1e18, "You need to stake at least 10K GLQ");
uint256 index = _indexStaker[msg.sender];
_totalStaked += glqAmount;
_totalStaked += msg.value;

if (index == 0) {
GlqStaker memory staker = GlqStaker(msg.sender, block.number, glqAmount, _stakersIndex, false);
GlqStaker memory staker = GlqStaker(msg.sender, block.number, msg.value, _stakersIndex);
_stakers.push(staker);
_indexStaker[msg.sender] = _stakersIndex;

// emit event of a new staker registered at current block position
emit NewStakerRegistered(msg.sender, block.number, glqAmount);
emit NewStakerRegistered(msg.sender, block.number, msg.value);
_stakersIndex = _stakersIndex.add(1);

}
else {
// claim rewards before adding new staking amount
if (_stakers[index-1].amount > 0) {
claimGlq();
}
_stakers[index-1].amount += glqAmount;
}
}

function removeStaker(GlqStaker storage staker) private {
uint256 currentIndex = _indexStaker[staker.wallet]-1;
_indexStaker[staker.wallet] = 0;
for (uint256 i= currentIndex ; i < _stakers.length-1 ; i++) {
_stakers[i] = _stakers[i+1];
_stakers[i].index_at = _stakers[i].index_at.sub(1);
_indexStaker[_stakers[i].wallet] = _stakers[i].index_at;
_stakers[index-1].block_number = block.number;
_stakers[index-1].amount += msg.value;
}
_stakers.pop();

// Remove the staker and decrease stakers index
_stakersIndex = _stakersIndex.sub(1);
if (_stakersIndex == 0) { _stakersIndex = 1; }
}

/*
** Emergency withdraw enabled by GLQ team in an emergency case
*/
function emergencyWithdraw() public {
require(
_emergencyWithdraw == true,
"The emergency withdraw feature is not enabled"
);
uint256 index = _indexStaker[msg.sender];
require (index > 0, "Invalid staking index");
GlqStaker storage staker = _stakers[index - 1];
IERC20 glqToken = IERC20(_glqTokenAddress);

require(
staker.amount > 0,
"Not funds deposited in the staking contract");

require(
glqToken.transfer(msg.sender, staker.amount) == true,
"Error transfer on the contract"
);
staker.amount = 0;
}

/*
** Withdraw Glq from the staking contract (reduce the tier position)
** Withdraw Glq from the staking contract
*/
function withdrawGlq() public {
uint256 index = _indexStaker[msg.sender];
address payable src = payable(msg.sender);
require (index > 0, "Invalid staking index");
GlqStaker storage staker = _stakers[index - 1];
IERC20 glqToken = IERC20(_glqTokenAddress);
require(
staker.amount > 0,
"Not funds deposited in the staking contract");

//auto claim when withdraw
claimGlq();


_stakers[index-1].block_number = block.number;
_totalStaked -= staker.amount;
require(
glqToken.balanceOf(address(this)) >= staker.amount,
"Insufficient funds from the deployer contract");
require(
glqToken.transfer(msg.sender, staker.amount) == true,
"Error transfer on the contract"
);

uint256 amount = staker.amount;

staker.amount = 0;
src.transfer(amount);

if (staker.already_withdrawn) {
removeStaker(staker);
} else {
staker.already_withdrawn = true;
if (staker.index_at != 0) {
staker.index_at = 0;
_indexWithdrawed += 1;
}

}

function percent(uint256 numerator, uint256 denominator, uint256 precision) private pure returns(uint256) {
Expand All @@ -418,23 +406,15 @@ contract GlqStakingContract {
*/
function claimGlq() public returns(uint256) {
uint256 index = _indexStaker[msg.sender];
require (index > 0, "Invalid staking index");
GlqStaker storage staker = _stakers[index - 1];
address payable sender = payable(msg.sender);
require (index > 0, "Invalid staking index");

uint256 glqToClaim = getGlqToClaim(msg.sender);
IERC20 glqToken = IERC20(_glqTokenAddress);
if (glqToClaim == 0) { return 0; }

require(
glqToken.balanceOf(address(this)) >= glqToClaim,
"Not enough funds in the staking program to claim rewards"
);

staker.block_number = block.number;

require(
glqToken.transfer(msg.sender, glqToClaim) == true,
"Error transfer on the contract"
);
sender.transfer(glqToClaim);
return (glqToClaim);
}

Expand Down
2 changes: 1 addition & 1 deletion migrations/1_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const StakingContract = artifacts.require("GlqStakingContract");

module.exports = function(deployer) {
deployer.deploy(StakingContract, "0xCcbB043F94c49Be8D448582Cab9158cDFc57a0a1", "0x8984e422E30033A84B780420566046d25EB3519a");
deployer.deploy(StakingContract, "0xBd510d1DD4857061B092420039B44Ca20366F7Fd");
};
Loading