DevelopersSeptember 14, 2026by
EmpoorioChain Core
EmpoorioChain Core

Sending DMS: A Transfer in Polkadot.js, the Rust SDK and viem

One ledger, two doors. DMS can move as a native balances extrinsic or as an EVM value transfer, and both end up in the same state. Here is the same transfer written three ways, with the trade-offs.

1. Native, with Polkadot.js API

import { ApiPromise, WsProvider, Keyring } from "@polkadot/api";

const api = await ApiPromise.create({
  provider: new WsProvider("wss://rpc.testnet.empooriochain.org"),
});
const keyring = new Keyring({ type: "sr25519", ss58Format: 2026 });
const sender = keyring.addFromUri(process.env.SENDER_SEED!);

const amount = 10n * 10n ** 18n;          // 10 DMS, 18 decimals
const tx = api.tx.balances.transferKeepAlive(RECIPIENT_SS58, amount);

const unsub = await tx.signAndSend(sender, ({ status, dispatchError }) => {
  if (dispatchError) throw new Error(dispatchError.toString());
  if (status.isInBlock)   console.log("included in", status.asInBlock.toHex());
  if (status.isFinalized) { console.log("finalized"); unsub(); }
});

Polkadot.js reads the runtime metadata at connection time, so it encodes the two EmpoorioChain-specific signed extensions (CheckPqcPolicy, CheckDormantAccount) without you doing anything. Note the two callbacks: included is not finalized, and a payment UI should show them differently. transferKeepAlive refuses to drop the sender below the existential deposit; transferAllowDeath does not.

Cost on the testnet snapshot: 0.000025 DMS.

2. Native, with the Rust SDK

use empoorio_sdk::{EmpoorioClient, SdkConfig};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let cfg = SdkConfig::new("wss://rpc.testnet.empooriochain.org");
    let client = EmpoorioClient::connect(cfg).await?;
    let signer = empoorio_sdk::signer::from_seed(std::env::var("SENDER_SEED")?)?;

    let receipt = client
        .balances()
        .transfer_keep_alive(&signer, RECIPIENT, 10 * 10u128.pow(18))
        .await?;                                   // waits for finality
    println!("finalized in block {}", receipt.block_hash);
    Ok(())
}

The SDK's typed clients hide SCALE encoding and metadata; for pallets without a typed client it exposes dynamic Subxt calls. If you compile against your own metadata.scale, take it from a node at the current spec version — the metadata changes in every runtime upgrade.

3. EVM, with viem

import { createWalletClient, http, parseEther, defineChain } from "viem";
import { privateKeyToAccount } from "viem/accounts";

const empooriochain = defineChain({
  id: 2026,
  name: "EmpoorioChain Testnet",
  nativeCurrency: { name: "DRACMA", symbol: "DMS", decimals: 18 },
  rpcUrls: { default: { http: ["https://rpc.testnet.empooriochain.org"] } },
  blockExplorers: { default: { name: "EmpooScan", url: "https://empooscan.com" } },
});

const client = createWalletClient({
  chain: empooriochain,
  transport: http(),
  account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
});

const hash = await client.sendTransaction({
  to: "0xRecipient…",
  value: parseEther("10"),
});

The chain id must be 2026: under EIP-155 it is inside the signature, and a wrong id yields a transaction the node rejects. Gas is 1 gwei since runtime 220. The EVM address maps to a native account deterministically, so a native transfer to that account and an EVM transfer to the H160 land in the same balance.

Which door

NativeEVM
ToolingPolkadot.js, Rust SDK, Dart SDK, EooniaMetaMask, Hardhat, viem, ethers
Fee modelWeight-based, ~0.000025 DMS per transferEIP-1559, 1 gwei base
Reaches native pallets (staking, DEX, identity, NFTs)DirectlyThrough precompiles 0xAA, 0x72, 0x1155 or not at all
Signed extensionsMust encode CheckPqcPolicy (Polkadot.js and the SDKs do)Standard Ethereum signature

Use native when you need the chain's own features; use the EVM when you are bringing Ethereum tooling or contracts. Verify either on EmpooScan — and for a contract deployment on the EVM side, verify by nonce rather than eth_getCode(…, 'latest'), which was found to return 0x for deployed contracts at latest on runtime 213.

Transfer fee from FEE_MODEL_AND_LOW_COST_STRATEGY.md; chain parameters from RED.json; extension encoding from FORMATO_DE_EXTRINSECOS.md.

Share this article