# Bridging $EWT Between EWX - ETH (Manual)

This guide explains the steps required for bridging $EWT tokens between Energy Web X (EWX) and Ethereum Mainnet (ETH) manually via Polkadot.js explorer and Energy-Bridge-ETH contract interactions.&#x20;

## Key Components

* Tier-1 (T1): Ethereum Mainnet (ETH, EVM)
* Tier-2 (T2): Energy Web X (EWX, Substrate parachain)&#x20;
* Energy Bridge Contract: Deployed on Ethereum, coordinates token transfers to/from EWX
* Token Manager Pallet: Handles bridge operations on EWX
* t2PublicKey: the EWX Substrate account’s public key in hex bytes

## Lowering Tokens: EWX → Ethereum

This guide explains how to move $EWT from Energy Web X (EWX, Tier-2) to Ethereum (Tier-1) using the on-chain bridge.\
The process involves scheduling a *lower* on EWX and then claiming it through the Energy Bridge smart contract on Ethereum.

### Step 1: Schedule a Lower on EWX

1. Navigate to [**Polkadot.JS Portal**](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-rpc.mainnet.energywebx.com%2F#/explorer) connected to the **EWX network**.
2. Go to `Developer` → `Extrinsics`.
3. Under `using the selected account`, choose the EWX account that holds the tokens to be lowered.
4. Under `submit the following extrinsic`, select:\
   `tokenManager → scheduleDirectLower(from, tokenId, amount, t1Recipient)` .
5. Fill in the parameters:
   * **from:** EWX account to lower from (your account)
   * **tokenId:** Ethereum address of the token to lower (e.g., the [EWT ERC-20 address](https://etherscan.io/address/0xB66a5D30D04f076E78ffB0d045C55846Fdcde928))
   * **amount:** Amount to lower (in wei units, e.g., `1000000000000000000` for 1 EWT)
   * **t1Recipient:** Ethereum address to receive the lowered tokens
6. Submit and sign the transaction.
7. The transaction will schedule a lowering event after a predefined delay (check `tokenManager.lowerSchedulePeriod` in `Developer` → `Chain State` for the exact number of blocks).

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2F9Qj72KOl1TQ03cANyRdv%2FStep%201%3A%20Schedule%20Lower%20on%20EWX%20Polkadot.js%20edited.png?alt=media&#x26;token=51607ef9-185b-48a2-b0d4-2b4301413e70" alt=""><figcaption></figcaption></figure>

### Step 2: Monitor the Scheduled Lower

* Go to `Network` **→** `Explorer` and look for the event:\
  `TokenManager.LowerRequested`
* Click on the event to view details and copy the `lowerId`.
* Alternatively:
  * `Network` → `Scheduler` shows pending scheduled lowers.
  * `Network` → `Event Calendar` displays the approximate execution date and time.

<div data-full-width="false"><figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2FKYGMdYXhzSKIIOfJ9prH%2FStep%202%20Monitor%20schedule%20edited.png?alt=media&#x26;token=d6359ae8-21b1-4284-bfa9-3f299c15b816" alt=""><figcaption></figcaption></figure></div>

### Step 3: Wait for Execution and Obtain the Proof

After the scheduled number of blocks elapse, the system will execute the lower.\
Once executed, a new event `TokenManager.LowerReadyToClaim` will appear.

1. Go to `Developer` → `Chain State`.
2. Select `tokenManager` → `lowersReadyToClaim`.
3. Toggle `include option` and enter your `lowerId` to filter results.
4. Retrieve the **proof**, specifically the `encodedLowerData` field.\
   This proof will be required on Ethereum.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2FsYmYBiusjeHcLn1nCdCu%2FScreenshot%202025-10-24%20at%2014.14.13.png?alt=media&#x26;token=ed76e105-de5f-447f-a5a4-717f81792820" alt=""><figcaption></figcaption></figure>

### Step 4: Claim the Lower on Ethereum

1. Visit the Energy Bridge Contract (Ethereum mainnet): [Energy Bridge Proxy Contract](https://etherscan.io/address/0x5dDed30f8cd557257CcDC4a530cB77AC45f0259D)
2. Connect your Ethereum wallet.
3. Under the `Write Proxy` tab, select `claimLower`.
4. Paste the `encodedLowerData` retrieved from EWX.
5. Click `Write`, sign the transaction, and wait for confirmation.

Upon success, the tokens will be unlocked and transferred to your Ethereum address, and a new `Lower` transaction will appear on the contract.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2FVxJ8MaRHEUWvf0iBdNbr%2FScreenshot%202025-10-24%20at%2012.41.10.png?alt=media&#x26;token=ef64580c-4e83-4a13-b5b5-b4b8f8e08c3f" alt=""><figcaption></figcaption></figure>

#### Notes

* Ensure your Ethereum account has sufficient ETH to cover gas fees.
* The lowering process is asynchronous, the on-chain scheduler on EWX must reach the required block height before the proof becomes claimable.
* The bridge only supports whitelisted tokens (e.g., $EWT).

***

## Lifting Tokens: Ethereum → EWX

There are two methods for lifting EW tokens: **Lift**, which first requires approving the bridge contract to spend your tokens; and **PermitLift**, which combines an ERC-2612 permit (EIP-712 signature) with the lift, allowing tokens to be lifted in a single transaction with no prior `approve()` needed.

## Alternative 1: Lift

#### **Step 1: Access the Energy Bridge Contract**

1. Visit the **Energy Bridge Contract (Ethereum mainnet)**: [Energy Bridge Proxy Contract](https://etherscan.io/address/0x5dDed30f8cd557257CcDC4a530cB77AC45f0259D)
2. Select `Write as Proxy`
3. Connect your Ethereum wallet holding $EWT (e.g., MetaMask) by clicking on `Connect web3` .

#### **Step 2: Approve the Bridge to Spend Your Tokens**

Before lifting, the bridge must be authorized to transfer your tokens.

1. Identify the ERC-20 EWT token contract on Ethereum: [EWT ERC-20 Proxy Contract](https://etherscan.io/address/0xB66a5D30D04f076E78ffB0d045C55846Fdcde928)
   1. Click the link above, or find the address through the [**Polkadot.JS Portal**](https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Fpublic-rpc.mainnet.energywebx.com%2F#/explorer)**:**
      1. &#x20;`Developer` → `Chain State` → `tokenManager` → `avtTokenContract():H160`
      2. Click "+", and copy the address in the `tokenManager.avtTokenContract: H160` field.
2. Once the contract is open on Etherscan → `Contract` → `Write as Proxy` →  `approve(spender, amount)`.
3. In the `spender` field, enter the Energy Bridge address: `0x5dDed30f8cd557257CcDC4a530cB77AC45f0259D`
4. In the `amount` field, enter the number of tokens (in wei) you wish to lift.
   * Example: `1000000000000000000` = 1 EWT
5. Click `Write`, sign, and wait for confirmation.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2FWRSeYl8plrMAnJTbk02j%2FScreenshot%202025-10-24%20at%2014.26.23.png?alt=media&#x26;token=453227e3-4189-43b3-9e6c-ffb61d9b2921" alt=""><figcaption></figcaption></figure>

#### **Step 3: Execute the Lift**

1. Return to the **Energy Bridge Proxy Contract** page.
2. Under `Write as Proxy`, locate the `lift` function.
3. Fill in the parameters:

| Parameter               | Description                                | Example                                                                                |
| ----------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------- |
| **token**               | ERC-20 token address to lift               | 0xB66a5D30D04f076E78ffB0d045C55846Fdcde928                                             |
| **t2PublicKey (bytes)** | Hexadecimal public key of your EWX account | Convert your EWX address using Polkadot.js → Developer → Utilities → Address Converter |
| **amount**              | Number of tokens (in wei) to lift          | `1000000000000000000` (= 1 EWT)                                                        |

4. Click `Write`, confirm the transaction, and wait for it to be mined.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2FgGschpy9KBg6FqGGhgQP%2FScreenshot%202025-10-24%20at%2014.30.00.png?alt=media&#x26;token=96510219-1a16-414e-8ef6-df3d3b902374" alt=""><figcaption></figcaption></figure>

After submission, your tokens are locked in the bridge contract, and a **Lifted** event is emitted on Ethereum.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2F9ForsC5y6bYqAFpYWDhr%2FScreenshot%202025-10-24%20at%2014.33.23.png?alt=media&#x26;token=1b5f8542-78f5-468d-a1fe-1455a059dbd0" alt=""><figcaption></figcaption></figure>

#### **Step 4: Monitor the Lift on EWX**

Once the bridge relayer processes the Ethereum Lifted event (typically within 5–10 minutes):

1. On the EWX explorer, open `Network` → `Explorer`.
2. Look for `tokenManager.AVTLifted` events.
3. Optionally, check `Developer` → `Chain State` → `ethereumBridge` → `activeEthereumRange()` to see the Ethereum block range being processed.
4. When your transaction is within that range, your lifted tokens will appear in your EWX account.

To verify, open `Accounts` → `My Accounts` and confirm the updated balance.

<figure><img src="https://4257445316-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fnf3YeoQlQerc93GsC2Me%2Fuploads%2Fk6V9JqNVFsXhGyHVJ4Gd%2FScreenshot%202025-10-24%20at%2014.37.45.png?alt=media&#x26;token=6e1fd931-cc44-415b-92e4-e6130050ce09" alt=""><figcaption></figcaption></figure>

***

### Alternative 2: PermitLift

`permitLift` simplifies the process by embedding an **ERC-2612 permit signature** directly into the lift call.\
This removes the need for a separate `approve()` step.

#### Steps:

1. On Etherscan, open the same **Energy Bridge Proxy Contract →** `Write as Proxy`.
2. Locate the `permitLift` function.
3. Prepare an **EIP-712 signature** (v, r, s) offline for the ERC-2612 permit corresponding to your token.
4. Fill the parameters:

| Parameter     | Description                                                       |
| ------------- | ----------------------------------------------------------------- |
| `token`       | ERC-20 token address (0xB66a5D30D04f076E78ffB0d045C55846Fdcde928) |
| `t2PublicKey` | Hex of your EWX account (as above)                                |
| `amount`      | Amount in wei                                                     |
| `deadline`    | Expiration timestamp for the permit                               |
| `v`, `r`, `s` | Components of the EIP-712 signature                               |

5. Click **Write**, sign, and confirm.\
   Your lift is processed in a single transaction.

Monitoring on EWX follows the same path as the standard `lift`.

Programmatic example `permitLift.js`

```
#!/usr/bin/env node

const { ethers } = require("ethers");
require("dotenv").config();

async function main() {
  const {
    RPC_URL,
    PRIVATE_KEY,
    BRIDGE_ADDR,
    TOKEN_ADDR,
    T2_PUBKEY,
    AMOUNT = "0.1",
    DECIMALS = "18",
    DEADLINE_SECS = "3600",
  } = process.env;

  if (!RPC_URL || !PRIVATE_KEY) {
    console.error("Missing RPC_URL or PRIVATE_KEY env vars");
    process.exit(1);
  }
  if (!BRIDGE_ADDR || !TOKEN_ADDR || !T2_PUBKEY) {
    console.error("Missing BRIDGE_ADDR, TOKEN_ADDR or T2_PUBKEY env vars");
    process.exit(1);
  }

  const provider = new ethers.JsonRpcProvider(RPC_URL);
  const signer = new ethers.Wallet(PRIVATE_KEY, provider);

  // Minimal ABIs required for this flow
  const BRIDGE_ABI = [
    "function permitLift(address token, bytes32 t2PubKey, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external returns (bool)"
  ];
  const TOKEN_ABI = [
    "function name() view returns (string)",
    "function nonces(address owner) view returns (uint256)"
  ];

  const bridge = new ethers.Contract(BRIDGE_ADDR, BRIDGE_ABI, signer);
  const token  = new ethers.Contract(TOKEN_ADDR, TOKEN_ABI, signer);

  const amount   = ethers.parseUnits(AMOUNT, Number(DECIMALS));
  const deadline = Math.floor(Date.now() / 1000) + Number(DEADLINE_SECS);
  const owner    = await signer.getAddress();

  const domain = {
    name: await token.name(),
    version: "1",
    chainId: (await signer.provider.getNetwork()).chainId,
    verifyingContract: await token.getAddress(),
  };

  const types = {
    Permit: [
      { name: "owner",   type: "address" },
      { name: "spender", type: "address" },
      { name: "value",   type: "uint256" },
      { name: "nonce",   type: "uint256" },
      { name: "deadline",type: "uint256" },
    ],
  };

  const message = {
    owner,
    spender: await bridge.getAddress(),
    value: amount,
    nonce: await token.nonces(owner),
    deadline,
  };

  const sig = await signer.signTypedData(domain, types, message);
  const { v, r, s } = ethers.Signature.from(sig);

  const tx = await bridge.permitLift(await token.getAddress(), T2_PUBKEY, amount, deadline, v, r, s);
  const receipt = await tx.wait();

  console.log("permitLift tx: ", receipt.hash);
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

```
