Skip to content

Commit

Permalink
Merge pull request #70 from Tenderize/nv/multi-testnet
Browse files Browse the repository at this point in the history
Add UnlockTime and CurrentTime to Adapter
  • Loading branch information
kyriediculous committed Nov 30, 2023
2 parents c8d7c76 + dbfc3af commit 78b890b
Show file tree
Hide file tree
Showing 23 changed files with 99 additions and 30 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
},
"scripts": {
"clean": "rimraf cache out",
"lint": "yarn lint:sol && yarn prettier:check",
"lint:sol": "forge fmt --check && yarn solhint \"{src,test}/**/*.sol\"",
"lint": "yarn lint:sol && yarn prettier:write",
"lint:sol": "yarn solhint \"{src,test,script}/**/*.sol\"",
"postinstall": "husky install",
"prettier:check": "prettier --check \"**/*.{json,md,yml}\"",
"prettier:write": "prettier --write \"**/*.{json,md,yml}\""
Expand Down
2 changes: 2 additions & 0 deletions script/Adapter_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable no-console

pragma solidity >=0.8.19;

import { Script } from "forge-std/Script.sol";
Expand Down
2 changes: 2 additions & 0 deletions script/Tenderize_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable no-console

pragma solidity >=0.8.19;

import { Script, console2 } from "forge-std/Script.sol";
Expand Down
2 changes: 2 additions & 0 deletions script/XYZ_Data.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable no-console

pragma solidity >=0.8.19;

import { Script, console2 } from "forge-std/Script.sol";
Expand Down
2 changes: 2 additions & 0 deletions script/XYZ_Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable no-console

pragma solidity >=0.8.19;

import { Script, console2 } from "forge-std/Script.sol";
Expand Down
2 changes: 2 additions & 0 deletions script/XYZ_Faucet.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable no-console

pragma solidity >=0.8.19;

import { Script, console2 } from "forge-std/Script.sol";
Expand Down
4 changes: 4 additions & 0 deletions src/adapters/Adapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ interface Adapter is IERC165 {

function unlockMaturity(uint256 unlockID) external view returns (uint256);

function unlockTime() external view returns (uint256);

function currentTime() external view returns (uint256);

function stake(address validator, uint256 amount) external;

function unstake(address validator, uint256 amount) external returns (uint256 unlockID);
Expand Down
8 changes: 8 additions & 0 deletions src/adapters/GraphAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ contract GraphAdapter is Adapter {
}
}

function unlockTime() external view override returns (uint256) {
return GRAPH.thawingPeriod();
}

function currentTime() external view override returns (uint256) {
return block.number;
}

function stake(address validator, uint256 amount) external override {
GRT.safeApprove(address(GRAPH), amount);
GRAPH.delegate(validator, amount);
Expand Down
8 changes: 8 additions & 0 deletions src/adapters/LivepeerAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ contract LivepeerAdapter is Adapter {
}
}

function unlockTime() external view override returns (uint256) {
return LIVEPEER_ROUNDS.roundLength() * LIVEPEER.unbondingPeriod();
}

function currentTime() external view override returns (uint256) {
return block.number;
}

function stake(address validator, uint256 amount) public {
LPT.approve(address(LIVEPEER), amount);
LIVEPEER.bond(amount, validator);
Expand Down
9 changes: 9 additions & 0 deletions src/adapters/PolygonAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ contract PolygonAdapter is Adapter {
return u.withdrawEpoch + WITHDRAW_DELAY;
}

function unlockTime() external pure override returns (uint256) {
return WITHDRAW_DELAY;
}

function currentTime() external view override returns (uint256) {
return MATIC_STAKE_MANAGER.epoch();
}

function stake(address validator, uint256 amount) external override {
// approve tokens
POLY.safeApprove(address(MATIC_STAKE_MANAGER), amount);
Expand Down Expand Up @@ -128,6 +136,7 @@ contract PolygonAdapter is Adapter {

// This call will revert if there are no rewards
// In which case we don't throw, just return the current staked amount.
// solhint-disable-next-line no-empty-blocks
try validatorShares.restake() { }
catch {
return currentStake;
Expand Down
2 changes: 2 additions & 0 deletions src/adapters/interfaces/ILivepeer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ interface ILivepeerBondingManager {
returns (uint256 amount, uint256 withdrawRound);

function isRegisteredTranscoder(address _transcoder) external view returns (bool);

function unbondingPeriod() external view returns (uint256);
}

interface ILivepeerRoundsManager {
Expand Down
3 changes: 3 additions & 0 deletions src/adapters/interfaces/IPolygon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

// SPDX-License-Identifier: MIT

// solhint-disable func-name-mixedcase

pragma solidity >=0.8.19;

struct DelegatorUnbond {
Expand All @@ -12,6 +14,7 @@ struct DelegatorUnbond {
interface IMaticStakeManager {
function getValidatorId(address user) external view returns (uint256);
function getValidatorContract(uint256 validatorId) external view returns (address);
function epoch() external view returns (uint256);
}

interface IValidatorShares {
Expand Down
19 changes: 8 additions & 11 deletions src/tenderizer/Tenderizer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ contract Tenderizer is TenderizerImmutableArgs, TenderizerEvents, TToken, Multic
uint256 private constant MAX_FEE = 0.005e6; // 0.5%
uint256 private constant FEE_BASE = 1e6;

// solhint-disable-next-line no-empty-blocks
constructor(address _registry, address _unlocks) TenderizerImmutableArgs(_registry, _unlocks) { }

// @inheritdoc TToken
Expand Down Expand Up @@ -174,10 +175,6 @@ contract Tenderizer is TenderizerImmutableArgs, TenderizerEvents, TToken, Multic
return string.concat(ERC20(asset()).symbol(), "-", addressToString(validator()));
}

function _adapter() internal view returns (Adapter) {
return Adapter(_registry().adapter(asset()));
}

function previewDeposit(uint256 assets) external view returns (uint256) {
uint256 out = abi.decode(_staticcall(address(this), abi.encodeCall(this._previewDeposit, (assets))), (uint256));
Storage storage $ = _loadStorage();
Expand All @@ -201,31 +198,31 @@ contract Tenderizer is TenderizerImmutableArgs, TenderizerEvents, TToken, Multic
// using a `staticcall` to `this`.
// This is a hacky workaround while better solidity features are being developed.
function _previewDeposit(uint256 assets) public returns (uint256) {
return abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().previewDeposit, (assets))), (uint256));
return abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().previewDeposit, (assets))), (uint256));
}

function _previewWithdraw(uint256 unlockID) public returns (uint256) {
return abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().previewWithdraw, (unlockID))), (uint256));
return abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().previewWithdraw, (unlockID))), (uint256));
}

