Skip to content

Conversation

@frolvanya
Copy link
Contributor

@frolvanya frolvanya commented Dec 9, 2025

Note

Deploying this requires backfilling initial locked token amounts—reindex prior bridge events to populate locked_tokens before allowing withdrawals.

This pull request introduces significant enhancements to the omni-bridge contract, primarily focused on improved token deployment tracking, token locking mechanisms, and code maintainability. The main changes include the addition of a new deployed_tokens_v2 mapping for more robust token origin tracking, the introduction of token locking logic, and various refactorings to support these features and improve code clarity.

Token Deployment and Origin Tracking Enhancements:

  • Added a new deployed_tokens_v2 (LookupMap<AccountId, ChainKind>) to the Contract struct, which enables more accurate tracking of deployed tokens and their origin chains. The contract now uses an is_deployed_token method to check token deployment status, covering both old and new mappings. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R220), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R282), [[3]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1285-R1288), [[4]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1343-R1372))
  • Implemented a get_token_origin_chain method to determine a token's origin chain, leveraging the new mapping, UTXO chain checks, and string pattern matching for legacy tokens. The mapping is updated as needed for non-UTXO chains. ([near/omni-bridge/src/lib.rsR1343-R1372](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1343-R1372))
  • Updated all relevant contract logic to use deployed_tokens_v2 and the new is_deployed_token method, including token deployment, migration, and removal flows. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1128), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1463-R1464), [[3]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1435-R1490), [[4]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1521-R1523), [[5]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1539-R1598), [[6]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1620-R1679))

Token Locking Mechanism:

  • Introduced a locked_tokens mapping and integrated new token locking logic. Tokens are now locked as needed during fast and UTXO transfers, and lock actions are managed and reverted as appropriate in callbacks. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R232), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L865-R891), [[3]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1573-R1589), [[4]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1663-R1728))
  • Added token_lock module and LockAction usage to support the locking mechanism. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R39-R45), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R1573-R1589))

