Creating a Sigil
What creating a Sigil will involve, and what you can experiment with today.
DraftCreating a Sigil means constructing an envelope, serializing it and publishing it to Elysium through the Saelis transport. Two of those three steps depend on decisions that have not been made, so this page separates what is specified from what is experimental.
What creation will involve
- Construct an envelope with a protocol identifier, version, optional standard, metadata, references and body.
- Serialize it in the canonical encoding.
- Publish it in a transaction through the chosen transport.
- Confirm inclusion, then wait for indexers to validate it.
Steps 1 and 2 follow the draft in Data Structure. Step 3 is an open design decision.
Construct an envelope
The envelope is plain data. Constructing it requires no network access.
Draft Example — Not Finalized
import type { SigilEnvelope } from './types'
const envelope: SigilEnvelope = {
p: 'saelis',
v: 0,
std: null,
meta: {
name: 'Fragment 01',
description: 'An experimental piece.',
},
refs: [],
body: {},
}The SigilEnvelope type is defined in Data Structure.
Serialize
The draft encoding is a fixed marker followed by the JSON payload, converted to bytes for the transaction.
Draft Example — Not Finalized
import { stringToHex, type Hex } from 'viem'
import type { SigilEnvelope } from './types'
export const SIGIL_MARKER = 'data:application/vnd.saelis+json,'
export function serializeSigil(envelope: SigilEnvelope): Hex {
return stringToHex(SIGIL_MARKER + JSON.stringify(envelope))
}Experiment with calldata on testnet
Calldata is one of the transport candidates. The code below is valid viem and sends a zero-value transaction to your own address with the serialized envelope as input data. It is a way to experiment with cost, size and retrieval. It does not create a recognized Sigil.
import 'viem/window'
import { createWalletClient, custom } from 'viem'
import { elysiumTestnet } from './lib/elysium'
import { serializeSigil } from './serialize'
const walletClient = createWalletClient({
chain: elysiumTestnet,
transport: custom(window.ethereum!),
})
const [account] = await walletClient.requestAddresses()
await walletClient.switchChain({ id: elysiumTestnet.id })
const hash = await walletClient.sendTransaction({
account,
to: account,
value: 0n,
data: serializeSigil({ p: 'saelis', v: 0, body: {} }),
})Estimating cost
On Arbitrum Orbit chains, a transaction's fee includes execution gas and a component for the data it posts to the parent chain. Larger envelopes cost more. Estimate before sending:
import { formatEther, type Address } from 'viem'
import { publicClient } from './lib/client'
import { serializeSigil } from './serialize'
const sender: Address = '0x000000000000000000000000000000000000dEaD'
const gas = await publicClient.estimateGas({
account: sender,
to: sender,
data: serializeSigil({ p: 'saelis', v: 0, body: {} }),
})
const gasPrice = await publicClient.getGasPrice()
console.log(`~${formatEther(gas * gasPrice)} HYPE`)When the transport is finalized
This page will be updated with the canonical publishing method. Until then, treat every example here as a prototype for understanding the model, not as a way to create Sigils.