datahaven/operator/precompiles/datahaven-native-transfer
undercover-cactus b8cc9eee4b
feat: upgrade to polkadot SDK 2503 (#444)
## Polkadot upgrade 2503

In this PR, we upgrade form Polkadot SDK 2412 to Polkadot SDK 2503. In
order to upgrade the SDK we need to upgrade some dependencies :
StorageHub and frontier simultaneously.


## What changes 

### Trivial changes

* https://github.com/paritytech/polkadot-sdk/pull/7634 -> The new trait
is required in all the pallets using scale encoding.

* https://github.com/paritytech/polkadot-sdk/pull/7043 -> Remove
deprecated `sp-std` and replace with `alloc` or `core`.

* https://github.com/paritytech/polkadot-sdk/pull/6140 -> Accurate
weight reclaim with frame_system::WeightReclaim


### Breaking changes

* https://github.com/paritytech/polkadot-sdk/pull/2072 -> There is a
change in `pallet-referenda`. Now, the tracks are retrieved as a list of
`Track`s. Also, the names of the tracks might have some trailing null
values (`\0`). This means display representation of the tracks' names
must be sanitized.

* https://github.com/paritytech/polkadot-sdk/pull/5723 -> adds the
ability for these pallets to specify their source of the block number.
This is useful when these pallets are migrated from the relay chain to a
parachain and vice versa. (Not entirely sure it is breaking as it is
being marked as backward compatible).

* https://github.com/paritytech/polkadot-sdk/pull/6338 -> Update
Referenda to Support Block Number Provider

### Notable changes

* https://github.com/paritytech/polkadot-sdk/pull/5703 -> Not changes
required in the codebase but impact fastSync mode. Should improve
testing.

* https://github.com/paritytech/polkadot-sdk/pull/5842 -> Removes
`libp2p` types in authority-discovery, and replace them with network
backend agnostic types from `sc-network-types`. The `sc-network`
interface is therefore updated accordingly.

## What changes in Frontier 

* https://github.com/polkadot-evm/frontier/pull/1693 -> Add support for
EIP 7702 which has been enable with Pectra. This EIP add a new field
`AuthorizationList` in Ethereum transaction.

Changes example :

```rust
#[test]
fn validate_transaction_fails_on_filtered_call() {
...
            pallet_evm::Call::<Runtime>::call {
                source: H160::default(),
                target: H160::default(),
                input: Vec::new(),
                value: sp_core::U256::zero(),
                gas_limit: 21000,
                max_fee_per_gas: sp_core::U256::zero(),
                max_priority_fee_per_gas: Some(sp_core::U256::zero()),
                nonce: None,
                access_list: Vec::new(),
                authorization_list: Vec::new(),
            }
            .into(),
```

## ⚠️ Breaking Changes ⚠️

* Upgrade to Stirage hub v0.5.1
* Support for Ethereum latest upgrade (txs now have the
`authoriation_list` for support EIP 7702)

---------

Co-authored-by: Steve Degosserie <723552+stiiifff@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 10:04:57 +01:00
..
src feat: upgrade to polkadot SDK 2503 (#444) 2026-03-26 10:04:57 +01:00
Cargo.toml feat: upgrade to polkadot SDK 2503 (#444) 2026-03-26 10:04:57 +01:00
DataHavenNativeTransfer.sol feat: Add datahaven native transfer precompile (#309) 2025-12-02 13:57:40 +01:00
README.md feat: Add datahaven native transfer precompile (#309) 2025-12-02 13:57:40 +01:00

DataHaven Native Transfer Precompile

This precompile exposes the pallet-datahaven-native-transfer functionality to the EVM layer, allowing smart contracts to transfer DataHaven native tokens to Ethereum via Snowbridge.

Overview

The DataHaven Native Transfer precompile provides an EVM-compatible interface for:

  • Transferring native tokens from DataHaven to Ethereum
  • Managing the pallet's operational state (pause/unpause)
  • Querying transfer statistics and system state

Precompile Address: 0x0000000000000000000000000000000000000819 (2073 decimal)

Functions

transferToEthereum(address recipient, uint256 amount, uint256 fee)

Transfers DataHaven native tokens to an Ethereum address via Snowbridge.

Parameters:

  • recipient: Ethereum address to receive the tokens
  • amount: Amount of tokens to transfer (in smallest unit)
  • fee: Fee to incentivize relayers (in smallest unit)

Requirements:

  • Caller must have sufficient balance for amount + fee
  • recipient cannot be the zero address
  • amount and fee must be greater than zero
  • Pallet must not be paused
  • Native token must be registered on Ethereum

Example (Solidity):

import "./DataHavenNativeTransfer.sol";

contract MyContract {
    function sendToEthereum(address ethRecipient, uint256 amount) external {
        DATAHAVEN_NATIVE_TRANSFER_CONTRACT.transferToEthereum(
            ethRecipient,
            amount,
            100000000000000000 // 0.1 token fee
        );
    }
}

isPaused() view returns (bool)

Checks if the pallet is currently paused.

Returns:

  • true if paused (transfers disabled)
  • false if operational (transfers enabled)

Example (Solidity):

bool paused = DATAHAVEN_NATIVE_TRANSFER_CONTRACT.isPaused();
if (paused) {
    revert("Transfers are currently disabled");
}

totalLockedBalance() view returns (uint256)

Returns the total amount of tokens currently locked in the Ethereum sovereign account.

Returns:

  • Total locked balance in smallest unit

Example (Solidity):

uint256 locked = DATAHAVEN_NATIVE_TRANSFER_CONTRACT.totalLockedBalance();

ethereumSovereignAccount() view returns (address)

Returns the address of the Ethereum sovereign account that holds locked tokens.

Returns:

  • The sovereign account address

Example (Solidity):

address sovereign = DATAHAVEN_NATIVE_TRANSFER_CONTRACT.ethereumSovereignAccount();

Events

TokensLocked(address indexed account, uint256 amount)

Emitted when tokens are locked for transfer to Ethereum.

TokensUnlocked(address indexed account, uint256 amount)

Emitted when tokens are unlocked from Ethereum (handled by pallet, not directly through precompile).

TokensTransferredToEthereum(address indexed from, address indexed to, uint256 amount)

Emitted when a transfer to Ethereum is initiated.

Paused()

Emitted when the pallet is paused.

Unpaused()

Emitted when the pallet is unpaused.

Error Handling

The precompile provides detailed error messages for common failure cases:

  • "Recipient cannot be zero address": The recipient parameter is the zero address
  • "Amount must be greater than zero": The amount parameter is zero
  • "Fee must be greater than zero": The fee parameter is zero
  • "Amount overflow": The amount exceeds u128::MAX
  • "Fee overflow": The fee exceeds u128::MAX
  • "InsufficientBalance": Caller doesn't have enough tokens
  • "TransfersDisabled": Pallet is paused
  • "TokenNotRegistered": Native token not registered on Ethereum
  • "BadOrigin": Caller doesn't have permission (for pause/unpause)

Gas Costs

Approximate gas costs for each operation:

Operation Estimated Gas Notes
transferToEthereum ~100,000-150,000 Includes dispatch + storage writes
pause ~30,000-50,000 Simple dispatch
unpause ~30,000-50,000 Simple dispatch
isPaused (view) ~2,000-5,000 Single storage read
totalLockedBalance (view) ~2,000-5,000 Single storage read
ethereumSovereignAccount (view) ~1,000-3,000 Config read

Note: Actual gas costs may vary depending on runtime configuration and network conditions.

Integration Example

Complete example of integrating the precompile into a smart contract:

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

import "./DataHavenNativeTransfer.sol";

contract CrossChainBridge {
    event TransferInitiated(address indexed from, address indexed to, uint256 amount);
    
    function bridgeToEthereum(
        address ethRecipient,
        uint256 amount,
        uint256 fee
    ) external {
        require(!DATAHAVEN_NATIVE_TRANSFER_CONTRACT.isPaused(), "Transfers paused");
        require(ethRecipient != address(0), "Invalid recipient");
        require(amount > 0, "Invalid amount");
        
        DATAHAVEN_NATIVE_TRANSFER_CONTRACT.transferToEthereum(
            ethRecipient,
            amount,
            fee
        );
        
        emit TransferInitiated(msg.sender, ethRecipient, amount);
    }
    
    function getLockedBalance() external view returns (uint256) {
        return DATAHAVEN_NATIVE_TRANSFER_CONTRACT.totalLockedBalance();
    }
}

Testing

The precompile includes a comprehensive test suite covering:

  • Function selector validation
  • Function modifier checks
  • Successful transfer scenarios
  • Error cases (zero address, zero amount, insufficient balance, etc.)
  • Pause/unpause functionality
  • View function correctness
  • Gas accounting
  • Edge cases and overflow handling

Run tests with:

cd operator/precompiles/datahaven-native-transfer
cargo test

Security Considerations

  1. Existential Deposit: Transfers respect the chain's existential deposit requirement. Ensure callers retain sufficient balance to keep their account alive.

  2. Fee Payment: The fee is paid to the configured fee recipient separately from the amount being bridged. Ensure you have sufficient balance for both.

  3. Token Registration: The native token must be registered on Ethereum before transfers can occur. Check this before initiating transfers.

  4. Pause Mechanism: Only governance can pause the pallet. This is a safety mechanism for emergency situations.

  5. Snowbridge Dependency: Transfers depend on the Snowbridge infrastructure. Monitor Snowbridge health before large transfers.

  6. No Reentrancy: The precompile uses Frontier's reentrancy protection (forbid-evm-reentrancy feature).

Architecture

┌─────────────────┐
│  EVM Contract   │
└────────┬────────┘
         │ calls precompile at 0x...07F5
         ↓
┌─────────────────────────────┐
│ DataHavenNativeTransfer     │
│      Precompile             │
│  ┌──────────────────────┐   │
│  │ Address Mapping      │   │
│  │ Type Conversions     │   │
│  │ Gas Accounting       │   │
│  │ Error Handling       │   │
│  └──────────┬───────────┘   │
└─────────────┼───────────────┘
              │ dispatches call
              ↓
┌─────────────────────────────┐
│ pallet-datahaven-native-    │
│         transfer             │
│  ┌──────────────────────┐   │
│  │ Lock tokens          │   │
│  │ Build message        │   │
│  │ Send via Snowbridge  │   │
│  └──────────┬───────────┘   │
└─────────────┼───────────────┘
              │
              ↓
        [ Snowbridge ]
              │
              ↓
        [ Ethereum ]

License

This precompile is part of DataHaven and is licensed under GPL-3.0.

Support

For issues or questions: