Documentation Index
Fetch the complete documentation index at: https://docs.startale.com/llms.txt
Use this file to discover all available pages before exploring further.
USDSC (Startale USD) is the canonical stablecoin on Soneium. Charging a user is a standard ERC-20 transfer. Gas is sponsored by the Startale paymaster, so the user pays only the USDSC amount.
Contract addresses
| Network | USDSC contract |
|---|
| Soneium Mainnet | 0x3f99231dD03a9F0E7e3421c92B7b90fbe012985a |
| Soneium Minato | 0xF2c10dC1beB13ee96036DE3F922eA871Ff2e0A7e |
USDSC follows the standard ERC-20 interface. Read decimals at runtime, do not hardcode them.
Send a USDSC payment
import { useWriteContract } from 'wagmi'
import { erc20Abi, parseUnits } from 'viem'
const USDSC = '0x3f99231dD03a9F0E7e3421c92B7b90fbe012985a' as const
export function PayButton({ to, amount }: { to: `0x${string}`; amount: string }) {
const { writeContractAsync, isPending } = useWriteContract()
const onClick = async () => {
const hash = await writeContractAsync({
address: USDSC,
abi: erc20Abi,
functionName: 'transfer',
args: [to, parseUnits(amount, 6)],
})
console.log({ hash })
}
return (
<button onClick={onClick} disabled={isPending}>
Pay {amount} USDSC
</button>
)
}
The parseUnits(amount, 6) call assumes USDSC uses 6 decimals. Read the actual value at runtime with decimals() if you support multiple stablecoins or want to be defensive against contract upgrades.
Approve and spend in one click
Use wallet_sendCalls (EIP-5792) when your flow needs an approve followed by a contract call. The user signs once and both calls land atomically.
import { encodeFunctionData, erc20Abi, parseUnits } from 'viem'
const calls = [
{
to: USDSC,
data: encodeFunctionData({
abi: erc20Abi,
functionName: 'approve',
args: [SPENDER, parseUnits('10', 6)],
}),
},
{
to: SPENDER,
data: encodeFunctionData({
abi: spenderAbi,
functionName: 'subscribe',
args: [parseUnits('10', 6)],
}),
},
]
const { id } = await provider.request({
method: 'wallet_sendCalls',
params: [
{ version: '1', from: address, chainId: '0x74c', atomicRequired: true, calls },
],
})
See Batched calls for the full pattern.
Pay in ETH
For native ETH payments, use useSendTransaction:
import { parseEther } from 'viem'
await sendTransactionAsync({
to: '0xRecipient...',
value: parseEther('0.05'),
})
Gas is still sponsored. Only the value moves from the user’s smart account.
Reading balances
import { erc20Abi, formatUnits } from 'viem'
import { publicClient } from './viem'
const balance = await publicClient.readContract({
address: USDSC,
abi: erc20Abi,
functionName: 'balanceOf',
args: [address],
})
const decimals = await publicClient.readContract({
address: USDSC,
abi: erc20Abi,
functionName: 'decimals',
})
const display = formatUnits(balance, decimals)