{"id":29040724,"url":"https://github.com/pushchain/push-chain-migration","last_synced_at":"2026-02-03T05:02:42.294Z","repository":{"id":297209161,"uuid":"886664180","full_name":"pushchain/push-chain-migration","owner":"pushchain","description":null,"archived":false,"fork":false,"pushed_at":"2025-07-03T10:44:44.000Z","size":248,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-03T11:45:46.794Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pushchain.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":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-11-11T11:38:07.000Z","updated_at":"2025-06-20T08:17:28.000Z","dependencies_parsed_at":"2025-06-16T10:41:07.857Z","dependency_job_id":"90d4ce90-f301-4978-8294-b436f80f3b47","html_url":"https://github.com/pushchain/push-chain-migration","commit_stats":null,"previous_names":["push-protocol/token_and_migration","push-protocol/push-chain-migration","pushchain/push-chain-migration"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pushchain/push-chain-migration","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pushchain%2Fpush-chain-migration","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pushchain%2Fpush-chain-migration/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pushchain%2Fpush-chain-migration/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pushchain%2Fpush-chain-migration/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pushchain","download_url":"https://codeload.github.com/pushchain/push-chain-migration/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pushchain%2Fpush-chain-migration/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29033716,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T02:28:16.591Z","status":"ssl_error","status_checked_at":"2026-02-03T02:27:48.904Z","response_time":96,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2025-06-26T14:36:38.339Z","updated_at":"2026-02-03T05:02:42.281Z","avatar_url":"https://github.com/pushchain.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PUSH Token Migration System\n\nThis project implements a secure, two-phase token migration system for the PUSH token ecosystem, enabling users to migrate from the existing PUSH token to a new implementation. The project is built using Solidity and Foundry, with transparent upgradeable proxies for future extensibility.\n\n## Details on Migration\nThe migration of tokens is from:\n- **Old Token:** ERC20 Push Token on Ethereum [@0xf418588522d5dd018b425e472991e52ebbeeeeee](https://etherscan.io/token/0xf418588522d5dd018b425e472991e52ebbeeeeee)\n- **New Token:** Native $PUSH Token on Push Chain. ( *Push Chain is a EVM-Compatible chain on Cosmos with a native token called PUSH*)\n\n**Migration Amounts**\n- Token migration is planned to be at a 1:15 ratio (1 Push Protocol token = 15 Push Chain tokens).\n- The token holders on Ethereum will be required to lock their token in the `MigrationLocker` contract.\n- The token holders will be able to release/claim their migrated tokens using the `MigrationRelease` contract on Push Chain.\n- The release of tokens will be a two phase release:\na. **Instant Release:** Allows users to claim 50% of their migrated tokens ( 7.5 out of 15 ratio ) instantly.\nb. **Vested Release:** Allows users to claim the remaininig 50% of their migrated token 90 days after the instant release.\n\n**Migration Proofs**\n- The verification of token locked is done using Merkle Proofs.\n- When users lock their tokens, an event emission occurs which is recorded offchain.\n- These emissions are then used to generate proofs for each deposit by a given address.\n- Users can use these proofs later on Push Chain's `MigrationRelease` contract to claim their migration tokens.\n\n---\n\n## System Architecture\n\nThe migration system consists of two main components:\n\n1. **MigrationLocker**: A contract that allows users to lock their PUSH tokens for migration. *To Deployed on Ethereum Mainnet*\n2. **MigrationRelease**: A contract that enables whitelisted users to claim their migrated tokens in two phases. *To Deployed on Push Mainnet*\n\n### Technical Stack\n\n- **Solidity**: ^0.8.20\n- **Framework**: Foundry, with Hardhat for deployments\n- **Proxy Pattern**: OpenZeppelin Transparent Upgradeable Proxy\n- **Verification Mechanism**: Merkle Tree for secure, gas-efficient verification\n\n## Contract Details\n\n### MigrationLocker.sol\n\nThe MigrationLocker contract is responsible for allowing users to lock their PUSH tokens as part of the migration process.\n\n**Key Features:**\n- Token locking mechanism with unique identifier generation\n- Openzeppelin's Pausable library to prevent/allow locking - Owner Controlled\n- Proper access control with Ownable2Step pattern\n- Token burning capability for migrated tokens\n- Emergency fund recovery functionality\n\n**Main Functions:**\n- `lock(uint _amount, address _recipient)`: Allows users to lock tokens for migration\n- `burn(uint _amount)`: Burns tokens that have been successfully migrated\n- `pause()`: Pauses the contract to prevent new locks\n- `unpause()`: Unpauses the contract to allow new locks\n- `initiateNewEpoch()`: Starts a new epoch for organizing locks\n- `recoverFunds(address _token, address _to, uint _amount)`: Emergency function to recover funds\n\n**Events:**\n- `Locked(address caller, address recipient, uint amount, uint epoch)`: Emitted when tokens are locked\n\n### Epoch System in MigrationLocker\n\nThe MigrationLocker contract uses an epoch-based system to organize token locks into time periods for efficient Merkle Tree generation.\n\nIt should be noted, however, that epochs are owner-controlled.\n\n**How it Works:**\n- Each epoch represents a specific time period for token locking\n- The current epoch is recorded when users lock tokens via the `Locked` event\n- Owners can start new epochs using `initiateNewEpoch()`\n- Each epoch tracks its start block for off-chain event processing\n- Epochs help organize locks into batches for systematic Merkle Tree generation and verification\n\nThis system ensures organized processing of token locks across different time periods.\n\n**Expected Workflow**\n1. Owner initiates LOCKING with `initiateNewEpoch()`, i.e., Epoch-1\n2. Duration for how long EPOCH-1 will run is flexible and decided by owner, hence owner-controlled.\n3. Users starts locking token in EPOCH-1. All such locks emit out `Locked(msg.sender, _recipient, _amount, 1)`. These event and params will be used for merkle proof creation.\n4. After 30 days, for example, owner initiates pause() and triggers `initiateNewEpoch(). i.e., EPOCH-2.\n5. Same locking cycle starts again, but now locks emits out `Locked(msg.sender, _recipient, _amount, 2)`.\n\n---\n### MigrationRelease.sol\n\nThe MigrationRelease contract manages the release of migrated tokens to eligible users based on Merkle proofs.\n\n**Key Features:**\n- Two-phase token release (instant + vested)\n- Merkle Tree-based verification for gas efficiency\n- Fixed allocation ratios for instant and vested portions\n- Fair and transparent distribution mechanism\n- Fund recovery safety mechanism\n\n## Important Constants and Params\n\n- `VESTING_PERIOD`: 90 days\n- `INSTANT_RATIO`: 75 (interpreted as 7.5x)\n- `VESTING_RATIO`: 75 (interpreted as 7.5x)\n\n**Release Model:**\n- **Instant Release**: \na. As users provide proof of their fund-lock, 50% of the locked amount is immediately released.\nb. Once released, we record the timestamp of instant release.\nc. Only after 90 days of this timestamp, users can unlock their vested release.\n\n- **Vested Release**: \na. Vested release is the release that takes place 90 days after instant release. \nb. Merkle proof is still required but the 90 days check is additionally imposed.\n\n**Main Functions:**\n- `releaseInstant(address _recipient, uint _amount, uint _epoch, bytes32[] calldata _merkleProof)`: Claims instant portion\n- `releaseVested(address _recipient, uint _amount, uint _epoch)`: Claims vested portion after vesting period\n- `setMerkleRoot(bytes32 _merkleRoot)`: Updates the Merkle root for verification\n- `addFunds()`: Adds funds to the contract for distribution\n- `pause()`: Pauses the contract to prevent claims\n- `unpause()`: Unpauses the contract to allow claims\n- `recoverFunds(address _token, address _to, uint _amount)`: Emergency function to recover funds\n\n**Events:**\n- `ReleasedInstant(address indexed recipient, uint indexed amount, uint indexed epochId)`\n- `ReleasedVested(address indexed recipient, uint indexed amount, uint indexed epochId)`\n- `FundsAdded(uint indexed amount, uint indexed timestamp)`\n- `MerkleRootUpdated(bytes32 indexed oldMerkleRoot, bytes32 indexed newMerkleRoot)`\n\n## Merkle Tree Implementation\n\nThe system uses a Merkle Tree for efficient and secure verification of eligible claims. This approach significantly reduces gas costs compared to on-chain storage of all claims.\n\n### Merkle Tree Generation Process\n\n1. Events are collected from the MigrationLocker contract using `fetchAndStoreEvents.js`\n2. Each lock event produces a leaf in the Merkle Tree with `(address, amount, epochId)` as parameters\n3. The Merkle root is calculated and set in the MigrationRelease contract\n4. Users can provide proofs to verify their eligibility when claiming tokens\n\n### Technical Implementation\n\nThe utility scripts in the `script/utils` folder handle the Merkle tree generation process:\n\n- **merkle.js**: Core Merkle tree implementation with functions to hash leaves, generate roots, create proofs, and verify claims using the (address, amount, epoch) format.\n- **fetchAndStoreEvents.js**: Fetches all \"Locked\" events from the MigrationLocker contract, groups them by address and epoch, combines amounts for duplicate addresses within the same epoch, and saves the processed claims.\n- **getRoot.js**: Simple utility that loads processed claims and generates the Merkle root for deployment to the MigrationRelease contract.\n- **config.js**: Contains configuration settings for contract addresses, ABIs, and file paths used by the utility scripts.\n\nKey functions in `merkle.js`:\n\n- `hashLeaf(address, amount, epochId)`: Creates hashed leaves for the Merkle Tree\n- `getRoot(claims)`: Generates the Merkle root from an array of claims\n- `getProof(address, amount, epochId, claims)`: Generates a Merkle proof for a specific claim\n- `verify(address, amount, epochId, claims)`: Verifies a claim against the Merkle Tree\n\n## Security Considerations\n\n### Claims Verification\n\nThe system uses the following security measures for claims verification:\n\n1. **Double-claim prevention**: Both instant and vested claims track their status in mappings\n2. **Tamper-proof verification**: Merkle Tree verification ensures users can only claim their allocated amounts\n3. **Parameter binding**: The address, amount, and epochId must all match the Merkle proof\n4. **Contract locking**: MigrationLocker can be locked to prevent new tokens from being locked\n\n### Access Control\n\n- Both contracts use OpenZeppelin's `Ownable2StepUpgradeable` for secure ownership management\n- Critical functions are protected with `onlyOwner` modifier\n- Both contracts can be paused/unpaused by owners to control operations\n\n### Deployment Scripts\n\n- `script/deploy/DeployLocker.s.sol`: Deploys the MigrationLocker contract\n- `script/deploy/DeployRelease.s.sol`: Deploys the MigrationRelease contract and sets the Merkle root\n\n## Usage Instructions\n\n### Building the Project\n\n```shell\nforge build\n```\n\n### Testing the Project\n\n```shell\nforge test\n```\n\n## License\n\nThis project is licensed under the MIT License with Attribution - see the [LICENSE](LICENSE) file for details.\n\nAny use of this code must include visible attribution to Push Protocol (https://push.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpushchain%2Fpush-chain-migration","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpushchain%2Fpush-chain-migration","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpushchain%2Fpush-chain-migration/lists"}