Learn state, constructor, view functions, write functions, events, and receipts.
start here / contracts / AppliedML / OCS-01 / compile / deploy / call / verify
Okay, you want to build on Octra. Start with programs: create one, compile it, deploy it, call it, inspect receipts, verify the source.
This is not a 0xio-first page and not a PVAC-first page. 0xio wallet integrations and PVAC-HFHE privacy work are useful later, but the first app starts with Octra contracts: what a program stores, which entrypoints it exposes, how AppliedML lowers into bytecode and ABI, how deployment runs the constructor, and how calls mutate state.
The beginner path is concrete: install/open the Octra web client, open Dev Tools, create the ocs-01 token template, keep main.aml plus interfaces/IOCS01.aml, compile as AppliedML (.aml), enter constructor params, preview address, deploy, read with contract_call, send a transfer, inspect Storage/receipts, verify source.
Write readable AML that compiles to OCTB bytecode, ABI, and disassembly.
Compile, preview address, deploy bytecode, call methods, inspect Storage and receipts.
After contracts work, add wallet UI, SDK approval, and optional PVAC-HFHE privacy.
What this page is actually for
This is the page you give to a developer when they say: "I want to build my first Octra app, but I do not understand contracts yet." The answer is not "install a wallet SDK" and not "start with FHE proofs". The answer is: learn the program lifecycle.
On Octra, a program is the deployed execution unit. It owns persistent state, exposes entrypoints, emits events, compiles into OCTB bytecode, and can be inspected through ABI, disassembly, storage, receipts, and source verification.
OCS-01 is the right first classroom because a token is easy to reason about. Name, symbol, supply, decimals, balances, grants, transfer, allowance, and events are all concrete. They let you learn how contracts work without inventing a new protocol at the same time.
Once you can create, deploy, call, and verify an OCS-01 token, then a wallet UI becomes obvious: it is a product surface for program state and program calls. Integrations like 0xio or PVAC should support that model, not replace it.
The corrected architecture
1. AppliedML source: readable program logic: imports, interface, state, constructor, functions, events, checks.
2. Compiler output: bytecode for deployment, ABI for calls, disassembly for inspection, Storage view for state behavior.
3. Deployment: bytecode plus constructor params become a program address and initialized state.
4. Calls: read-only calls inspect state; send-call transactions mutate state and produce receipts/events.
5. Web UI: reads ABI and state, builds action tickets, shows staging/confirmed/rejected/failed states.
6. Optional integrations: wallet SDK for approval UX, PVAC-HFHE for private encrypted values and proofs when the app actually needs them.
Program = deployed runtime object
In Octra docs, the core word is program. If you come from Solidity, you can mentally map it to "smart contract", but it is better to learn Octra's own model. A program is source code compiled into OCTB bytecode, deployed at an address, initialized by a constructor, and then called through entrypoints.
The program owns persistent state. That state can be simple fields like owner, maps like balances, nested maps like grants, or richer structures. When a write call succeeds, state changes. When a read-only call runs, state is inspected without mutation.
The program also emits events. Events are not decoration. They are the structured story of what happened. For a UI, events become activity rows, receipts, explorer history, and product trust.
Read vs write is the first mental split
| view/read call | Inspects state without submitting a transaction. Example: balance_of(address). |
| write call | Submits a transaction that can mutate state. Example: transfer(to, amount). |
| constructor | Runs during deployment and creates the first state. For OCS-01: name, symbol, supply, decimals, owner, deployer balance. |
| ABI | The callable shape of the program. A frontend should read this instead of inventing methods. |
| receipt | The execution result after a write call. This is where the UI learns whether the call actually succeeded. |
| storage | The persistent state view. After transfer, sender and recipient balances should change here. |
The contract lifecycle
Create the project
- Install and run the Octra web client, then open the local browser UI. Official docs describe the client at 127.0.0.1:8420 by default.
- Open Dev Tools in the client. This is where the first-program flow lives.
- Create a project from the existing ocs-01 token template. Do not start from a blank contract for the first run.
- Keep both generated files: main.aml and interfaces/IOCS01.aml. The main token file imports the interface.
- Read the template before editing. Identify token metadata, total supply, decimals, owner, balances, grants, transfer, grant, pull, balance_of, allowance, and get_* methods.
- For the first deploy, do not customize behavior. Prove the default path works before changing source.
Compile and inspect
- Set language to AppliedML (.aml).
- Click compile. If compilation fails, stop. Do not deploy half-understood code.
- Inspect ABI. This is the frontend method map: method names, params, view/write shape.
- Inspect Assembly or disassembly. This shows how readable source lowers into VM behavior.
- Inspect Console for compiler errors/warnings and output metadata.
- Inspect Storage after deployment/calls to verify state changed the way source says it should.
Deploy
- Enter constructor params as a JSON array, for example ["MyToken", "MTK", 1000000000000, 6].
- Understand the positions: name, symbol, raw total supply, decimals. Keep order exact.
- Click preview address. This computes the expected deployed address without publishing the program.
- Review deploy fee, deployer account, bytecode field, and constructor params.
- Click deploy. Deployment submits bytecode and runs the constructor.
- Copy the resulting program address. This is now the contract your app will read and call.
Call and verify
- Use read-only calls first: get_name [], get_symbol [], get_total_supply [], balance_of ["your_address"].
- Confirm the deployer received initial supply. In the template, initial supply is assigned during constructor initialization.
- Send a small transfer: method transfer, params ["recipient_octra_address", 1000], native OCT amount 0.
- Track the transaction: submitted/staging is not the same as final confirmation.
- Re-read sender and recipient balance_of. Confirm Storage and receipts match expectations.
- Use source verification with the same project files: main.aml and interfaces/IOCS01.aml.
RPC mental model for contracts
SDK comes after the contract path is clear
The SDK is not the center of the first app. The contract is. Use the SDK after you already understand the deployed program, ABI, constructor params, read calls, write calls, staging, receipts, and verification.
At that point, the SDK becomes a user-consent layer: connect account, request approval, submit or route the call, and show rejection/failure/confirmation states without your dApp touching private keys.
Keep the SDK behind an adapter. Components should speak product language like "request transfer" or "wait for receipt", not random wallet-package internals.
SDK adapter surface
| detectWallet | Can this browser connect to 0xio Wallet? Show installed, missing, unsupported, or wrong-network states. |
| connectWallet | Starts the user consent flow. The UI should distinguish connecting, connected, rejected, and failed. |
| getAccount | Returns the connected address/session state. Display short address, full copy button, and account freshness. |
| readBalance | Reads account or token balances. Reads should not trigger signing approval. |
| requestContractCall | Asks wallet to approve a program call: address, method, params, native amount, fee, privacy mode. |
| waitForTransaction | Tracks submitted -> staging -> confirmed or failed. The action row should not disappear after approval. |
Data model for optional wallet approval UI
type WalletState =
| "unsupported"
| "missing"
| "disconnected"
| "connecting"
| "connected"
| "wrong_network"
| "approval_requested"
| "rejected"
| "submitted"
| "staging"
| "confirmed"
| "failed";
type ContractCallTicket = {
programAddress: string;
method: "transfer" | "grant" | "pull" | string;
params: unknown[];
nativeAmount: "0";
feeEstimate?: string;
privacyMode: "public" | "private";
};
What Cursor/Claude/Codex should build after contracts work
- Keep the contract adapter first: deployed address, ABI, read methods, write tickets, receipts.
- Create a wallet adapter file and a mock implementation behind an explicit dev flag.
- Build the account header: wallet detected, connected address, network, copy address, disconnect.
- Build an action ticket before any chain call: method, params, fee, privacy mode, state.
- Add rejection and failure states. A user rejecting approval is not an app crash.
- Only after this works, wire OCS-01 reads and writes into the adapter.
- Only after public calls work, add PVAC for private data preparation.
What webcli is for
octra-labs/webcli is a local browser client for Octra. The public README describes it as compatible with DEVNET and MAINNET ALPHA, able to send transactions, encrypt/decrypt balances, and send private transactions to stealth addresses.
For DevRel, webcli is useful because it gives builders a working reference surface before they build their own dApp. It teaches the shape of wallet files, account balance views, transaction sending, private balance operations, stealth transfers, and local RPC behavior.
The important product lesson is that private operations are not magic. In the client they show up as explicit actions: encrypt balance, decrypt balance, send private tx, export/import wallets, inspect pending balance, and view transaction history.
Concrete webcli facts to know
| local URL | Docs say the client runs at http://127.0.0.1:8420. |
| wallet file | Wallet data is stored in data/wallet.oct when using the client flow. |
| wallet format | The installed client docs describe encrypted local storage and account metadata, not seed phrase collection inside random dApps. |
| networks | The repo README mentions DEVNET and MAINNET ALPHA compatibility. |
| features | Send txs, encrypt/decrypt balance, and send private transactions to stealth addresses. |
| RPC | Docs show JSON-RPC through POST /rpc on the local webcli server. |
How to use webcli while designing the dApp
- Install and run the client from the official docs. Treat it as the known-good Octra account surface.
- Create or import a wallet, then inspect the public balance, pending balance, nonce, and transaction history.
- Perform a simple public send so you understand address, amount, fee, nonce, and confirmation behavior.
- Try encrypt/decrypt balance flows and write down the user-visible states. Those states become your private DeFi UI queue.
- Inspect local JSON-RPC examples so your frontend mental model matches the network method groups.
- Use OCS-01 dev tools after that, so token program calls feel like an extension of the wallet flow, not a separate universe.
UI components webcli implies
- account summaryAddress, balance, pending/private balance, nonce, network, copy/export actions.
- transaction composerRecipient, amount, fee, nonce, preview, send, submitted, confirmed.
- privacy operationsEncrypt balance, decrypt balance, private send, proof/pending states, stealth address labels.
- history tableHash, type, value, status, timestamp, sender/recipient, privacy mode.
- RPC inspectorDeveloper-only surface for method, params, response, latency, error body.
- safety railNever ask users to paste secrets into a dApp just because webcli has local wallet management.
AppliedML is not theory here / it is the token contract you can compile
Use OCS-01 as the AppliedML classroom: every language concept appears as a token behavior, a storage change, an ABI method, or a UI state.
AppliedML, also called AML or Applied in the Octra docs, is Octra's high-level program language. The important beginner idea is that it stays readable while still lowering into inspectable Octra VM output: bytecode, ABI, disassembly, storage behavior, event emission, and revert paths.
That makes OCS-01 a perfect learning contract. You do not learn AppliedML by memorizing syntax in isolation. You learn it by asking: where is the token name stored, who receives initial supply, what does caller mean during transfer, why does require protect balances, what does the ABI expose, and what should the UI show after an event is emitted?
AppliedML concepts inside OCS-01
Read the file like this
- Open interfaces/IOCS01.aml first. This is the contract's public API and the best frontend checklist.
- Open main.aml and identify the state block. Every state field needs either a UI surface, a dev inspector row, or an intentional reason to stay hidden.
- Find the constructor. Constructor params are deployment-time product decisions: token name, symbol, raw supply, decimals.
- Separate view fn from fn. Reads are query UX; writes are approval and transaction UX.
- Find each require. Each check is a future validation message in the app.
- Find each emit. Each event is a future activity-row type.
- Compile and inspect ABI, Assembly, Console, and Storage. The source is readable, but the lowered output shows execution truth.
Annotated AppliedML token skeleton
import "./interfaces/IOCS01.aml"
program Token implements IOCS01 {
// Persistent data. This becomes storage.
state {
name: string
symbol: string
total_supply: int
decimals: int
owner: address
balances: map[address]int
grants: map[address]map[address]int
}
// User-facing history. This becomes an activity row.
event Transfer(from: address, to: address, amount: int)
// Deployment-time initialization.
constructor(name_: string, symbol_: string, supply_: int, decimals_: int) {
self.name = name_
self.symbol = symbol_
self.total_supply = supply_
self.decimals = decimals_
self.owner = origin
self.balances[origin] = supply_
}
// Read-only API. No signing prompt should be required.
view fn balance_of(addr: address): int {
return self.balances[addr]
}
// State-changing API. Needs wallet approval and receipt tracking.
fn transfer(to: address, amount: int): bool {
require(amount > 0, "amount must be positive")
require(self.balances[caller] >= amount, "insufficient balance")
self.balances[caller] = self.balances[caller] - amount
self.balances[to] = self.balances[to] + amount
emit Transfer(caller, to, amount)
return true
}
}
How compilation teaches you AppliedML
The compiler output is part of the learning loop. The ABI teaches the frontend which methods exist and what params they expect. The Assembly/disassembly teaches how readable source lowers into explicit Octra VM behavior. Storage inspection teaches what actually changed after deployment and calls.
For OCS-01, this is concrete. When you compile, you should see callable methods for metadata, balances, allowances, and token operations. When you deploy, constructor params initialize persistent token state. When you call transfer, storage changes and an event gives the UI something to index as history.
This is why AppliedML should be taught together with UI. The language concept is not separate from product design: view fn becomes a read panel, fn becomes an action ticket, require becomes validation/error copy, and event becomes activity history.
Beginner exercises
- Deploy the unedited OCS-01 template once. Do not customize it yet. Learn the happy path first.
- Change only token name and symbol. Recompile and verify which ABI parts do not change.
- Change decimals and supply. Learn raw units by comparing total supply display against human token display.
- Add or rename an event in a local experiment. Watch how the activity model changes.
- Add a stricter require. Make the frontend show that error before submission where possible.
- Inspect Storage before and after transfer, then make the UI refresh exactly those balances.
Mistakes to teach against
- confusing caller and originAsk who directly called the program versus who initiated the transaction path.
- ignoring decimalsHuman display units and raw integer units are different. Show both in dev mode.
- treating reads as writesRead-only methods should not trigger approval UX.
- hiding require failuresEvery runtime check should have a matching validation or error surface.
- trusting source onlyCompile output, ABI, assembly, and storage are part of the truth.
- inventing ABI methodsAgents should read the ABI or interface, not hallucinate wallet or contract calls.
Octra network
Octra is an FHE blockchain network with programs, isolated execution environments, JSON-RPC, accounts, contract calls, encrypted operations, and transaction settlement. For app builders, the important idea is that privacy can be part of execution, not just an offchain promise.
Applied program
An Octra program defines state, entrypoints, checks, events, constructor logic, views, and standard functions. Read it like a product spec: every field becomes a UI surface, every function becomes an action, and every event becomes activity history.
OCS-01 asset
The OCS-01 token template gives you a concrete starting object: name, symbol, total supply, decimals, owner, balances, grants, and token methods like transfer, grant, pull, balance_of, allowance, and get_* metadata calls.
app integration layer
After the program works, integrations turn chain capability into usable dApp UX: connect an account, request approval, submit actions, show public/private balance modes, and keep users in control of signing and sensitive privacy work.
The developer rule
Do not begin from pixels. Begin from the program surface. If the contract has balance_of, the UI needs balance reads. If it has transfer, the UI needs a transfer ticket. If it has grant and pull, the UI needs allowance language. If the flow uses encrypted values, the UI needs proof generation, ciphertext, failure, and waiting states.
Why "program" matters
Octra docs use "program" as the main executable unit. A program is not only source code. It is the thing that gets compiled, deployed, called, inspected, and verified. That means your frontend should treat the program as the contract of truth.
A good app reads the program in this order: state, constructor, view functions, state-changing functions, events, ABI, lowered assembly. You do not need to expose all of that to end users, but you need to understand it while designing the app.
For vibe coding, this is especially important. AI agents will happily invent a beautiful generic wallet. You want to force the agent to anchor its UI in program reality: exact methods, exact params, exact states, exact receipts.
Why OCS-01 is the first example
OCS-01 is useful because tokens are familiar. A token has identity, supply, decimals, balances, transfer behavior, and allowance-like behavior. That maps naturally to a wallet UI, so the developer can learn Octra without also inventing a new product category.
It is also useful because it teaches the full loop: create a template, compile, inspect ABI, deploy with constructor params, call read methods, send a state-changing call, inspect storage/events, verify source. Those are the habits you need before touching more complex DeFi.
So the page uses OCS-01 as a "hello world that is not a toy": small enough to understand, real enough to become a portfolio and transfer interface.
What Octra says to do first
- Open the Octra client dev tools and create a project from the ocs-01 token template.
- Keep both generated files: main.aml and interfaces/IOCS01.aml. The main file imports the interface.
- Compile as AppliedML (.aml) and inspect the generated ABI, Assembly, Console, and Storage tabs.
- Use constructor params as a JSON array, for example ["MyToken", "MTK", 1000000000000, 6].
- Preview address, deploy, then call read methods like get_name, get_symbol, get_total_supply, and balance_of.
- Send a small transfer call with OCT amount set to 0, because you are calling the token program, not sending native OCT with the call.
- Verify source after deployment so the deployed program can be linked back to the exact source files.
Read OCS-01 as a UI spec
| name / symbol | Asset identity in the portfolio header, token selector, and action ticket. |
| total supply | Token detail panel, supply metrics, and risk context. |
| decimals | Formatting layer. Never let UI send human units where raw units are expected. |
| balances | Primary wallet balance, account rows, balance checks before transfer. |
| grants | Allowance or delegation UI. Explain who can pull and how much. |
| events | Recent activity table and receipts. Events are user-visible product history. |
Minimal OCS-01 shape
program Token implements IOCS01 {
state {
balances: map[address]int
}
event Transfer(from: address, to: address, amount: int)
constructor(supply: int) {
self.balances[origin] = supply
}
view fn balance_of(addr: address): int {
return self.balances[addr]
}
fn transfer(to: address, amount: int): bool {
let bal = self.balances[caller]
require(bal >= amount, "insufficient balance")
self.balances[caller] = bal - amount
self.balances[to] = self.balances[to] + amount
emit Transfer(caller, to, amount)
return true
}
}
What the UI must not hide
- constructor paramsToken name, symbol, raw supply, and decimals are positional. The wrong order breaks deployment.
- ABI truthUse ABI output as the source of callable methods. Do not invent method names in components.
- raw unitsDisplay human units, submit raw units, and show the conversion in the review ticket.
- call modeRead methods use view calls. State changes use send call tx and need wallet approval.
- receipt stateAcceptance into staging is not final confirmation. The activity table needs both states.
- verificationVerified source gives builders and users confidence that the UI matches the deployed program.
Method to product map
What happens when you press transfer
The user thinks they are sending a token. The frontend should think in a stricter sequence. First it reads the selected OCS-01 contract and confirms token metadata. Then it validates the recipient, converts the typed amount into raw units using decimals, and checks balance_of so the ticket can catch obvious failures before wallet approval.
Then the UI builds a method call: program address, method name transfer, params like ["recipient_octra_address", 1000], and native OCT amount 0. That ticket is what the user approves through 0xio. After approval, the app submits and tracks the transaction through staging and confirmation.
When the receipt or transaction state is final, the UI refreshes balances and writes an activity row. This is why "send button" is too small a model. It is really a state machine with a user approval boundary in the middle.
What happens when you press grant
Grant is where DeFi wallet UX usually gets confusing. A grant is not a transfer. It is permission. The user is saying another address or program can later pull some amount under the rules of the token program.
A good wallet UI should therefore show three identities: the owner, the spender, and the token contract. It should show the allowance amount in human units and raw units. It should also show whether the grant replaces, increases, or otherwise changes existing allowance according to the actual contract behavior.
For AI-generated apps, this is a common risk area: the agent may label everything "approve" because it remembers ERC-20. On this page, the safer language is grant/pull until the exact OCS-01 interface in the deployed source says otherwise.
Build states before features
The product will feel serious if every async state is named. Disconnected, connecting, wrong network, connected, reading, ready, approving, building proof, staging, confirmed, rejected, failed, retryable, and stale are all different states.
Make privacy legible
Private does not mean "mystery spinner". Tell users when the app is encrypting locally, generating a proof, waiting for wallet approval, submitting to the network, and waiting for confirmation.
Keep DeFi calm
Use dense tables, exact labels, hashes, receipts, and explicit errors. A DeFi wallet should feel like an instrument panel, not a launch poster.
What the user should understand
The user does not need to know AppliedML. They do need to know what they are approving. The wallet UI should translate program mechanics into human consequences: "you are sending 1.25 MTK", "you are granting this app permission to pull up to 50 MTK", or "you are generating a private proof locally before the transaction can be submitted."
For personal DeFi, the UI should always answer five questions: what asset, what method, what amount, who can act, and what state comes next. If any one of those is unclear, the user is being asked to trust a black box.
What the developer should instrument
Log adapter-level events in development: wallet detected, account connected, ABI loaded, view call sent, action ticket built, wallet approval requested, transaction submitted, staging seen, confirmation seen, receipt parsed, balance refreshed.
Do not log secrets. Do not log plaintext private values beyond explicit local development mocks. But do log the public structure of the flow so a developer using Codex or Claude Code can debug the integration without guessing which layer failed.
The boundaries
Do not mix them up
| basic wallet app | Start with @0xio/sdk. You need connection, address, balance, approval, submit, status. |
| private DeFi app | Add @0xio/pvac only when the app needs encrypted amounts, proofs, or ciphertext math. |
| server backend | Do not plan to run @0xio/pvac on Node.js. The package README says browser only because of WASM threading. |
| mobile/native | Use the native PVAC route such as pvac-rs, not the browser package. |
| AI agents | Tell Cursor/Claude/Codex to verify package types before importing exact method names. |
@0xio/pvac quick shape
import {
PvacContext,
initPvac,
buildEncryptPayload,
buildDecryptPayload
} from "@0xio/pvac";
const wasm = await initPvac();
const ctx = await PvacContext.create(seed, wasm, {
preWarm: true,
threads: navigator.hardwareConcurrency
});
const encrypted = ctx.fullEncrypt(1000000);
const cipher = encrypted.cipherB64; // hfhe_v1|base64
const proof = encrypted.boundProofEncoded; // zkzp_v2|base64
const encryptTxData = buildEncryptPayload(ctx, 1000000);
const decryptTxData = await buildDecryptPayload(
ctx,
500000,
currentCipher,
currentBalance
);
What devs need to know about PVAC
- browser onlyRuns in web dApps, browser extensions, and web workers. Not supported on Node.js servers.
- WASM bundledThe README says the WASM module is bundled, so no separate setup is required for the package itself.
- seed mattersContext creation expects a 32-byte seed from wallet key derivation. Do not invent your own unsafe key flow.
- proofs can be slowRange proofs can take tens of seconds. UI needs progress, cancellation language, and patience.
- headers matterParallel proof generation needs SharedArrayBuffer plus COOP/COEP headers for rayon thread pool parallelism.
- memory mattersPlan for around 100MB RAM during PVAC context initialization according to the package README.
SDK reminder before PVAC
Do not start PVAC work while wallet connection is still vague. The public path should already be boring: connect wallet, show account, build ticket, ask approval, submit, track state, refresh balances.
The SDK is the consent boundary. If the app can do something sensitive, the wallet should be involved. That is why the dApp should never collect seed phrases, private keys, wallet files, or secret recovery material. The dApp requests; the wallet asks the user.
When PVAC arrives, it should plug into the same action-ticket model. The only difference is that the ticket now has a local cryptographic preparation phase before wallet approval.
How to think about @0xio/pvac
PVAC is not a prettier wallet connection library. It is cryptographic machinery for private app flows. Use it when your browser dApp must create encrypted values, proofs, or ciphertext arithmetic before a program call.
That distinction matters for UX. A normal public transfer can feel fast: prepare ticket, approve, submit, confirm. A private flow may need local WASM initialization, encryption, bound proof generation, range proof generation, and then wallet approval. Some of those steps can take real time.
So do not hide PVAC behind a single spinner. Name the work: initializing PVAC, encrypting locally, generating bound proof, generating range proof, preparing payload, waiting for wallet approval. The user is more patient when the interface is honest.
Public token transfer
- Read token metadata from OCS-01: get_name, get_symbol, get_total_supply, decimals from the contract/template.
- Read the connected account balance with balance_of and format raw units for display.
- User enters recipient and amount. UI converts human amount to raw units and validates address, decimals, and balance.
- Action ticket shows program address, method transfer, params, OCT amount 0, fee estimate, and settlement path.
- Request 0xio wallet approval through the SDK adapter. Never collect secrets in the app.
- Submit, show staging, poll transaction or receipt, then refresh balances and activity after confirmation.
Private DeFi action
- Connect wallet and initialize PVAC only for actions that require encrypted values or proofs.
- Encrypt the user amount locally. The UI says "encrypting locally", not "loading".
- Create a bound proof if the program needs to prove the ciphertext matches a committed amount.
- Use cipher arithmetic when the app must compute new encrypted balances or reserve deltas.
- Create range proofs when the program needs non-negative balance or reserve guarantees.
- Submit ciphertexts and proofs to the program through the wallet-approved transaction flow.
Private DEX mental model from PVAC
The PVAC README describes the private DEX shape clearly: encrypt the swap amount, prove the amount is valid with a bound proof, update encrypted reserves with ciphertext addition/subtraction, prove the pool remains non-negative with a range proof, then submit to the DEX contract with the proofs. For a personal DeFi wallet UI, this becomes a visible queue: encrypt amount, build proof, update preview, ask wallet, submit, confirm.
Why private DeFi changes the app shape
In a public DeFi app, the UI can often read everything it needs from public balances, pool reserves, and events. In a private DeFi app, the UI may be working with ciphertexts and proofs. The app can still be usable, but the user experience has to explain less obvious work.
For example, a private swap preview may show a human amount locally, but the chain-facing payload is encrypted. The program may verify that the encrypted amount is valid without learning the plaintext. The UI should explain that difference: "your browser prepares encrypted proof material; the network verifies the proof; the plaintext amount is not broadcast as a normal public value."
This is the main devrel point: privacy is not just a backend feature. It is a product state. If the UI does not show the privacy pipeline, users and developers will both misunderstand what the app is doing.
How to stage the build
- Build the OCS-01 public wallet first: connect, read metadata, read balance, transfer, activity table.
- Add allowance/delegation UI: grant, allowance read, pull, revoke or reset if the contract supports it.
- Add a mock private action queue with named states before adding cryptography.
- Add PVAC initialization and capability checks: browser, WASM, SharedArrayBuffer, memory expectations.
- Wire encryption and proof generation behind a privacy adapter, then connect it to wallet-approved submission.
- Only after that, design private swap/lending/portfolio features. Otherwise you will mix product logic and cryptographic plumbing too early.
devrel truth / AI is for speed, review is for trust
Use AI to learn, prototype, document, and build UI fast. Do not blindly vibe-code contracts that will hold user value.
Smart contracts and Octra programs are settlement logic. If a program controls balances, grants, private state, vault behavior, swaps, or lending positions, it needs a real review process. Cursor, Claude Code, Codex, and other agents can help you explore AppliedML, generate tests, explain ABI output, build UI adapters, and find obvious issues. They are not a substitute for human review, adversarial testing, and public scrutiny.
If you publish something people may use, publish the source on GitHub, document what the program does, tag the exact deployed address, explain constructor params, include tests or reproduction steps, and ask for peer review before calling it safe. Make it easy for other developers to inspect, run, criticize, and improve the code.
Contract rule
Vibe-code the learning path, not the trust boundary. It is fine to use AI to generate a toy OCS-01 variant, a local experiment, a UI mock, a test scaffold, or an explanation. It is not fine to paste generated contract code into production because it compiled once.
Before anyone relies on the program, make the repo public or shared, include the exact source used for deployment, and invite peer review. Ask reviewers to look for broken invariants, incorrect caller/origin assumptions, raw unit mistakes, allowance bugs, missing checks, event mismatch, and privacy/proof misuse.
For Octra specifically, reviewers should inspect both the AppliedML source and the compile artifacts. The ABI, Assembly, and Storage behavior are part of what people should review.
GitHub peer review checklist
- Publish the repository with main.aml, interfaces, tests, README, and exact deployed program address.
- Include constructor params and explain raw units, decimals, owner/deployer assumptions, and network.
- Commit generated ABI or provide a reproducible compile command so reviewers can compare source to deployed behavior.
- Document every public method: who can call it, what state it changes, what it emits, and how it can fail.
- Ask peers to review invariants, edge cases, malicious callers, overflow/underflow assumptions, grants/allowances, and revert paths.
- Do not market the contract as safe until review feedback is addressed and the source is verified against deployment.
Code is cheap
AI made code cheaper. That is good. It means more people can prototype wallets, dashboards, adapters, docs, tests, and demos. But cheap code also means cheap bugs, cheap clones, cheap half-products, and cheap confusion.
The scarce thing is not generating another contract or another app screen. The scarce thing is clarity: what user problem you solve, why Octra privacy matters for that problem, who needs it, why they trust it, how they find it, and why they keep using it.
So the builder lesson is simple: use AI to compress implementation time, but do not confuse implementation with success.
GTM is key for success
A dApp wins when a real group of users understands why it should exist. For Octra, that means explaining private balances, private transfers, private DeFi, or encrypted application state in a way that maps to a real user pain.
Before polishing contract complexity, write the GTM path: target user, first use case, trust story, onboarding path, distribution channel, demo flow, docs, example repo, and success metric. The best technical primitive still needs a reason to be adopted.
For DevRel, this means your GitHub repo, docs page, demo UI, and peer review thread are part of the product. They are not afterthoughts. They are how developers decide whether to build with you.
Prompt 1: build the OCS-01 wallet UI shell
You are building a personal DeFi wallet UI for Octra using the octrascan design system from https://chiefofautism.com/ui-kit/llms.txt.
Build order:
1. Contracts first: understand Octra programs, AppliedML source, state, constructor, view fn, fn, require, event, ABI, storage.
2. Create an OCS-01 token project in the Octra client Dev Tools using main.aml and interfaces/IOCS01.aml.
3. Compile as AppliedML, inspect ABI/Assembly/Console/Storage, enter constructor params, preview address, deploy.
4. Test with read-only calls, send one transfer call, inspect receipt/storage, verify source.
5. Build the UI around deployed program reality: contract address, ABI methods, read panels, write tickets, receipts.
6. Only after that add optional wallet SDK integration and optional PVAC-HFHE for private encrypted values/proofs.
OCS-01 token mental model:
- token metadata: get_name, get_symbol, get_total_supply, decimals
- account balance: balance_of(address)
- state-changing methods: transfer, grant, pull
- allowance: allowance(owner, spender)
- deployed program address and verified source matter
Do not make a landing page. Build the actual app surface:
- header with deployed contract address, network state, and optional connected account
- portfolio metrics for OCT, OCS-01 token balance, public/private modes
- token table with contract address, symbol, balance, state
- action ticket for transfer/grant/pull
- receipt/activity table with staging, confirmed, rejected, failed states
- contract inspector with ABI methods and source links
Architecture:
- put all contract calls behind a contract adapter
- put optional wallet calls behind a wallet SDK adapter
- do not ask for seed phrase, private key, plaintext wallet file, or local key import
- if exact SDK method names are unknown, create typed TODO methods and verify from installed package types before wiring
- use mock data only behind an explicit mock flag and label it in the UI
- treat AppliedML compile artifacts as product data: ABI for calls, Assembly for inspectability, Storage for state changes
- do not present AI-generated contract code as production-safe
- if contract code is published, prepare a GitHub repo/readme for peer review with source, ABI, deployed address, constructor params, risks, and tests
- remember: code is cheap; GTM, trust, distribution, and developer adoption are key for success
Prompt 2: add SDK adapter
Create a small @0xio/sdk adapter for this app.
Interface:
- detectWallet()
- connectWallet()
- getAccount()
- readBalance(address)
- requestContractCall({ programAddress, method, params, amount, fee })
- waitForTransaction(hash)
Rules:
- no SDK calls inside React components except through this adapter
- no secret key handling in app code
- preserve disconnected, connecting, approving, submitted, confirmed, rejected, failed states
- verify exact SDK imports from local package types before using them
Prompt 3: add PVAC privacy adapter
Add a browser-only @0xio/pvac adapter for encrypted DeFi actions.
Use PVAC for:
- initPvac()
- PvacContext.create(seed, wasm, options)
- fullEncrypt(amount)
- buildEncryptPayload(ctx, amount)
- buildDecryptPayload(ctx, amount, currentCipher, currentBalance)
- ctAdd / ctSub for ciphertext arithmetic where needed
- bound proof and range proof states
UI requirements:
- show "initializing PVAC"
- show "encrypting locally"
- show "building proof"
- show "waiting for wallet approval"
- show "submitted"
- show "confirmed" or "failed"
Constraints:
- browser only, no Node.js server usage
- proof generation may be slow, so do not block the whole UI
- if SharedArrayBuffer/COOP/COEP are missing, show a slower-mode warning
Prompt 4: review like DevRel
Review this Octra/0xio dApp as a DevRel engineer.
Find:
- any place the app invents wallet APIs
- any place the app asks for user secrets
- any missing transaction states
- any OCS-01 raw unit / decimals mistakes
- any view call vs state-changing call confusion
- any PVAC proof state hidden behind generic loading UI
- any AI-generated contract logic that lacks tests, source verification, or peer review path
- any mobile layout overflow for addresses, hashes, errors, or method names
Return findings with file and line references, then patch the highest-impact issues.
What was verified
Octra docs describe Octra as an FHE blockchain network, Applied programs as deployable units with state, entrypoints, checks, events, constructor logic, ABI and lowered output, and the first-program flow as an OCS-01 token template with main.aml, interfaces/IOCS01.aml, compile, deploy, call, transfer, and verify steps.
Package versions checked
@0xio/pvac latest was checked from npm as 1.0.0, described as PVAC-HFHE privacy primitives for Octra Network: FHE encryption, range proofs, and cipher arithmetic. The SDK package listing describes @0xio/sdk as the official TypeScript SDK for 0xio Wallet and Octra dApp integration.