Skip to content

Commit

Permalink
Modify our Lynx strategy so that TACoApplication can be deployed on G…
Browse files Browse the repository at this point in the history
…oerli, and child application etc. on Mumbai.

The bridge is non-existent but owners of the contract can execute txs to similate bridge/synching functionality.
Separate deployment scripts for Goerli deployment, and Mumbai.
  • Loading branch information
derekpierre committed Sep 25, 2023
1 parent 48c43e5 commit 3ab22f2
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 177 deletions.
192 changes: 17 additions & 175 deletions contracts/contracts/testnet/LynxSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,190 +8,32 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../coordination/ITACoRootToChild.sol";
import "../coordination/ITACoChildToRoot.sol";
import "../coordination/TACoChildApplication.sol";
import "../TACoApplication.sol";

contract LynxRootApplication is Ownable, ITACoChildToRoot {
struct StakingProviderInfo {
address operator;
bool operatorConfirmed;
uint64 operatorStartTimestamp;
uint96 authorized;
}

uint96 public immutable minimumAuthorization = 40000000000000000000000;
uint256 public immutable minOperatorSeconds = 3600;
ITACoRootToChild public childApplication;
mapping(address => StakingProviderInfo) public stakingProviderInfo;
address[] public stakingProviders;
mapping(address => address) internal _stakingProviderFromOperator;

function setChildApplication(ITACoRootToChild _childApplication) external onlyOwner {
childApplication = _childApplication;
}

function updateAuthorization(address _stakingProvider, uint96 _amount) external onlyOwner {
if (address(childApplication) != address(0)) {
childApplication.updateAuthorization(_stakingProvider, _amount);
}
}

function confirmOperatorAddress(address _operator) external override {
address stakingProvider = _stakingProviderFromOperator[_operator];
if (stakingProvider == address(0)) {
return;
}
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
if (!info.operatorConfirmed) {
info.operatorConfirmed = true;
}
}

//
// Required TACoApplication functions
//
function stakingProviderFromOperator(address _operator) public view returns (address) {
return _stakingProviderFromOperator[_operator];
}

function getOperatorFromStakingProvider(
address _stakingProvider
) public view returns (address) {
return stakingProviderInfo[_stakingProvider].operator;
}

function getActiveStakingProviders(
uint256 _startIndex,
uint256 _maxStakingProviders
)
external
view
returns (uint256 allAuthorizedTokens, uint256[2][] memory activeStakingProviders)
{
uint256 endIndex = stakingProviders.length;
require(_startIndex < endIndex, "Wrong start index");
if (_maxStakingProviders != 0 && _startIndex + _maxStakingProviders < endIndex) {
endIndex = _startIndex + _maxStakingProviders;
}
activeStakingProviders = new uint256[2][](endIndex - _startIndex);
allAuthorizedTokens = 0;

uint256 resultIndex = 0;
for (uint256 i = _startIndex; i < endIndex; i++) {
address stakingProvider = stakingProviders[i];
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
uint256 eligibleAmount = info.authorized;
activeStakingProviders[resultIndex][0] = uint256(uint160(stakingProvider));
activeStakingProviders[resultIndex++][1] = eligibleAmount;
allAuthorizedTokens += eligibleAmount;
}
assembly {
mstore(activeStakingProviders, resultIndex)
}
}

function isAuthorized(address _stakingProvider) public view returns (bool) {
return stakingProviderInfo[_stakingProvider].authorized > 0;
}

function authorizedStake(address _stakingProvider) public view returns (uint96) {
return stakingProviderInfo[_stakingProvider].authorized;
}
contract LynxMockTACoChildApplication is Ownable, ITACoChildToRoot {
ITACoChildToRoot public immutable rootApplication;

function isOperatorConfirmed(address _operator) public view returns (bool) {
address stakingProvider = _stakingProviderFromOperator[_operator];
StakingProviderInfo storage info = stakingProviderInfo[stakingProvider];
return info.operatorConfirmed;
}

function getStakingProvidersLength() external view returns (uint256) {
return stakingProviders.length;
}

function bondOperator(address _stakingProvider, address _operator) external onlyOwner {
StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider];
address previousOperator = info.operator;
constructor(ITACoChildToRoot _rootApplication) {
require(
_operator != previousOperator,
"Specified operator is already bonded with this provider"
address(_rootApplication) != address(0),
"Address for root application must be specified"
);
// If this staker had a operator ...
if (previousOperator != address(0)) {
// Remove the old relation "operator->stakingProvider"
_stakingProviderFromOperator[previousOperator] = address(0);
}

if (_operator != address(0)) {
require(
_stakingProviderFromOperator[_operator] == address(0),
"Specified operator is already in use"
);
// Set new operator->stakingProvider relation
_stakingProviderFromOperator[_operator] = _stakingProvider;
}

if (info.operatorStartTimestamp == 0) {
stakingProviders.push(_stakingProvider);
}

// Bond new operator (or unbond if _operator == address(0))
info.operator = _operator;
info.operatorStartTimestamp = uint64(block.timestamp);
info.operatorConfirmed = false;
if (address(childApplication) != address(0)) {
childApplication.updateOperator(_stakingProvider, _operator);
}
rootApplication = _rootApplication;
}

//
// Remaining IApplication functions
//

// solhint-disable-next-line no-empty-blocks
function withdrawRewards(address stakingProvider) external {}

function authorizationIncreased(
address _stakingProvider,
// solhint-disable-next-line no-unused-vars
uint96 _fromAmount,
uint96 _toAmount
) external onlyOwner {
require(
_stakingProvider != address(0) && _toAmount > 0,
"Input parameters must be specified"
);
require(_toAmount >= minimumAuthorization, "Authorization must be greater than minimum");

StakingProviderInfo storage info = stakingProviderInfo[_stakingProvider];
require(
_stakingProviderFromOperator[_stakingProvider] == address(0) ||
_stakingProviderFromOperator[_stakingProvider] == _stakingProvider,
"A provider can't be an operator for another provider"
);

info.authorized = _toAmount;
if (address(childApplication) != address(0)) {
childApplication.updateAuthorization(_stakingProvider, _toAmount);
}
}

function authorizationDecreaseRequested(
address stakingProvider,
uint96 fromAmount,
uint96 toAmount // solhint-disable-next-line no-empty-blocks
) external {}

function involuntaryAuthorizationDecrease(
address stakingProvider,
uint96 fromAmount,
uint96 toAmount // solhint-disable-next-line no-empty-blocks
) external {}

// solhint-disable-next-line no-unused-vars
function availableRewards(address stakingProvider) external view returns (uint96) {
return 0;
function confirmOperatorAddress(address operator) external override onlyOwner {
rootApplication.confirmOperatorAddress(operator);
}
}

contract LynxMockRootApplication is Ownable, ITACoChildToRoot, ITACoRootToChild {
// Goerli <---------> Mumbai ....
// LynxTACoApplication LynxMockTACoApplication <---> LynxTACoChildApplication
//
//
// Registry:
// ^ TACoApplication
// ^ TACoChildApplication
contract LynxMockTACoApplication is Ownable, ITACoChildToRoot, ITACoRootToChild {
ITACoRootToChild public childApplication;

function setChildApplication(ITACoRootToChild _childApplication) external onlyOwner {
Expand Down
4 changes: 2 additions & 2 deletions deployments/constructor_params/lynx/lynx-alpha-13-params.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"LynxRootApplication": {},
"LynxMockRootApplication": {},
"LynxTACoChildApplication": {
"_rootApplication": "$LynxRootApplication"
"_rootApplication": "$LynxMockRootApplication"
},
"LynxRitualToken": {
"_totalSupplyOfTokens": 10000000000000000000000000
Expand Down
24 changes: 24 additions & 0 deletions deployments/constructor_params/lynx/lynx-alpha-13-root-params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"LynxRitualToken": {
"_totalSupplyOfTokens": 10000000000000000000000000
},
"ThresholdStakingForTACoApplicationMock": {},
"ProxyAdmin": {},
"TACoApplication": {
"_token": "$LynxRitualToken",
"_tStaking": "$ThresholdStakingForTACoApplicationMock",
"_minimumAuthorization": 40000000000000000000000,
"_minOperatorSeconds": 3600,
"_rewardDuration": 604800,
"_deauthorizationDuration": 5184000,
"_commitmentDurationOptions": [15724800, 31449600]
},
"TransparentUpgradeableProxy": {
"_logic": "$TACoApplication",
"admin_": "$ProxyAdmin",
"_data": "$EMPTY_BYTES"
},
"LynxMockTACoChildApplication": {
"_rootApplication": "$TACoApplication"
}
}
78 changes: 78 additions & 0 deletions scripts/deploy_lynx_root.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/python3

from ape import networks, project
from scripts.constants import (
ARTIFACTS_DIR,
CONSTRUCTOR_PARAMS_DIR,
CURRENT_NETWORK,
LOCAL_BLOCKCHAIN_ENVIRONMENTS,
)
from scripts.deployment import prepare_deployment
from scripts.registry import registry_from_ape_deployments

VERIFY = CURRENT_NETWORK not in LOCAL_BLOCKCHAIN_ENVIRONMENTS
CONSTRUCTOR_PARAMS_FILEPATH = CONSTRUCTOR_PARAMS_DIR / "lynx" / "lynx-alpha-13-root-params.json"
REGISTRY_FILEPATH = ARTIFACTS_DIR / "lynx" / "lynx-alpha-13-root-registry.json"

OZ_DEPENDENCY = project.dependencies["openzeppelin"]["4.9.1"]


def main():
"""
This script deploys only the Lynx TACo Root Application.
"""

deployer, params = prepare_deployment(
params_filepath=CONSTRUCTOR_PARAMS_FILEPATH,
registry_filepath=REGISTRY_FILEPATH,
)

reward_token = deployer.deploy(*params.get(project.LynxRitualToken), **params.get_kwargs())

mock_threshold_staking = deployer.deploy(
*params.get(project.ThresholdStakingForTACoApplicationMock), **params.get_kwargs()
)

proxy_admin = deployer.deploy(*params.get(OZ_DEPENDENCY.ProxyAdmin), **params.get_kwargs())

_ = deployer.deploy(*params.get(project.TACoApplication), **params.get_kwargs())

proxy = deployer.deploy(
*params.get(OZ_DEPENDENCY.TransparentUpgradeableProxy), **params.get_kwargs()
)

print("\nWrapping TACoApplication in proxy")
taco_application = project.TACoApplication.at(proxy.address)

print("\nSetting TACoApplication on ThresholdStakingMock")
mock_threshold_staking.setApplication(taco_application.address, sender=deployer)

print("\nInitialize TACoApplication proxy")
taco_application.initialize(sender=deployer)

mock_taco_child = deployer.deploy(
*params.get(project.LynxMockTACoChildApplication), **params.get_kwargs()
)

print(f"\nSetting child application {mock_taco_child.address} on TACoApplication")
taco_application.setChildApplication(mock_taco_child.address, sender=deployer)

deployments = [
reward_token,
proxy_admin,
mock_threshold_staking,
proxy,
taco_application,
mock_taco_child,
]

output_filepath = registry_from_ape_deployments(
deployments=deployments, output_filepath=REGISTRY_FILEPATH
)
print(f"(i) Registry written to {output_filepath}!")

if VERIFY:
etherscan = networks.provider.network.explorer
for deployment in deployments:
print(f"(i) Verifying {deployment.contract_type.name}...")
etherscan.publish_contract(deployment.address)

0 comments on commit 3ab22f2

Please sign in to comment.