Using Native Somnia Token (STT)

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

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

  • Payments

  • Escrow

  • Donations & Tipping

  • Sponsored gas via Account Abstraction

Use STT for Payments in Smart Contracts

A simple contract that accepts exact STT payments:

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

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

To withdraw collected STT:

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 STTPayment {
    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 STT to access this feature
    function payToAccess() external payable {
        require(msg.value == 0.01 ether, "Must send exactly 0.01 STT");

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

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

Build an STT Escrow Contract

A secure escrow contract allows a buyer to deposit STT 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 STT as value during deployment.

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

contract STTEscrow {
    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 STT");
        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);
    }
}

STT 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 STTTipJar {
    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 STT
});

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

Conclusion

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

  • There is no contract address for STT.

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

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

Last updated