Bootstrap Bootstrap
            {
   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" } }