Skip to content

Commit

Permalink
Merge pull request #69 from Tenderize/nv/multi-testnet
Browse files Browse the repository at this point in the history
feat: StakingXYZ rewrite and multi-token testnet preparation
  • Loading branch information
kyriediculous authored Nov 24, 2023
2 parents b1e40ce + f0258b5 commit c8d7c76
Show file tree
Hide file tree
Showing 16 changed files with 365 additions and 102 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# files
*.env
*.env.*
*.html
*.log
.DS_Store
Expand Down
4 changes: 4 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ wrap_comments = true
fail_on_revert = false
runs = 256
depth = 100

[rpc_endpoints]
# Uncomment to enable the RPC server
arbitrum_goerli = "${ARBITRUM_GOERLI_RPC}"
2 changes: 1 addition & 1 deletion script/Tenderize_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract Tenderize_Deploy is Script {
// Contracts are deployed deterministically.
// e.g. `foo = new Foo{salt: salt}(constructorArgs)`
// The presence of the salt argument tells forge to use https://github.com/Arachnid/deterministic-deployment-proxy
bytes32 private constant salt = 0x0;
bytes32 private constant salt = bytes32(uint256(1));

function run() public {
string memory json_output;
Expand Down
104 changes: 90 additions & 14 deletions script/XYZ_Data.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,101 @@ import { Factory } from "core/factory/Factory.sol";
contract XYZ_Data is Script {
bytes32 private constant salt = 0x0;

function run() public {
MockERC20 XYZ = MockERC20(0xf1C65dFa90eF3B6369f540bC32D7143cA4233c1e);
address constant LPT = 0x042Dd916727378Cf913B7719a5071D5789139feb;
address constant GRT = 0xdcfF31D3311BAbf2f14EC947BdAcE2404D3C922f;
address constant POL = 0x3e278E3fEE9A2E82437d9eAa0a7836095CbD8070;

address[] livepeer = [
0x07CA020fDDE5c57C1C3A783befdb08929cf77fec, // coaction
0x47A907a0BD1627D71cD14430A721D1550d6D6f58, // nightnode
0xBD677e96a755207D348578727AA57A512C2022Bd, // pixelfield
0xb1c579757622D8Ca7bD42542cb0325de1C8E1F8d, // video-miner.eth
0x10b21af759129F32C6064ADfb85d3eA2a8C0209c, // ruthlessmango.eth
0x269EBeee083CE6f70486a67dC8036A889bF322A9, // thomasblock.eth
0xf4e8Ef0763BCB2B1aF693F5970a00050a6aC7E1B, // livepool.eth
0x847791cBF03be716A7fe9Dc8c9Affe17Bd49Ae5e, // captain-stronk.eth
0xBe8770603dAf200b1Fa136aD354BA854928e602B, // titan node
0x9D61ae5875E89036FBf6059f3116d01a22ACe3C8, // authority-null
0x10e0A91E652b05e9C7449ff457Cf2E96C3037fB7, // interprtr.eth
0xdc28F2842810D1a013aD51DE174D02eABA192dC7 // pon-node.eth
];

address[] graph = [
0x87Eba079059B75504c734820d6cf828476754B83, //data nexus
0x07CA020fDDE5c57C1C3A783befdb08929cf77fec, // coaction
0x326c584E0F0eaB1f1f83c93CC6Ae1aCC0feba0Bc, // graphtronauts
0xa3276E7ab0a162F6A3b5aA6B3089aCcBAA65d12e, // stakesquid
0x6f8a032B4b1Ee622EF2F0fC091bdbB98CFAE81A3, // semiotic
0x1A99DD7d916117a523f3CE6510dcFD6BcEAB11E7, // p-ops.eth
0xDFE6Ad10265AfC05831b332FDA6F5Bc1Ad9d79ce, // p2p.org
0x8842ea85732F94Feeb9cF1Ccc7D357C63658E7A4, // chorus-one
0x43cd17fa4c21440d71d34061F9A6AA9f99093049, // chainflow
0x048cFedf907c4C9dDD11ff882380906E78E84BbE, // blockdaemon
0x0fd8FD1dC8162148cb9413062FE6C6B144335Dbf, // protofire
0xc35649Ae99Be820c7B200a0ADD09b96D7032d232, // hashquark
0x1EFEcb61A2f80Aa34d3b9218B564a64D05946290, // figment
0x62A0BD1d110FF4E5b793119e95Fc07C9d1Fc8c4a, // ellipfra
0xef46D5fe753c988606E6F703260D816AF53B03EB, // staked
0x7DDf0C8cB0167870Bf7CC5368792C93AEEb15430, // stake2earn
0x0b9d582B7FDD387bA13Ad7f453d49aF255a8ED5E, // Dapplooker
0x269EBeee083CE6f70486a67dC8036A889bF322A9, // thomasblock.eth
0x1B7E0068cA1d7929c8c56408d766e1510E54d98D // suntzu.eth
];

address[] polygon = [
0x127685D6dD6683085Da4B6a041eFcef1681E5C9C, // vault staking
0x959A4D857b7071c38878BEb9DC77051b5Fed1DFd, // girnaar
0x87Eba079059B75504c734820d6cf828476754B83, // data nexus
0x62fB676db64f87fd1602048106476C6036D44c92, // blocks united
0x8842ea85732F94Feeb9cF1Ccc7D357C63658E7A4, // chorus-one
0x9eaD03F7136Fc6b4bDb0780B00a1c14aE5A8B6d0, // luganodes
0x742d13F0b2A19C823bdd362b16305e4704b97A38, // infStones
0xF0245F6251Bef9447A08766b9DA2B07b28aD80B0, // allnodes
0x048cFedf907c4C9dDD11ff882380906E78E84BbE, // blockdaemon
0xb95D435df3f8b2a8D8b9c2b7c8766C9ae6ED8cc9, // everstake
0x3A9DF5dFcB4cC102ce20D40434A2b1BacA9eAfD3, // atlas staking
0x1EFEcb61A2f80Aa34d3b9218B564a64D05946290, // figment
0xC6869257205e20c2A43CB31345DB534AECB49F6E, // staking4all
0x43cd17fa4c21440d71d34061F9A6AA9f99093049, // chainflow
0xef46D5fe753c988606E6F703260D816AF53B03EB, // staked
0xa8B52F02108AA5F4B675bDcC973760022D7C6020, // twinstake
0xDFE6Ad10265AfC05831b332FDA6F5Bc1Ad9d79ce, // p2p.org
0x414B4b5a2A0e303B89360EdA83598aB7702EAe04, // Vader73
0x6b2Ed7E4b12A544ca7D215fED85dC16240D64aea, // defimatic
0xc35649Ae99Be820c7B200a0ADD09b96D7032d232, // hashquark
0x8E9700392F9246a6c5B32eE3EcEF586F156Ed683, // newroad network
0xbc6044f4a1688D8B8596A9f7D4659e09985EeBE6 // stake.fish
];

function run() public {
uint256 privKey = vm.envUint("PRIVATE_KEY");
address me = vm.addr(privKey);
vm.startBroadcast(privKey);

XYZ.mint(me, 10_000_000_000 ether);
address tenderizer_1 = 0x35D2BC5Fc0884a7A24E9B1D723A4d99922d788EB;
address tenderizer_2 = 0xD58Fed21106A046093086903909478AD96D310a8;
address tenderizer_3 = 0x2eaC4210B90D13666f7E88635096BdC17C51FB70;
XYZ.approve(tenderizer_1, 10_000_000_000 ether);
XYZ.approve(tenderizer_2, 10_000_000_000 ether);
XYZ.approve(tenderizer_3, 10_000_000_000 ether);
// address tenderizer_1 = 0x35D2BC5Fc0884a7A24E9B1D723A4d99922d788EB;
// address tenderizer_2 = 0xD58Fed21106A046093086903909478AD96D310a8;
// address tenderizer_3 = 0x2eaC4210B90D13666f7E88635096BdC17C51FB70;
// XYZ.approve(tenderizer_1, 10_000_000_000 ether);
// XYZ.approve(tenderizer_2, 10_000_000_000 ether);
// XYZ.approve(tenderizer_3, 10_000_000_000 ether);

// Tenderizer(tenderizer_1).deposit(me, 35_983 ether);
// Tenderizer(tenderizer_2).deposit(me, 12_821 ether);
// Tenderizer(tenderizer_3).deposit(me, 5123 ether);

// Tenderizer(tenderizer_1).unlock(1202 ether);

address factory = vm.envAddress("FACTORY");
address asset = vm.envAddress("ASSET");
address[] memory validators;

Tenderizer(tenderizer_1).deposit(me, 35_983 ether);
Tenderizer(tenderizer_2).deposit(me, 12_821 ether);
Tenderizer(tenderizer_3).deposit(me, 5123 ether);
if (asset == LPT) validators = livepeer;
if (asset == GRT) validators = graph;
if (asset == POL) validators = polygon;

Tenderizer(tenderizer_1).unlock(1202 ether);
for (uint256 i = 0; i < validators.length; i++) {
address t = Factory(factory).newTenderizer(asset, validators[i]);
console2.log("Validator: %s", validators[i]);
console2.log("Tenderizer: %s", t);
}
}
}
37 changes: 19 additions & 18 deletions script/XYZ_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,32 @@ import { Registry } from "core/registry/Registry.sol";
import { Factory } from "core/factory/Factory.sol";

contract XYZ_Deploy is Script {
bytes32 private constant salt = 0x0;
bytes32 private constant salt = bytes32(uint256(1));

function run() public {
address registry = vm.envAddress("REGISTRY");
address factory = vm.envAddress("FACTORY");

vm.startBroadcast(vm.envUint("PRIVATE_KEY"));
string memory name = vm.envString("NAME");
string memory symbol = vm.envString("SYMBOL");

MockERC20 XYZ = new MockERC20{salt: salt}("XYZ", "XYZ", 18);
console2.log("XYZ Token: ", address(XYZ));
StakingXYZ stakingXYZ = new StakingXYZ{salt: salt}(address(XYZ));
console2.log("StakingXYZ: ", address(stakingXYZ));
uint256 unlockTime = vm.envUint("UNLOCK_TIME");
uint256 baseAPR = vm.envUint("BASE_APR");
uint256 totalSupply = vm.envUint("TOTAL_SUPPLY");

uint256 privKey = vm.envUint("PRIVATE_KEY");

vm.startBroadcast(privKey);
address me = vm.addr(privKey);

MockERC20 XYZ = new MockERC20{salt: salt}(name, symbol, 18);
console2.log(string.concat(symbol, " Token: "), address(XYZ));
// mint supply
XYZ.mint(me, totalSupply);
StakingXYZ stakingXYZ = new StakingXYZ{salt: salt}(address(XYZ), unlockTime, baseAPR);
console2.log(string.concat(symbol, " Staking :"), address(stakingXYZ));
XYZAdapter adapter = new XYZAdapter{salt: salt}(address(stakingXYZ), address(XYZ));
console2.log("XYZ Adapter: ", address(adapter));
console2.log(string.concat(symbol, " Adapter: "), address(adapter));
// Register XYZ adapter
Registry(registry).registerAdapter(address(XYZ), address(adapter));

// Register some mock validators
address[] memory validators = new address[](3);
validators[0] = 0x597aD7F7A1C9F8d0121a9e949Cca7530F2B25ef6;
validators[1] = 0x6C06d3246FbB77C4Ad75480E03d2a0A8eaF68121;
validators[2] = 0xf909aC60C647a14DB3663dA5EcF5F8eCbE324395;

for (uint256 i = 0; i < validators.length; i++) {
Factory(factory).newTenderizer(address(XYZ), validators[i]);
}
}
}
50 changes: 50 additions & 0 deletions script/XYZ_Faucet.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
//
// _____ _ _
// |_ _| | | (_)
// | | ___ _ __ __| | ___ _ __ _ _______
// | |/ _ \ '_ \ / _` |/ _ \ '__| |_ / _ \
// | | __/ | | | (_| | __/ | | |/ / __/
// \_/\___|_| |_|\__,_|\___|_| |_/___\___|
//
// Copyright (c) Tenderize Labs Ltd

pragma solidity >=0.8.19;

import { Script, console2 } from "forge-std/Script.sol";
import { MockERC20 } from "solmate/test/utils/mocks/MockERC20.sol";
import { StakingXYZ } from "../test/helpers/StakingXYZ.sol";
import { XYZAdapter } from "../test/helpers/XYZAdapter.sol";
import { Registry } from "core/registry/Registry.sol";

import { Factory } from "core/factory/Factory.sol";
import { TokenFaucet } from "../test/helpers/Faucet.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";

contract XYZ_Faucet is Script {
bytes32 private constant salt = bytes32(uint256(1));

function run() public {
uint256 privKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(privKey);

address tokenAddress = vm.envAddress("TOKEN");
ERC20 token = ERC20(tokenAddress);
uint256 seedAmount = vm.envUint("SEED_AMOUNT");
uint256 cooldown = vm.envUint("COOLDOWN");
uint256 requestAmount = vm.envUint("REQUEST_AMOUNT");

address me = vm.addr(privKey);
console2.log("privKey", privKey);
console2.log("me", me);
console2.log("balance", token.balanceOf(me));

cooldown = cooldown != 0 ? cooldown : 1 days;
requestAmount = requestAmount != 0 ? requestAmount : 1000 ether;

address faucet = address(new TokenFaucet{salt: salt}(token, requestAmount, cooldown));
token.transfer(faucet, seedAmount);

console2.log("Faucet: ", faucet);
}
}
28 changes: 28 additions & 0 deletions script/anvil_xyz.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,36 @@ export FACTORY=0x3cB1E8d050E126bBE05782c7206Cf53856FDaA77

forge script script/Tenderize_Deploy.s.sol:Tenderize_Deploy --fork-url http://127.0.0.1:8545 --broadcast --private-key $PRIVATE_KEY -vvvv


# Deploy Livepeer
# Parameters
export NAME="Livepeer"
export SYMBOL="LPT"
export BASE_APR="280000"
export UNLOCK_TIME="604800"
export TOTAL_SUPPLY="30000000000000000000000000"
export ID=0
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --fork-url http://127.0.0.1:8545 --broadcast --private-key $PRIVATE_KEY -vvvv

# Deploy Graph
export NAME="The Graph"
export SYMBOL="GRT"
export BASE_APR="170000"
export UNLOCK_TIME="2419200"
export TOTAL_SUPPLY="10000000000000000000000000000"
export ID=1
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --fork-url http://127.0.0.1:8545 --broadcast --private-key $PRIVATE_KEY -vvvv

# Deploy Polygon
export NAME="Polygon"
export SYMBOL="POL"
export BASE_APR="110000"
export UNLOCK_TIME="201600"
export TOTAL_SUPPLY="10000000000000000000000000000"
export ID=2
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --fork-url http://127.0.0.1:8545 --broadcast --private-key $PRIVATE_KEY -vvvv


read -r -d '' _ </dev/tty
echo "Closing Down Anvil"
pkill -9 anvil
44 changes: 44 additions & 0 deletions script/arbgoerli_testnet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
set -x

forge build

curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","id":67,"method":"anvil_setCode","params": ["0x4e59b44847b379578588920ca78fbf26c0b4956c","0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3"]}' 127.0.0.1:8545

source .env

# Deterministic
export REGISTRY=0x6232894e592F104FB561c1Fb59a52ea01ee7D867
export FACTORY=0x62536191D4EB10D4CA5909D60232593A1b40BE10

# forge script script/Tenderize_Deploy.s.sol:Tenderize_Deploy --rpc-url ${ARBITRUM_GOERLI_RPC} --broadcast --private-key $PRIVATE_KEY -vvvv


# Deploy Livepeer
# Parameters
export NAME="Livepeer"
export SYMBOL="LPT"
export BASE_APR="280000"
export UNLOCK_TIME="604800"
export TOTAL_SUPPLY="30000000000000000000000000"
export ID=0
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --rpc-url ${ARBITRUM_GOERLI_RPC} --broadcast --private-key $PRIVATE_KEY -vvvv

# Deploy Graph
export NAME="The Graph"
export SYMBOL="GRT"
export BASE_APR="170000"
export UNLOCK_TIME="2419200"
export TOTAL_SUPPLY="10000000000000000000000000000"
export ID=1
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --rpc-url ${ARBITRUM_GOERLI_RPC} --broadcast --private-key $PRIVATE_KEY -vvvv

# Deploy Polygon
export NAME="Polygon"
export SYMBOL="POL"
export BASE_APR="110000"
export UNLOCK_TIME="201600"
export TOTAL_SUPPLY="10000000000000000000000000000"
export ID=2
forge script script/XYZ_Deploy.s.sol:XYZ_Deploy --rpc-url ${ARBITRUM_GOERLI_RPC} --broadcast --private-key $PRIVATE_KEY -vvvv

23 changes: 8 additions & 15 deletions src/adapters/GraphAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,17 @@ contract GraphAdapter is Adapter {
Epoch memory currentEpoch = $.epochs[$.currentEpoch];
IGraphStaking.DelegationPool memory delPool = GRAPH.delegationPools(validator);

uint256 _tokensPerShare = delPool.tokens * 1 ether / delPool.shares;
uint256 _tokensPerShare = delPool.shares != 0 ? delPool.tokens * 1 ether / delPool.shares : 1 ether;
newStake = currentStake;

// Account for rounding error of -1 or +1
// This occurs due to a slight change in ratio because of new delegations or withdrawals,
// rather than an effective reward or loss
if (
(_tokensPerShare >= $.tokensPerShare && _tokensPerShare - $.tokensPerShare <= 1)
|| (_tokensPerShare < $.tokensPerShare && $.tokensPerShare - _tokensPerShare <= 1)
) {
return currentStake;
return newStake;
}

IGraphStaking.Delegation memory delegation = GRAPH.getDelegation(validator, address(this));
Expand All @@ -159,29 +161,20 @@ contract GraphAdapter is Adapter {
// Last epoch amount should be synced with Delegation.tokensLocked
if ($.currentEpoch > 0) $.epochs[$.currentEpoch - 1].amount = delegation.tokensLocked;

if (staked < oldStake) {
// handle a potential slash
// A slash needs to be distributed accross 2 parts
// - Stake still to unlock (current Unlocks epoch)
// - Current Staked amount (total supply)
uint256 slash = oldStake - staked;

// Slash for the current epoch slashCurrent is calculated as
// slashCurrent = (slash - slashLast) * currentEpochAmount / ( currentEpochAmount + currentStake)
uint256 slashCurrent = slash * currentEpoch.amount / oldStake;
currentEpoch.amount -= slashCurrent;
} else if (staked > oldStake) {
if (staked > oldStake) {
// handle rewards
// To reduce long waiting periods we want to still reward users
// for which their stake is still to be unlocked
// because technically it is not unlocked from the Graph either
// We do this by adding the rewards to the current epoch
uint256 currentEpochAmount = (staked - oldStake) * currentEpoch.amount / oldStake;
currentEpoch.amount += currentEpochAmount;
} else {
return newStake;
}

$.epochs[$.currentEpoch] = currentEpoch;
$.tokensPerShare = _tokensPerShare == 0 ? 1 ether : _tokensPerShare;
$.tokensPerShare = _tokensPerShare;

// slash/rewards is already accounted for in $.epochs[$.currentEpoch].amount
newStake = staked - currentEpoch.amount;
Expand Down
6 changes: 5 additions & 1 deletion src/tenderizer/Tenderizer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,11 @@ contract Tenderizer is TenderizerImmutableArgs, TenderizerEvents, TToken, Multic
}

function previewDeposit(uint256 assets) external view returns (uint256) {
return abi.decode(_staticcall(address(this), abi.encodeCall(this._previewDeposit, (assets))), (uint256));
uint256 out = abi.decode(_staticcall(address(this), abi.encodeCall(this._previewDeposit, (assets))), (uint256));
Storage storage $ = _loadStorage();
uint256 _totalShares = $._totalShares; // Saves an extra SLOAD if slot is non-zero
uint256 shares = convertToShares(out);
return _totalShares == 0 ? out : shares * $._totalSupply / _totalShares;
}

function previewWithdraw(uint256 unlockID) external view returns (uint256) {
Expand Down
Loading

0 comments on commit c8d7c76

Please sign in to comment.