{"id":35227282,"url":"https://github.com/lidofinance/easy-track","last_synced_at":"2026-04-02T02:16:57.362Z","repository":{"id":42003300,"uuid":"375369428","full_name":"lidofinance/easy-track","owner":"lidofinance","description":"Easy Track Motions for Lido DAO governance","archived":false,"fork":false,"pushed_at":"2026-03-22T10:15:17.000Z","size":19913,"stargazers_count":10,"open_issues_count":19,"forks_count":8,"subscribers_count":28,"default_branch":"master","last_synced_at":"2026-03-23T00:47:46.559Z","etag":null,"topics":["protocol"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lidofinance.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-06-09T13:42:04.000Z","updated_at":"2026-03-19T13:41:03.000Z","dependencies_parsed_at":"2024-06-06T11:20:25.312Z","dependency_job_id":"2b22a1f5-7096-40b9-9e3d-737ec212b0ac","html_url":"https://github.com/lidofinance/easy-track","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/lidofinance/easy-track","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lidofinance%2Feasy-track","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lidofinance%2Feasy-track/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lidofinance%2Feasy-track/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lidofinance%2Feasy-track/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lidofinance","download_url":"https://codeload.github.com/lidofinance/easy-track/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lidofinance%2Feasy-track/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31294478,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T01:43:37.129Z","status":"online","status_checked_at":"2026-04-02T02:00:08.535Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["protocol"],"created_at":"2025-12-30T01:28:56.609Z","updated_at":"2026-04-02T02:16:57.354Z","avatar_url":"https://github.com/lidofinance.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Easy Track\n\n## Problem\n\nLido DAO governance currently relies on Aragon voting model. This means DAO approves or rejects proposals via direct governance token voting. Though transparent and reliable, it is not a convenient way to make decisions only affecting small groups of Lido DAO members. Besides, direct token voting doesn't exactly reflect all the decision making processes within the Lido DAO and is often used only to rubber-stamp an existing consensus.\nThere are a few natural sub-governance groups within the DAO, e.g. validators committee, financial operations team and LEGO committee. Every day they need to take routine actions only related to their field of expertise. The decisions they make hardly ever spark any debate in the community, and votings on such decisions often struggle to attract wider DAO attention and thus, to pass.\n\n## Solution\n\nEasy Track frictionless motions are solution to this problem.\nEasy Track motion is a lightweight voting considered to have passed if the minimum objections threshold hasn’t been exceeded. As opposed to traditional Aragon votings, Easy Track motions are cheaper (no need to vote ‘pro’, token holders only have to vote ‘contra’ if they have objections) and easier to manage (no need to ask broad DAO community vote on proposals sparking no debate).\n\n## Use cases for Easy Track motions\n\nThere are four types of votings run periodically by the Lido DAO that are proposed to be wrapped into the new Easy Track motions.\n\n- Node Operators increasing staking limits\n- Funds being allocated into reward programs\n- Funds being allocated to LEGO program\n- Funds being allocated to the whitelisted referral partners\n\nSee [specification.md](https://github.com/lidofinance/easy-track/blob/master/specification.md) for full specification.\n\n## EVMScript Factory Requirements\n\n### Methods Compatibility\n\n**Every EVMScript factory must implement [`IEVMScriptFactory`](https://github.com/lidofinance/easy-track/blob/master/contracts/interfaces/IEVMScriptFactory.sol) interface.**\n\nMethods from this interface are used by EasyTrack at the motion lifecycle.\n\n### Accessibility For Aragon Voting\n\n**Every action done by EasyTrack must be allowed to do also by Aragon Voting.**\n\nThis requirement fills automatically in cases when easy tracks do actions provided by the Aragon application. But for contracts outside the Aragon ecosystem access to Voting must be provided explicitly. To grant such access you can use role-based control access contracts from the OpenZeppelin package. To see an example of how this pattern was used in EVMScript factories see the `RewardProgramsRegistry.sol` contract.\n\n### Onchain EVMScript calldata decoding\n\n**Each EVMScript factory must provide the method `decodeEVMScriptCallData` to decode the calldata used in it.**\n\nThis provides a flexible way to check which parameters were used to create motion even without access to UI.\n\n### Carefully review added factories\n\n**Each EVMScript factory must be carefully reviewed and tested before adding to the EasyTrack.**\n\nRemember, that EVMScript generated by the factory might be run with potentially dangerous permissions. Be sure, that generated EVMScript makes exactly what it has to do.\n\n### Choose the narrowest set of permissions\n\n**When adds new EVMScript factory use only required permissions**\n\nPermissions for EVMScript factory must contain only methods used by generated EVMScript.\n\n## Project Setup\n\nTo use the tools that this project provides, please pull the repository from GitHub and install its dependencies as follows.\n\n```bash\ngit clone https://github.com/lidofinance/easy-track\ncd easy-track\nnvm install\nnpm ci\n\npoetry install\npoetry run brownie networks import network-config.yaml True\npoetry shell\n```\n\nCompile the Smart Contracts:\n\n```bash\nbrownie compile # add `--size` to see contract compiled sizes\n```\n\nTo run scripts that require EVM script decoding, tests with contract name resolution via Etherscan or contract source code verification in deploy scripts, you must provide an Etherscan API token. Use the following command:\n\n```bash\nexport ETHERSCAN_TOKEN=\u003cetherscan_api_key\u003e\n```\n\n## Scripts\n\n### `deploy.py`\n\nContains script to deploy main Easy Track contracts with EVM Script factories.\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - id of brownie's account which will deploy contracts. Might be skipped if run on `development` network.\n- `LEGO_PROGRAM_VAULT` - address of Lido's LEGO program\n- `LEGO_COMMITTEE_MULTISIG` - address allowed to create motions to top up LEGO program\n- `REWARD_PROGRAMS_MULTISIG` - address allowed to create motions to add, remove or top up reward program\n- `PAUSE_ADDRESS` - address to grant PAUSE_ROLE\n\nNext optional variables can be set:\n\n- `UNPAUSE_ADDRESS` - address to grant UNPAUSE_ROLE\n- `CANCEL_ADDRESS` - address to grant CANCEL_ROLE\n\n### `deploy_vaults_factories_base.py`\n\nContains script to deploy base OperatorGrid EVM Script factories for vault management.\nScript deploys factories for:\n\n- RegisterGroupsInOperatorGrid - for registering new operator groups\n- UpdateGroupsShareLimitInOperatorGrid - for updating group share limits\n- RegisterTiersInOperatorGrid - for registering new tiers\n- AlterTiersInOperatorGrid - for altering existing tier parameters\n\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - id of brownie's account which will deploy contracts. Might be skipped if run on `development` network.\n\n### `deploy_vaults_factories_with_adapter.py`\n\nContains script to deploy vault-specific EVM Script factories that work through VaultsAdapter.\nScript deploys VaultsAdapter and factories for:\n\n- SetJailStatusInOperatorGrid - for setting jail status of vaults\n- UpdateVaultsFeesInOperatorGrid - for updating vault fees\n- ForceValidatorExitsInVaultHub - for forcing validator exits\n- SocializeBadDebtInVaultHub - for socializing bad debt\n- SetLiabilitySharesTargetInVaultHub - for setting liability shares target\n\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - id of brownie's account which will deploy contracts. Might be skipped if run on `development` network.\n\n### `final_check.py`\n\nContains script to validate deployed setup of EasyTrack in mainnet network.\n\nScript accepts next optional ENV variables:\n\n- `GRANT_PERMISSIONS_VOTING_ID` - id of voting where permissions `CREATE_PAYMENTS_ROLE` and `SET_NODE_OPERATOR_LIMIT_ROLE` granted to `EVMScriptExecutor`. If this variable is passed, the simulation will not create new voting to add permissions to `EVMScriptExecutor`.\n\n### `grant_executor_permissions.py`\n\nCreates Aragon's Voting to grants permissions to EVMScriptExecutor required to execute EVMScripts generated by EVMScript factories. After voting creation checks that after execution all permissions will be granted correctly.\n\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - id of brownie's account which will deploy contracts. To create a voting account must have LDO Tokens. Might be skipped if run on a `development` network.\n- `EVM_SCRIPT_EXECUTOR` - address to grant permissions.\n\n### `revoke_all_permissions.py`\n\nCreates Aragon's Voting to revoke all granted permissions from EVMScriptExecutor. After voting creation checks that after execution EVMScriptExecutor will has no any permissions.\n\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - id of brownie's account which will deploy contracts. To create a voting account must have LDO Tokens. Might be skipped if run on a `development` network.\n- `EVM_SCRIPT_EXECUTOR` - address to grant permissions.\n\n### `renounce_all_roles.py`\n\nSends transactions to renounce `DEFAULT_ADMIN_ROLE`, `PAUSE_ROLE`, `UNPAUSE_ROLE`, `CANCEL_ROLE` roles from EasyTrack contract deployed in mainnet [`0xF0211b7660680B49De1A7E9f25C65660F0a13Fea`](https://etherscan.io/address/0xf0211b7660680b49de1a7e9f25c65660f0a13fea).\n\nScript requires next ENV variables to be set:\n\n- `DEPLOYER` - address of the account that renounces roles\n\n## Tests\n\nSet rpc url:\n```bash\nexport MAINNET_RPC_URL=\u003cYOUR_RPC_URL\u003e\n```\n\nThe fastest way to run the tests is:\n\n```bash\nbrownie test --network mainnet-fork\n```\n\nRun tests with coverage and gas profiling:\n\n```bash\nbrownie test --network mainnet-fork --coverage --gas\n```\n\nRun tests only for stVaults factories on Hoodi fork:\n```bash\nexport HOODI_RPC_URL=\u003cYOUR_HOODI_RPC_URL\u003e\n./scripts/run_vaults_tests.sh\n```\n\n\u003e Note: Holesky support will be removed in upcoming upgrades.\n\n### Coverage notes\n\n#### Immutable issues\n\nCurrent brownie version has problems with coverage reports for some contracts. Contracts which use `immutable` variables don't get on the resulting report. Details can be found in this [issue](https://github.com/eth-brownie/brownie/issues/1087). Easy Track uses `immutable` modifier in next contracts:\n\n- [TrustedCaller.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/TrustedCaller.sol#L9)\n- [EVMScriptExecutor.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EvmScriptExecutor.sol#L39)\n- [AddRewardProgram.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EVMScriptFactories/AddRewardProgram.sol#L24)\n- [IncreaseNodeOperatorStakingLimit.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EVMScriptFactories/IncreaseNodeOperatorStakingLimit.sol#L50)\n- [RemoveRewardProgram.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EVMScriptFactories/RemoveRewardProgram.sol#L23)\n- [TopUpLegoProgram.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EVMScriptFactories/TopUpLegoProgram.sol#L26)\n- [TopUpRewardProgram.sol](https://github.com/lidofinance/easy-track/blob/a72858804481009f2e09508ffbf93d8a4aee6c84/contracts/EVMScriptFactories/TopUpRewardPrograms.sol#L27)\n- [TopUpAllowedRecipients.sol](https://github.com/lidofinance/easy-track/blob/522ae893f6c03516354a8d1950b29b3203adae52/contracts/EVMScriptFactories/TopUpAllowedRecipients.sol#L29)\n\nThe workaround for the coverage problem is removing the `immutable` modifier from the above contracts. Without modifier above contracts will be listed in the coverage report.\n\n#### No-branching issue\n\nAnother brownie issue is that some functions do not get into the coverage report. For example `decodeEVMScriptCallData` of `RemoveAllowedRecipient` contract:\n\n```\n  contract: RemoveAllowedRecipient - 100.0%\n    RemoveAllowedRecipient.createEVMScript - 100.0%\n```\n\nAlthough in brownie coverage report explorer (`brownie gui`) in statements section the function body is highlighted green, which means it is covered.\n\nIt seems such functions are not reflected in % coverage report, due to absence of branching in the function body. Adding dummy branching brings them to the report.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flidofinance%2Feasy-track","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flidofinance%2Feasy-track","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flidofinance%2Feasy-track/lists"}