function _unlockMaturity(uint256 unlockID) public returns (uint256) {
return abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().unlockMaturity, (unlockID))), (uint256));
return abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().unlockMaturity, (unlockID))), (uint256));
}
// ===============================================================================================================

function _rebase(address validator, uint256 currentStake) internal returns (uint256 newStake) {
newStake = abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().rebase, (validator, currentStake))), (uint256));
newStake = abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().rebase, (validator, currentStake))), (uint256));
}

function _stake(address validator, uint256 amount) internal {
_adapter()._delegatecall(abi.encodeCall(_adapter().stake, (validator, amount)));
adapter()._delegatecall(abi.encodeCall(adapter().stake, (validator, amount)));
}

function _unstake(address validator, uint256 amount) internal returns (uint256 unlockID) {
unlockID = abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().unstake, (validator, amount))), (uint256));
unlockID = abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().unstake, (validator, amount))), (uint256));
}

function _withdraw(address validator, uint256 unlockID) internal returns (uint256 withdrawAmount) {
withdrawAmount = abi.decode(_adapter()._delegatecall(abi.encodeCall(_adapter().withdraw, (validator, unlockID))), (uint256));
withdrawAmount = abi.decode(adapter()._delegatecall(abi.encodeCall(adapter().withdraw, (validator, unlockID))), (uint256));
}
}
5 changes: 5 additions & 0 deletions src/tenderizer/TenderizerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pragma solidity >=0.8.19;
import { Clone } from "clones/Clone.sol";
import { Unlocks } from "core/unlocks/Unlocks.sol";
import { Registry } from "core/registry/Registry.sol";
import { Adapter } from "core/adapters/Adapter.sol";

/// @title TenderizerImmutableArgs
/// @notice Immutable arguments for Tenderizer
Expand Down Expand Up @@ -46,6 +47,10 @@ abstract contract TenderizerImmutableArgs is Clone {
return _getArgAddress(20); // start: 20 end: 39
}

function adapter() public view returns (Adapter) {
return Adapter(_registry().adapter(asset()));
}

function _registry() internal view returns (Registry) {
return Registry(registry);
}
Expand Down
9 changes: 8 additions & 1 deletion src/unlocks/Unlocks.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import { ERC721 } from "solmate/tokens/ERC721.sol";
import { ERC20 } from "solmate/tokens/ERC20.sol";

