Using Native Somnia Token (SOMI)

SOMI is the native token of the Somnia Network, similar to ETH on Ethereum. Unlike ERC20 tokens, SOMI is built into the protocol itself and does not have a contract address.

This multi-part guide shows how to use SOMI for:

  • Payments

  • Escrow

  • Donations & Tipping

  • Sponsored gas via Account Abstraction

Use SOMI for Payments in Smart Contracts

A simple contract that accepts exact SOMI payments:

function payToAccess() external payable {
  require(msg.value == 0.01 ether, "Must send exactly 0.01 SOMI");
}

Use msg.value to access the native token sent in a transaction. No ERC20 functions are needed.

To withdraw collected SOMI:

function withdraw() external onlyOwner {
  payable(owner).transfer(address(this).balance);
}

Deploy using Hardhat Ignition or Viem and test with a sendTransaction call.

Example.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SOMIPayment {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    // Modifier to restrict access to the contract owner
    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner can call this");
        _;
    }

    // User must send exactly 0.01 SOMI to access this feature
    function payToAccess() external payable {
        require(msg.value == 0.01 ether, "Must send exactly 0.01 SOMI");

        // Logic for access: mint token, grant download, emit event, etc.
    }

    // Withdraw collected SOMI to owner
    function withdraw() external onlyOwner {
        payable(owner).transfer(address(this).balance);
    }
}

Build an SOMI Escrow Contract

A secure escrow contract allows a buyer to deposit SOMI and later release or refund:

constructor(address payable _seller) payable {
  buyer = msg.sender;
  seller = _seller;
  amount = msg.value;
}

Release funds to the seller:

function release() external onlyBuyer {
  seller.transfer(amount);
}

Deploy with Hardhat Ignition and pass SOMI as value during deployment.

Example.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SOMIEscrow {
    address public buyer;
    address payable public seller;
    uint256 public amount;
    bool public isDeposited;

    constructor(address payable _seller) payable {
        buyer = msg.sender;
        seller = _seller;
        amount = msg.value;
        require(amount > 0, "Must deposit SOMI");
        isDeposited = true;
    }

    modifier onlyBuyer() {
        require(msg.sender == buyer, "Only buyer can call this");
        _;
    }

    function release() external onlyBuyer {
        require(isDeposited, "No funds to release");
        isDeposited = false;
        seller.transfer(amount);
    }

    function refund() external onlyBuyer {
        require(isDeposited, "No funds to refund");
        isDeposited = false;
        payable(buyer).transfer(amount);
    }
}

SOMI Tip Jar

Allow any wallet to send tips directly:

receive() external payable {
  emit Tipped(msg.sender, msg.value);
}

Withdraw all tips:

function withdraw() external onlyOwner {
  payable(owner).transfer(address(this).balance);
}
Example.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SOMITipJar {
    address public owner;

    event Tipped(address indexed from, uint256 amount);
    event Withdrawn(address indexed to, uint256 amount);

    constructor() {
        owner = msg.sender;
    }

    receive() external payable {
        emit Tipped(msg.sender, msg.value);
    }

    function withdraw() external {
        require(msg.sender == owner, "Only owner can withdraw");
        uint256 balance = address(this).balance;
        require(balance > 0, "No tips available");
        payable(owner).transfer(balance);
        emit Withdrawn(owner, balance);
    }
}

Frontend tip

await walletClient.sendTransaction({
  to: '0xTipJarAddress',
  value: parseEther('0.05'),
});

Using a smart account + relayer (e.g. via Privy, Thirdweb), the dApp can cover gas fees:

await sendTransaction({
  to: contractAddress,
  data: mintFunctionEncoded,
  value: 0n, // user sends no SOMI
});

The Smart Contract function can execute mint or other logic as usual. The paymaster or relayer pays SOMI.

Conclusion

  • SOMI is native and used via msg.value, .transfer(), and payable.

  • There is no contract address for SOMI (STT for Testnet).

  • You can integrate SOMI into any Solidity or Viem app with no ERC20 logic.

  • Account Abstraction enables gasless dApps using SOMI as sponsor currency.

Last updated