Skip to content
GETTING STARTED

Quickstart

Integrate the Morpheus Privacy Oracle into your Neo smart contracts in under 5 minutes. This guide covers the end-to-end flow from encrypting secrets to reading the TEE-verified result on-chain.

Live Neo N3 Testnet Validation

The Morpheus paymaster-backed AA relay path has already been validated end-to-end on Neo N3 testnet, including account registration, verifier update, paymaster approval, relay submission, and on-chain executeUserOp success.

The paymaster guide links to the latest validated relay transactions on the explorer so the reference never goes stale.

Open Paymaster Guide

Step 1: Understand the Data Flow

The Morpheus network requires an asynchronous request-callback pattern. You must implement a callback function in your contract to receive the response.

Step 2: Seal Your Parameters (Off-Chain)

Before calling the Oracle contract, encrypt any sensitive API keys or parameters locally. The worker's active X25519 public key is exposed through the frontend proxy and also published on-chain in the Oracle registry metadata.

javascriptEncrypt Parameters
// 1. Fetch TEE Public Key
const res = await fetch("/api/oracle/public-key");
const { public_key } = await res.json();

// 2. Your confidential injection payload
const secrets = {
 "headers": { "Authorization": "Bearer YOUR_PRIVATE_API_KEY" }
};

// 3. Encrypt locally using X25519 + HKDF-SHA256 + AES-256-GCM
//    (helper signature: encryptJsonWithOraclePublicKey(publicKey, plaintext))
const encryptedBlob = await encryptJsonWithOraclePublicKey(public_key, JSON.stringify(secrets));

For the full sealed-envelope wire format and the migration to HPKE, see the X25519 / HPKE sealing reference.

Step 3: Submit On-Chain Request

Build a JSON payload, then pass that payload bytestring to the Oracle contract. On Neo N3 the request currently costs 0.01 GAS of prepaid credit.

csharpMyOracleConsumer.cs (Neo N3 Mainnet)
// Neo N3 Mainnet Oracle: 0xf54d8584ef82315c1800373272ab08ae0db2d5ef
// NeoNS alias: oracle.morpheus.neo

public static BigInteger FetchPrivateData(ByteString encryptedBlob)
{
 string payloadJson = "{\"url\":\"https://api.secret.io\","
 + "\"encrypted_params\":\"" + (string)encryptedBlob + "\","
 + "\"json_path\":\"data.price\","
 + "\"target_chain\":\"neo_n3\"}";

 return (BigInteger)Contract.Call(
 OracleHash,
 "request",
 CallFlags.All,
 "oracle",
 (ByteString)payloadJson,
 Runtime.ExecutingScriptHash,
 "onOracleResult"
 );
}

public static void OnOracleResult(BigInteger requestId, string requestType, bool success, ByteString result, string error)
{
 Storage.Put(Storage.CurrentContext, "last_result", result);
}

Step 3b: Recover the requestId from the transaction

Wallet relays only return a { txid } — the on-chain requestId is not in the relay response. This is the most common integration mistake. To correlate your request with its callback, poll getapplicationlog(txid) and read the requestId out of the OracleRequested (or MiniAppRequestQueued) notification emitted by the Oracle contract.

javascriptExtract requestId from the request transaction
// Poll the application log until the request notification appears.
async function waitForRequestId(rpcClient, txid, timeoutMs = 90000) {
 const deadline = Date.now() + timeoutMs;
 while (Date.now() < deadline) {
  const log = await rpcClient.getApplicationLog(txid).catch(() => null);
  const notification = (log?.executions?.[0]?.notifications || []).find((entry) =>
   ['OracleRequested', 'MiniAppRequestQueued'].includes(entry.eventname)
  );
  // The requestId is the first item in the notification state array.
  const requestId = notification?.state?.value?.[0]?.value ?? null;
  if (requestId) return requestId;
  await new Promise((resolve) => setTimeout(resolve, 3000));
 }
 throw new Error('timed out waiting for the Oracle request notification');
}

Step 4: Await the Relayer Callback

Once the transaction is mined, the Morpheus Relayer detects the event, forwards the encrypted payload to the enclave (AWS Nitro CVM), and then submits a callback transaction back to the shared kernel containing the signed result envelope. The kernel persists the canonical inbox record first, and optional external callback adapters can mirror that result into custom contracts. If the upstream fetch or compute fails, the request should still finalize with a failure result instead of being silently dropped.

Zero-Code Testing (Mainnet)

You don't need to write or deploy your own contract-specific callback bridge to test Morpheus. The selected Neo N3 Mainnet optional example callback adapter is 0x89b05cac00804648c666b47ecb1c57bc185821b7.

1. Submit Request: Generate your JSON payload using the Dashboard Oracle Builder. Then, invoke request on the shared kernel contract (0xf54d8584ef82315c1800373272ab08ae0db2d5ef) directly using NeoLine or Neo-CLI:

  • Arg 1 (String): "privacy_oracle" or "compute"
  • Arg 2 (ByteString): Your generated JSON payload string
  • Arg 3 (Hash160): 0x89b05cac00804648c666b47ecb1c57bc185821b7
  • Arg 4 (String): "onOracleResult" for the compatibility adapter path
  • Fee: Attach exactly 0.01 GAS to the transaction invocation.

2. Read Result: Check your transaction to get the requestId. Wait about 60 seconds, then read the kernel-managed result path or perform a read-only invoke of getCallback(requestId) on the optional adapter script hash above to view your completed result envelope.

CURRENT DESIGNUPDATED FOR DUAL-CVM ARCHITECTURE