import { Adapter } from "core/adapters/Adapter.sol";
import { Tenderizer } from "core/tenderizer/Tenderizer.sol";
import { Registry } from "core/registry/Registry.sol";
import { Renderer } from "core/unlocks/Renderer.sol";
Expand All @@ -27,6 +28,7 @@ pragma solidity >=0.8.19;
struct Metadata {
uint256 amount;
uint256 maturity;
uint256 progress;
uint256 unlockId;
string symbol;
string name;
Expand Down Expand Up @@ -104,9 +106,14 @@ contract Unlocks is ERC721 {
(address tenderizer, uint256 unlockId) = _decodeTokenId(tokenId);
address asset = Tenderizer(tenderizer).asset();

Adapter adapter = Tenderizer(tenderizer).adapter();
uint256 maturity = Tenderizer(tenderizer).unlockMaturity(unlockId);
uint256 currentTime = adapter.currentTime();

return Metadata({
amount: Tenderizer(tenderizer).previewWithdraw(unlockId),
maturity: Tenderizer(tenderizer).unlockMaturity(unlockId),
maturity: maturity,
progress: maturity > currentTime ? 100 - (maturity - currentTime) * 100 / adapter.unlockTime() : 100,
unlockId: unlockId,
symbol: ERC20(asset).symbol(),
name: ERC20(asset).name(),
Expand Down
8 changes: 4 additions & 4 deletions src/utils/TWAP.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

pragma solidity >=0.8.19;

import "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";
import "@uniswap/v3-core/libraries/TickMath.sol";
import "@uniswap/v3-core/libraries/FixedPoint96.sol";
import "@uniswap/v3-core/libraries/FullMath.sol";
import { IUniswapV3Pool } from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";
import { TickMath } from "@uniswap/v3-core/libraries/TickMath.sol";
import { FixedPoint96 } from "@uniswap/v3-core/libraries/FixedPoint96.sol";
import { FullMath } from "@uniswap/v3-core/libraries/FullMath.sol";

library TWAP {
function getSqrtTwapX96(address uniswapV3Pool, uint32 twapInterval) internal view returns (uint160 sqrtPriceX96) {
Expand Down
3 changes: 3 additions & 0 deletions test/adapters/PolygonAdapter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
//
// Copyright (c) Tenderize Labs Ltd

// solhint-disable state-visibility
// solhint-disable func-name-mixedcase

pragma solidity >=0.8.19;

import { Test, stdError } from "forge-std/Test.sol";
Expand Down
4 changes: 2 additions & 2 deletions test/helpers/StakingXYZ.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ import { MockERC20 } from "solmate/test/utils/mocks/MockERC20.sol";
pragma solidity >=0.8.19;

contract StakingXYZ {
address immutable token;
address private immutable token;
uint256 public nextRewardTimeStamp;

uint256 public immutable APR;
uint256 public constant APR_PRECISION = 1e6;
uint256 public constant SECONDS_IN_A_YEAR = 31_536_000;

uint256 immutable unlockTime;
uint256 public immutable unlockTime;

struct Unlock {
uint256 amount;
Expand Down
12 changes: 10 additions & 2 deletions test/helpers/XYZAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import { StakingXYZ } from "./StakingXYZ.sol";
pragma solidity >=0.8.19;

contract XYZAdapter is Adapter {
address immutable STAKINGXYZ;
address immutable XYZ_TOKEN;
address private immutable STAKINGXYZ;
address private immutable XYZ_TOKEN;

constructor(address _stakingXYZ, address _xyz) {
STAKINGXYZ = _stakingXYZ;
Expand All @@ -43,6 +43,14 @@ contract XYZAdapter is Adapter {
(, maturity) = StakingXYZ(STAKINGXYZ).unlocks(address(this), unlockID);
}

function unlockTime() external view returns (uint256) {
return StakingXYZ(STAKINGXYZ).unlockTime();
}

function currentTime() external view returns (uint256) {
return block.timestamp;
}

function stake(address, uint256 amount) external {
ERC20(XYZ_TOKEN).approve(STAKINGXYZ, amount);
StakingXYZ(STAKINGXYZ).stake(amount);
Expand Down
5 changes: 1 addition & 4 deletions test/tenderizer/Tenderizer.harness.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@ import { Unlocks } from "core/unlocks/Unlocks.sol";
import { Registry } from "core/registry/Registry.sol";

// solhint-disable func-name-mixedcase
// solhint-disable no-empty-blocks

contract TenderizerHarness is Tenderizer {
constructor(address _registry, address _unlocks) Tenderizer(_registry, _unlocks) { }

function exposed_adapter() public view returns (Adapter) {
return _adapter();
}

function exposed_registry() public view returns (Registry) {
return _registry();
}
Expand Down
2 changes: 1 addition & 1 deletion test/tenderizer/Tenderizer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ contract TenderizerTest is TenderizerSetup, TenderizerEvents {
assertEq(address(tenderizer.validator()), validator, "invalid validator");
assertEq(address(tenderizer.exposed_registry()), registry, "invalid registry");
assertEq(address(tenderizer.exposed_unlocks()), unlocks, "invalid unlocks");
assertEq(address(tenderizer.exposed_adapter()), adapter, "invalid adapter");
assertEq(address(tenderizer.adapter()), adapter, "invalid adapter");
}

function test_PreviewDeposit() public {
Expand Down
2 changes: 1 addition & 1 deletion test/unlocks/Renderer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ contract RendererTest is Test {
address private validator = vm.addr(4);
uint256 private id = 1;
Metadata private metadata =
Metadata({ amount: 100, maturity: 1000, unlockId: id, symbol: "GRT", name: "Graph", validator: validator });
Metadata({ amount: 100, maturity: 1000, progress: 100, unlockId: id, symbol: "GRT", name: "Graph", validator: validator });
RendererV1 private rendererV1;

bytes32 internal constant IMPL_SLOT = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
Expand Down
Loading

0 comments on commit 78b890b

Please sign in to comment.