{
address: "0xc3349025e73b4746d79a30ade1200e5dd2d8f754",
balance: {
type: "BigNumber",
hex: "0x00"
string: "0"
ether: "0.0"
},
"transactions": [],
code: "/*
Name: StackingService
Version: 0.0.3
Source:
- CakeVault : https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/cake-vault/contracts/CakeVault.sol
- SmartChefInitializable : https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/smartchef/v2/contracts/SmartChefInitializable.sol
- MasterChef : https://github.com/pancakeswap/pancake-smart-contracts/blob/master/projects/farms-pools/contracts/MasterChef.sol
*/
function IERC20(tokenAddress) {
return address(tokenAddress).getContract();
}
function StackerInfo(stackedAmount, rewardDebt) {
this.stackedAmount = stackedAmount || number(0);
this.rewardDebt = rewardDebt || number(0);
}
class StackingService {
owner = ''
stackedToken = '';
rewardToken = '';
totalStacked = number(0);
accRewardPerStackToken = number(0);
stackers = {}; // mapping(address => StackerInfo)
lastMint = number(0);
mintPeriod = number(60 * 1000); // 60 seconds (1 minute)
rewardsPerPeriod = number('100' + '000000000000000000'); // 100 Token emitted per period (splitted on all stackers)
Initialize(stackedToken, rewardToken) {} // event
Reset() {} // event
Deposit(sender, amount) {} // event
Withdrawal(sender, amount, rewardAmount) {} // event
UpdatePool(pendingRewards, extraRewardPerStackToken) {} // event
UpdateStacker(stackerAddress, stackerRewardAmount) {} // event
initialize(stackedToken, rewardToken) {
require(this.stackedToken == '', "ALREADY_INITIALIZED");
this.stackedToken = stackedToken.toLowerCase();
this.rewardToken = rewardToken.toLowerCase();
this.owner = msg.sender;
emit('Initialize', [stackedToken, rewardToken]);
}
reset() {
require(msg.sender == this.owner, 'ONLY_OWNER');
require(this.stackedToken != '', 'NOT_INITIALIZED');
this.stackers = {};
this.totalStacked = number(0);
this.lastMint = number(0);
this.accRewardPerStackToken = number(0);
const [balance1,] = IERC20(this.stackedToken).balanceOf(address(this).address);
if (balance1.gt(0)) {
IERC20(this.stackedToken).transferFrom(address(this).address, msg.sender, balance1);
}
const [balance2,] = IERC20(this.rewardToken).balanceOf(address(this).address);
if (balance2.gt(0)) {
IERC20(this.rewardToken).transferFrom(address(this).address, msg.sender, balance2);
}
emit('Reset', []);
}
balanceOf(stacker) {
stacker = stacker.toLowerCase();
let stackedAmount = number(0);
if (stacker in this.stackers) {
stackedAmount = this.stackers[stacker].stackedAmount;
}
return [stackedAmount];
}
deposit(_amount) {
// stacking
require(this.stackedToken != '', 'NOT_INITIALIZED');
require(_amount.gt(0), 'INVALID_AMOUNT');
if (this.totalStacked.eq(0)) {
this.lastMint = block.timestamp;
}
const _rewardAmount = this.payStackerRewards(msg.sender); // mise a jour de la pool + on encaisse les rewards potentiels, pour repartir sur des comptes à zero à partir de ce deposit
IERC20(this.stackedToken).transferFrom(msg.sender, address(this).address, _amount);
if (! (msg.sender in this.stackers)) {
this.stackers[msg.sender] = new StackerInfo;
}
const stacker = this.stackers[msg.sender];
stacker.stackedAmount = stacker.stackedAmount.add(_amount);
this.totalStacked = this.totalStacked.add(_amount);
stacker.rewardDebt = stacker.stackedAmount.mul(this.accRewardPerStackToken).div(1e12);
//this._earn();
emit('Deposit', [msg.sender, _amount]);
}
withdraw(_amount) {
// unstacking => Withdraw staked tokens and collect reward tokens
require(this.stackedToken != '', 'NOT_INITIALIZED');
require(_amount.gt(0), 'Nothing to withdraw');
require(! _amount.gt(this.totalStacked), 'INSUFFICIENT_TOTAL');
require(msg.sender in this.stackers, 'INVALID_OWNER');
require(! _amount.gt(this.stackers[msg.sender].stackedAmount), 'Withdraw amount exceeds balance');
const _rewardAmount = this.payStackerRewards(msg.sender); // mise a jour de la pool + on encaisse les rewards potentiels, pour repartir sur des comptes à zero à partir de ce withdraw
const stacker = this.stackers[msg.sender];
stacker.stackedAmount = stacker.stackedAmount.sub(_amount);
this.totalStacked = this.totalStacked.sub(_amount);
IERC20(this.stackedToken).transfer(msg.sender, _amount);
stacker.rewardDebt = stacker.stackedAmount.mul(this.accRewardPerStackToken).div(1e12);
emit('Withdrawal', [msg.sender, _amount, _rewardAmount]);
}
getPendingRewards() {
// rewards à minter
let pendingRewards = number(0);
if (this.totalStacked.gt(0)) {
const duration = block.timestamp.sub(this.lastMint); // milliseconds depuis le dernier mint
if (duration.gt(0)) {
const periodsCount = duration.div(this.mintPeriod); // nbPeriods depuis le dernier mint
if (periodsCount.gt(0)) {
pendingRewards = periodsCount.mul(this.rewardsPerPeriod);
}
}
}
return [pendingRewards]; // retourne le nb de rewards POUVANT ÊTRE mintés
}
updatePool() {
const [pendingRewards,] = this.getPendingRewards();
if (pendingRewards.gt(0)) {
this.lastMint = block.timestamp;
IERC20(this.rewardToken).mint(address(this).address, pendingRewards); // on augmente la balance rewardToken (pour le present contract)
const extraRewardPerStackToken = pendingRewards.mul(1e12).div(this.totalStacked);
this.accRewardPerStackToken = this.accRewardPerStackToken.add(extraRewardPerStackToken);
emit('UpdatePool', [pendingRewards, extraRewardPerStackToken]);
}
}
getStackerAvailableRewards(stackerAddress) {
stackerAddress = stackerAddress.toLowerCase();
let stackerRewardAmount = number(0);
const [pendingRewards,] = this.getPendingRewards();
if (stackerAddress in this.stackers) {
const extraRewardPerStackToken = pendingRewards.mul(1e12).div(this.totalStacked);
const accRewardPerStackToken = this.accRewardPerStackToken.add(extraRewardPerStackToken);
const stacker = this.stackers[stackerAddress];
stackerRewardAmount = stacker.stackedAmount.mul(accRewardPerStackToken).div(1e12).sub(stacker.rewardDebt);
}
return [stackerRewardAmount];
}
payStackerRewards(stackerAddress) {
// harvest
stackerAddress = stackerAddress.toLowerCase();
this.updatePool();
const [stackerRewardAmount,] = this._updateStacker(stackerAddress);
return [stackerRewardAmount];
}
_updateStacker(stackerAddress) {
let stackerRewardAmount = number(0);
if (stackerAddress in this.stackers) {
const stacker = this.stackers[stackerAddress];
[stackerRewardAmount, ] = this.getStackerAvailableRewards(stackerAddress);
stacker.rewardDebt = stacker.stackedAmount.mul(this.accRewardPerStackToken).div(1e12);
if (stackerRewardAmount.gt(0)) {
IERC20(this.rewardToken).transfer(stackerAddress, stackerRewardAmount);
emit('UpdateStacker', [stackerAddress, stackerRewardAmount]);
}
}
return [stackerRewardAmount];
}
}
// Events
StackingService.prototype.Initialize.event = true;
StackingService.prototype.Initialize.inputs = ['address indexed', 'address indexed'];
StackingService.prototype.UpdateStacker.event = true;
StackingService.prototype.UpdateStacker.inputs = ['address indexed', 'uint256'];
StackingService.prototype.Reset.event = true;
StackingService.prototype.Deposit.event = true;
StackingService.prototype.Deposit.inputs = ['address indexed', 'uint256'];
StackingService.prototype.Withdrawal.event = true;
StackingService.prototype.Withdrawal.inputs = ['address indexed', 'uint256', 'uint256'];
StackingService.prototype.UpdatePool.event = true;
StackingService.prototype.UpdatePool.inputs = ['uint256', 'uint256'];
StackingService.prototype.UpdateStacker.event = true;
StackingService.prototype.UpdateStacker.inputs = ['address indexed', 'uint256'];
// Methods
StackingService.prototype.initialize.inputs = ['address', 'address'];
StackingService.prototype.balanceOf.view = true;
StackingService.prototype.balanceOf.inputs = ['address'];
StackingService.prototype.balanceOf.outputs = ['uint256'];
StackingService.prototype.deposit.inputs = ['uint256'];
StackingService.prototype.withdraw.inputs = ['uint256'];
StackingService.prototype.getPendingRewards.view = true;
StackingService.prototype.getPendingRewards.outputs = ['uint256'];
StackingService.prototype.getStackerAvailableRewards.view = true;
StackingService.prototype.getStackerAvailableRewards.inputs = ['address'];
StackingService.prototype.getStackerAvailableRewards.outputs = ['uint256'];
StackingService.prototype.payStackerRewards.inputs = ['address'];
StackingService.prototype.payStackerRewards.outputs = ['uint256'];
StackingService.prototype._updateStacker.internal = true;
return StackingService;
",
codeHash: "0x4abec54ff2c7059d3e4d3a9d0a2500599e6d19caac54fd3d2ee939560fb416e5",
codeAbi: {
0x8da5cb5b: {
constant: true,
"inputs": [],
name: "owner",
outputs: [
{
name: "",
type: "string"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x5b5c0f23: {
constant: true,
"inputs": [],
name: "stackedToken",
outputs: [
{
name: "",
type: "string"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0xf7c618c1: {
constant: true,
"inputs": [],
name: "rewardToken",
outputs: [
{
name: "",
type: "string"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x29eae70d: {
constant: true,
"inputs": [],
name: "totalStacked",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x585dd2e4: {
constant: true,
"inputs": [],
name: "accRewardPerStackToken",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x834ea32d: {
constant: true,
"inputs": [],
name: "stackers",
outputs: [
{
name: "",
type: "string"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x586fc5b5: {
constant: true,
"inputs": [],
name: "lastMint",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x4c498203: {
constant: true,
"inputs": [],
name: "mintPeriod",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0x978db419: {
constant: true,
"inputs": [],
name: "rewardsPerPeriod",
outputs: [
{
name: "",
type: "uint256"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0xa8ac9b50: {
constant: true,
"inputs": [],
name: "prototype",
outputs: [
{
name: "",
type: "string"
}
],
payable: false,
stateMutability: "view",
type: "function"
},
0xdc90fed0: {
inputs: [
{
name: "stackedToken",
type: "address",
indexed: true
},
{
name: "rewardToken",
type: "address",
indexed: true
}
],
name: "Initialize",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0x6423db34: {
"inputs": [],
name: "Reset",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0xe1fffcc4: {
inputs: [
{
name: "sender",
type: "address",
indexed: true
},
{
name: "amount",
type: "uint256",
indexed: false
}
],
name: "Deposit",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0xdf273cb6: {
inputs: [
{
name: "sender",
type: "address",
indexed: true
},
{
name: "amount",
type: "uint256",
indexed: false
},
{
name: "rewardAmount",
type: "uint256",
indexed: false
}
],
name: "Withdrawal",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0xb35b339e: {
inputs: [
{
name: "pendingRewards",
type: "uint256",
indexed: false
},
{
name: "extraRewardPerStackToken",
type: "uint256",
indexed: false
}
],
name: "UpdatePool",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0xc063ef91: {
inputs: [
{
name: "stackerAddress",
type: "address",
indexed: true
},
{
name: "stackerRewardAmount",
type: "uint256",
indexed: false
}
],
name: "UpdateStacker",
"outputs": [],
stateMutability: "nonpayable",
type: "event"
},
0x485cc955: {
inputs: [
{
name: "stackedToken",
type: "address"
},
{
name: "rewardToken",
type: "address"
}
],
name: "initialize",
"outputs": [],
stateMutability: "nonpayable",
type: "function"
},
0xd826f88f: {
"inputs": [],
name: "reset",
"outputs": [],
stateMutability: "nonpayable",
type: "function"
},
0x70a08231: {
inputs: [
{
name: "stacker",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
0xb6b55f25: {
inputs: [
{
name: "_amount",
type: "uint256"
}
],
name: "deposit",
"outputs": [],
stateMutability: "nonpayable",
type: "function"
},
0x2e1a7d4d: {
inputs: [
{
name: "_amount",
type: "uint256"
}
],
name: "withdraw",
"outputs": [],
stateMutability: "nonpayable",
type: "function"
},
0xd9621f9e: {
"inputs": [],
name: "getPendingRewards",
outputs: [
{
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
0xe3161ddd: {
"inputs": [],
name: "updatePool",
"outputs": [],
stateMutability: "nonpayable",
type: "function"
},
0x6e4b5056: {
inputs: [
{
name: "stackerAddress",
type: "address"
}
],
name: "getStackerAvailableRewards",
outputs: [
{
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
0x04c57c17: {
inputs: [
{
name: "stackerAddress",
type: "address"
}
],
name: "payStackerRewards",
outputs: [
{
name: "",
type: "uint256"
}
],
stateMutability: "nonpayable",
type: "function"
}
},
contractName: "StackingService",
storage: {
prototype: {
address: "0xc3349025e73b4746d79a30ade1200e5dd2d8f754"
},
owner: "0xccf8ba457dcad7ee6a0361c96846a0f79744b113",
stackedToken: "0x2347d36cf0d94b98bab6d6d41c6f94d7214830ad",
rewardToken: "0x92c8b8729d850d99c34c50ab2846ec36169e0024",
totalStacked: {
type: "BigNumber",
hex: "0x00"
string: "0"
ether: "0.0"
},
accRewardPerStackToken: {
type: "BigNumber",
hex: "0x00"
string: "0"
ether: "0.0"
},
"stackers": {},
lastMint: {
type: "BigNumber",
hex: "0x00"
string: "0"
ether: "0.0"
},
mintPeriod: {
type: "BigNumber",
hex: "0xea60"
string: "60000"
ether: "0.00000000000006"
},
rewardsPerPeriod: {
type: "BigNumber",
hex: "0x056bc75e2d63100000"
string: "100000000000000000000"
ether: "100.0"
}
},
storageHash: "0x5a50fe34cf2ae9d8f44abe7c1f52bd1095fe10415487b5143d6dcadad1774bb1",
savedOnBlockNumber: {
type: "BigNumber",
hex: "0x0c"
string: "12"
ether: "0.000000000000000012"
}
}