Refactoring and Consistency Improvements:

  • Refactored to use amount_without_fee() in place of manual fee subtraction throughout transfer logic, improving clarity and reducing errors. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L439-R448), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L819-R838))
  • Standardized destination chain access by replacing direct recipient chain checks with get_destination_chain() method. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L484-R496), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L865-R891))
  • Updated function signatures and internal logic to support new features and improve maintainability, including callback parameter updates and improved error handling. ([[1]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L842-R853), [[2]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6R961), [[3]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1025-R1047), [[4]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1044-R1064), [[5]](https://github.com/Near-One/omni-bridge/pull/481/files#diff-b60c5b1d9739aba26a808fe5bb90473c2c30a608886757604357c66a764256b6L1055-R1075))

Other:

  • Bumped the near workspace version to 0.4.4. ([near/Cargo.tomlL4-R4](https://github.com/Near-One/omni-bridge/pull/481/files#diff-6d770b88fda0eded3e60bfa1c6d3ec511baea883965f9457f7b4dbff97a816e1L4-R4))
  • Removed branch restrictions from the Rust GitHub Actions workflow trigger. ([.github/workflows/rust.yamlL10](https://github.com/Near-One/omni-bridge/pull/481/files#diff-9ed853ee5016b3f7cb01ee3da6506fd9e926a923324f327507c34e64f83dfe10L10))

These changes collectively enhance the omni-bridge's ability to accurately track tokens across chains, securely lock tokens during cross-chain operations, and maintain a cleaner, more maintainable codebase.

@frolvanya frolvanya linked an issue Dec 9, 2025 that may be closed by this pull request
Copy link
Contributor

@kiseln kiseln left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about transfers to other chain? We need to subtract tokens for source and add for destination

@frolvanya
Copy link
Contributor Author

What about transfers to other chain? We need to subtract tokens for source and add for destination

Added in 057401e

utxo_chain_connectors: old_state.utxo_chain_connectors,
migrated_tokens: LookupMap::new(StorageKey::MigratedTokens),
migrated_tokens: old_state.migrated_tokens,
locked_tokens: LookupMap::new(StorageKey::LockedTokens),
Copy link
Contributor Author

@frolvanya frolvanya Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to pause a contract, apply migration first and unpause it later. It might be better to allow providing a vec of locked tokens for migrate methods. Which option is better?

P.S: technically if locked_tokens field is empty, then it can be considered as a paused contract already, since init_transfer, fin_transfer methods won't work until locked_tokens are populated properly

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements per-chain locked-token accounting on the NEAR bridge to track NEP-141 tokens locked for each destination chain. The bridge now maintains a locked_tokens map indexed by (chain, token), incrementing balances when transferring from NEAR to other chains and enforcing availability before releasing tokens back to NEAR recipients.

Changes:

  • Added locked_tokens field to track token balances per chain
  • Implemented increase/decrease operations with overflow and insufficient balance checks
  • Updated transfer flows to maintain locked token accounting
  • Added administrative set_locked_tokens function for manual backfilling

Reviewed changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
near/omni-bridge/src/lib.rs Core implementation of locked tokens tracking with get/set/increase/decrease operations integrated into transfer flows
near/omni-bridge/src/migrate.rs Migration logic that initializes locked_tokens as empty map requiring manual backfilling
near/omni-bridge/src/tests/lib_test.rs Unit tests for locked token tracking including insufficient balance and refund scenarios
near/omni-tests/src/init_transfer.rs Updated migration test to verify locked_tokens functionality
near/omni-tests/src/environment.rs Test environment setup with locked token seeding for new deployments
near/Cargo.toml Version bump to 0.4.4
near/Cargo.lock Dependency updates (various minor version bumps)
Comments suppressed due to low confidence (1)

near/omni-tests/src/init_transfer.rs:716

  • The migration test now only verifies that locked_tokens can be queried after migration, but it no longer verifies that existing pending_transfers are preserved during the migration. The previous test performed an init_transfer before migration and then verified the transfer message was still accessible afterwards. Consider adding a verification that existing state (pending_transfers, finalized_transfers, etc.) is properly preserved through the migration to ensure no data loss occurs.
    #[rstest]
    #[tokio::test]
    async fn test_migrate(build_artifacts: &BuildArtifacts) -> anyhow::Result<()> {
        let sender_balance_token = 1_000_000;
        let env = TestEnv::new(sender_balance_token, true, build_artifacts).await?;

        let res = env
            .locker_contract
            .as_account()
            .deploy(&build_artifacts.locker)
            .await
            .unwrap();

        assert!(res.is_success(), "Failed to upgrade locker");

        let res = env
            .locker_contract
            .call("migrate")
            .max_gas()
            .transact()
            .await?;

        assert!(res.is_success(), "Migration didn't succeed");

        let transfer = env
            .locker_contract
            .call("get_locked_tokens")
            .args_json(json!({
                "chain_kind": ChainKind::Near,
                "token_id": env.token_contract.id(),
            }))
            .max_gas()
            .transact()
            .await?;

        assert_eq!(
            transfer.into_result()?.json::<U128>()?,
            U128(0),
            "Locked tokens not migrated correctly"
        );

        Ok(())
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

frolvanya and others added 3 commits January 12, 2026 13:20
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@frolvanya frolvanya force-pushed the feat/track-locked-tokens branch from d77f951 to 05743c0 Compare January 14, 2026 21:01
@frolvanya frolvanya requested a review from olga24912 February 2, 2026 18:42
* refactor: moved lock/unlock into a separate module

Also, implemented a method to get token's origin chain and added lock/unlock methods for tokens other than nep141

* feat: lock and unlock tokens coming from other chains

* fix: called an incorrect helper method

* feat: added tests

* feat: use `deployed_tokens_v2` in all places where regular `deployed_tokens` field is used

* feat: covered fast transfers with tests

* chore: allow running CI on any PRs

* fix: double lock for transfer to other chains

* fix: clippy

* fix: tests

* feat: lock tokens for utxo->near as well

* fix: clippy

* chore: fmt

* fix: removed separator at the end of token prefix

* fix: unlock tokens for fast fin transfer to other chain

* fix: lock/unlock for utxo transfers

* feat: allow setting multiple locked tokens in one call

* fix: tests

* fix: don't add utxo tokens to `deployed_tokens_v2`

* fix: tests

* refactor: reduced code duplication in locking/unlocking logic

* fix: lock net amount during fast transfer to other chain

* refactor: unified lock nep141 and other tokens in one method

* refactor: unified unlock nep141 and other tokens in one method

* refactor: moved check if token is deployed into a separate method

* fix(omni-bridge): tests

* fix: treat utxo token on near as native nep141

* chore: use `is_deployed_token` method when possible

* fix: don't lock tokens during utxo->near transfer

* fix: clippy

* chore: removed unreachable statement in `get_token_origin_chain`

* fix: don't lock/unlock nep141 if chain is utxo
@frolvanya frolvanya changed the title feat: track locked nep141 tokens feat: track locked tokens Feb 3, 2026
@kiseln kiseln self-requested a review February 4, 2026 10:21
frolvanya and others added 5 commits February 4, 2026 12:41
* refactor: moved lock/unlock into a separate module

Also, implemented a method to get token's origin chain and added lock/unlock methods for tokens other than nep141

* feat: lock and unlock tokens coming from other chains

* fix: called an incorrect helper method

* feat: added tests

* feat: use `deployed_tokens_v2` in all places where regular `deployed_tokens` field is used

* feat: covered fast transfers with tests

* chore: allow running CI on any PRs

* fix: double lock for transfer to other chains

* fix: clippy

* fix: tests

* feat: lock tokens for utxo->near as well

* fix: clippy

* chore: fmt

* fix: removed separator at the end of token prefix

* fix: unlock tokens for fast fin transfer to other chain

* fix: lock/unlock for utxo transfers

* feat: allow setting multiple locked tokens in one call

* fix: tests

* fix: don't add utxo tokens to `deployed_tokens_v2`

* feat: enable locked tokens tracker only for selected chains

* fix: tests

* Update near/omni-tests/src/utxo_fin_transfer.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: tests

* refactor: reduced code duplication in locking/unlocking logic

* fix: lock net amount during fast transfer to other chain

* refactor: unified lock nep141 and other tokens in one method

* refactor: unified unlock nep141 and other tokens in one method

* refactor: moved check if token is deployed into a separate method

* fix(omni-bridge): tests

* fix: treat utxo token on near as native nep141

* chore: use `is_deployed_token` method when possible

* fix: bring back chain check

* fix: mess after merge

* chore(omni-tests): disable near chain for token tracking

* feat: bring back chain check

* feat: remove chain isolation

* feat: enable token lock track for newly deployed tokens

* chore: changed lock/unlock methods visibility

Prevents an issue if someone accidentaly adds `#[near]` on top of the implementation section

* feat: added `TokenLockController` role

* feat: do not remove 0 locked from map

* fix(omni-bridge): tests

* chore: replaced all errors left with proper enum variants

* chore: removed `Copy` trait for errors

* chore: removed `enable_token` logic from tests

* fix(omni-tests): json serialization

* fix(omni-tests): fix fast transfer related tests

* fix(omni-tests): fix fin transfer related tests

* chore(omni-tests): removed unused block of code

* fix: don't add an entry in locked_tokens on deploy token event

* feat: added small safe guard

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@frolvanya frolvanya requested a review from olga24912 February 9, 2026 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[OmniBridge]: Track current locked nep141 tokens

4 participants