Stele
Prove what was agreed.
Enforce what must be agreed.
Verifiable acceptance infrastructure for organizations and Solana applications.
Stele Proof
For organizations and websites
Know exactly what your user agreed to.
- Publish
- Accept
- Receipt
- Verify
- Publish an exact version of your agreement.
- Let the user accept it — passkey or wallet.
- Stele creates tamper-resistant evidence anyone can verify later.
Stele Gate
For Solana applications
Require current acceptance before protected actions.
- Action
- Check
- Accept if needed
- Execute
- Your program calls require_current() before a deposit or any protected action.
- Investors accept in an embedded modal; an on-chain AccessPass records it.
- Publish v2 and old access no longer satisfies the requirement.
Gate includes Proof. Every Gate acceptance is also a Proof record with a verifiable receipt.
The problem
“I agree” usually becomes a database flag.
When a dispute comes, the only record of what a user accepted is controlled by one of the parties. Stele replaces that row with evidence anyone can check.
Without Stele
acceptances ───────────── user_id: 284 accepted: true
With Stele
- DocumentTerms of Service — version 3
- FingerprintSHA-256 9f2c 41aa 07de 5b13…
- Signaturethe user's passkey or wallet
- TimestampSolana slot 312,448,901
- Receiptstele-receipt-….json
1/4Without Stele, the record of an agreement is a row in the company's own database.
Stele Proof
Prove which exact version a user accepted.
A company publishes exact terms. A user accepts them. Stele preserves evidence of exactly what was accepted — and anyone can verify it later.
Explore Proof1/6The organization publishes Terms of Service, version 3.
Stele Gate
Require current acceptance before a protected Solana action.
An RWA app requires its current offering terms before a deposit. The investor's AccessPass proves current acceptance, and the Solana program checks it directly.
Explore GateAtlas Real Estate Vault
Commercial property income · 7.2% target
Deposit
5,000 USDC
AccessPass
Missing
Program check
Not run
Acceptance and deposit are two transactions: the investor sees one “Accept & Deposit” step.
1/7An investor taps “Deposit 5,000 USDC” in the Atlas Real Estate Vault app.
Example · Atlas Real Estate Vault
Investors can't deposit until they've accepted your current terms.
A permissioned investment vault on Solana, end to end. It is also the live demo — every step is a real transaction.
- Deposit 5,000 USDCThe investor connects a wallet and taps Deposit in the Atlas Real Estate Vault.
- No AccessPass → the modal opensInvestor Offering Terms v1, hash-verified against Solana. “Accept & Deposit”.
- Acceptance recorded, deposit succeedsThe acceptance creates the AccessPass; the vault's require_current() passes.
- The fund publishes v2 and requires itThe investor's next deposit is rejected on-chain: their pass names v1.
- Accept v2, deposit succeedsThe same pass now names v2. The v1 acceptance stays verifiable forever.
- A direct CLI call failsNo frontend, no SDK — deposit() without a current pass is rejected by the program.
The whole integration in the vault program
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
stele_gate::require_current(
&ctx.accounts.access_pass,
&ctx.accounts.policy,
&ctx.accounts.investor,
)?;
// … record the deposit
Ok(())
}Stele never holds the investor's funds and is not in the deposit's execution path: the vault program reads the AccessPass and the policy itself.
Run it on DevnetVersioning
Publish v2 and old access no longer satisfies the requirement.
An AccessPass names the version its holder accepted. When the organization requires a newer version, older passes simply stop satisfying the policy — nothing is rewritten.
Published versions
fingerprint 72d7 1ed9 83fa…
The wallet's AccessPass
accepted: Offering Terms v1
Valid
Protected deposit
deposit(5,000 USDC)
Waiting
—
The evidence for v1 remains. Access now requires v2.
1/6The investor accepted Offering Terms v1. Their AccessPass names v1 — and the policy requires v1.
Why program-level
Your frontend can be bypassed. The program check cannot.
A terms checkbox only exists in the interface you built. Anyone can call a Solana program from a script, the CLI or another frontend — so that is where the requirement has to live.
Without a program-level gate
With Stele Gate
The frontend is optional. The program check is not.
1/4Without program enforcement, the terms checkbox lives in the frontend. A normal investor passes through it.
For developers
Integrate without rebuilding your app.
Gate is one call in your program and one wrapper around the action you already send. Proof is two lines on any page.
import { createSteleGate } from "@stelehq/sdk";
const stele = createSteleGate({
apiBaseUrl: "https://stele.site/api",
// Any Wallet Standard wallet: the key that signs the deposit.
wallet: {
address: wallet.publicKey.toBase58(),
signMessage: (message) => wallet.signMessage(message),
},
});
// Shows the Stele modal only if the investor's AccessPass is missing or
// outdated, records the acceptance, then sends the deposit.
const signature = await stele.gate({
policy: OFFERING_TERMS_POLICY, // the policy address your program pins
action: () => sendDepositTransaction(5_000_000_000n),
acceptLabel: "Accept & Deposit",
});Stele Proof · any website
<!-- Stele Proof: where your terms should appear -->
<div data-stele-organization="acme.com" data-stele-document="terms-of-service"></div>
<script src="https://stele.site/sdk/v1/stele.js" defer></script>Choose
Which Stele do you need?
I run a normal application or website.
Use
Stele Proof
I want
- Verifiable terms acceptance
- Evidence of the exact document version
- Receipts anyone can verify
- Passkey or wallet signatures
- An audit trail you don't have to vouch for
I run a Solana application.
Use
Stele Gate
I want
- Everything in Proof
- AccessPass for each wallet
- Policy version enforcement
- Protected Solana actions
- SDK and program integration
- Bypass resistance on-chain
Gate includes Proof.
Security & verification
Built for the day someone wants the record to say something else.
Exact versions
Signed by the user
Enforced by your program
Verified by anyone
Stele answers “which exact document version did you accept?” — not “who are you?”. A passkey or wallet proves control of a key, not identity; Face ID is not KYC. What stays trusted: what the signing page displays, and who enrolls a passkey. Read the trust model.
Get started
See it work on Solana Devnet.
Accept offering terms, deposit, publish v2, watch the old pass stop working and a direct call fail — every step a real transaction.