> For the complete documentation index, see [llms.txt](https://argon-4.gitbook.io/argon-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://argon-4.gitbook.io/argon-docs/developers/dapp-integration.md).

# dApp integration

Integrate a website with Enclave: discovering the provider, connecting, signing messages and PSKTs on Kaspa, and using the Igra provider.

Enclave exposes two providers to web pages: a **Kaspa provider** following the KCC-12 draft (Browser Wallet Provider API and Discovery), and an **Igra provider** following the Ethereum provider conventions (EIP-1193 with EIP-6963 discovery). Both are couriers: they carry requests to the extension and answers back, hold no secrets, and cannot sign. Every signature a page obtains passes through a SureSign review the user approves.

{% hint style="warning" %}
KCC-12 is an open draft ([kaspanet/kccs PR #24](https://github.com/kaspanet/kccs/pull/24)). Enclave implements its discovery, request, event, and permission surface as drafted and also keeps serving the earlier KIP-12 draft ([kaspanet/kips PR #44](https://github.com/kaspanet/kips/pull/44), pinned at `4fc711ac`) that `kaspa-wallet-standard` dApps use. Both are re-checked on the schedule in the repository's KCC conformance ledger. Do not treat either draft as final.
{% endhint %}

## Kaspa provider

### Discovery

Enclave announces itself at page load and again whenever a page dispatches `kaspa:requestProvider`. It fires the KCC-12 `kaspa:announceProvider` event and, for older integrations, the KIP-12 draft `kaspa:provider` event with the same detail. Do not hard-code Enclave; discover it.

```js
const wallets = [];
window.addEventListener("kaspa:announceProvider", (ev) => wallets.push(ev.detail));
window.dispatchEvent(new Event("kaspa:requestProvider"));

// ev.detail = { info: { uuid, name, icon, rdns, id, methods }, provider }
const enclave = wallets.find((w) => w.info.rdns === "com.onargon.enclave");
```

`info.methods` lists the wire methods this wallet will execute. `rdns`, `name`, and `icon` identify the wallet to your interface; they are not authentication. The same provider is also available as `window.enclaveProvider`. Enclave never sets or overwrites other wallets' globals.

### Requests (KCC-12)

`provider.request({ method, params })` takes the KCC-12 method registry. Methods in the registry that Enclave does not implement reject with `4200` before any parameter check or prompt.

| Method                      | Params                          | Returns                                            | Approval                                                                         |
| --------------------------- | ------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------- |
| `kaspa_requestAccounts`     | —                               | `[address]` for the current network                | Connect prompt if not yet connected (origin-bound; grants expire after 24 hours) |
| `kaspa_accounts`            | —                               | `[address]`, or `[]` while locked or not connected | Never prompts                                                                    |
| `kaspa_chainId`             | —                               | `"mainnet"` or `"testnet-10"`                      | Never prompts                                                                    |
| `kaspa_signMessage`         | `[message, address?]`           | Schnorr signature, 128 hex chars                   | SureSign review, every time                                                      |
| `kaspa_signTransaction`     | `[{ transaction, signInputs }]` | Signed transaction JSON                            | SureSign review, every time                                                      |
| `wallet_requestPermissions` | `[{ kaspa_accounts: {} }]`      | `[Permission]`                                     | Connect prompt if not yet connected                                              |
| `wallet_getPermissions`     | —                               | `[Permission]` or `[]`                             | Never prompts                                                                    |
| `wallet_revokePermissions`  | `[{ kaspa_accounts: {} }]`      | `null`                                             | Never prompts                                                                    |

`kaspa_sendTransaction`, `kaspa_sendRawTransaction`, `kaspa_signPskb`, `kaspa_sendPskb`, `kaspa_sendRawPskb`, and `wallet_switchKaspaChain` are not implemented (`4200`): the wallet does not broadcast on a site's behalf and will not sign bytes it cannot fully explain to the user. The only permission Enclave defines is `kaspa_accounts`; its `Permission` object carries one `restrictReturnedAccounts` caveat naming the released address and the `date` of the grant.

### Events

`provider.on(event, listener)` / `provider.removeListener(event, listener)` deliver the KCC-12 events. Each fires only when the value actually changes.

| Event             | Payload                       | When                                              |
| ----------------- | ----------------------------- | ------------------------------------------------- |
| `connect`         | `{ chainId }`                 | The first time the provider learns the network    |
| `chainChanged`    | `"mainnet"` or `"testnet-10"` | The user switches network                         |
| `accountsChanged` | `[address]` or `[]`           | Connect, disconnect, account switch, lock, unlock |

Lock, unlock, network, and account changes reach the page as a state signal; the provider then re-reads `kaspa_chainId` and `kaspa_accounts` for that site alone and emits the difference. No site learns about another site's connection.

### Legacy calls (KIP-12 draft)

These remain for integrations built against the KIP-12 draft and map onto the same wallet paths.

| Call                                                           | Returns                                          | Approval                            |
| -------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- |
| `provider.connect()`                                           | `"connected"`                                    | Connect prompt                      |
| `provider.requestAccounts()`                                   | `[address]`                                      | Connect prompt if not yet connected |
| `provider.getNetwork()`                                        | `"mainnet"` or `"testnet-10"`                    | Never prompts                       |
| `provider.getPublicKey()`                                      | Compressed public key hex of the granted address | After connecting                    |
| `provider.signMessage(text, address?)`                         | Schnorr signature, hex                           | SureSign review, every time         |
| `provider.signPskt({ txJsonString, options: { signInputs } })` | Signed transaction JSON                          | SureSign review, every time         |
| `provider.disconnect()`                                        | `"disconnected"`                                 | Never prompts                       |
| `provider.request(method, args)`                               | Positional form of the above                     | As above                            |

Wire method names are `kaspa:connect`, `kaspa:disconnect`, `kaspa:requestAccounts`, `kaspa:accounts`, `kaspa:chainId`, `kaspa:getPublicKey`, `kaspa:getPermissions`, `kaspa:requestPermissions`, `kaspa:revokePermissions`, `kaspa:signPersonal`, `kaspa:signPskt`. Any other KIP-12 method, including opaque `kaspa:send`, `kaspa:sign`, `kaspa:broadcast`, and their `…Transaction` forms, returns error `4200`.

### Errors

Errors follow the KCC-12 / EIP-1193 registry. Parameter errors are returned before the user is prompted.

| Code     | Meaning                                                                                                              |
| -------- | -------------------------------------------------------------------------------------------------------------------- |
| `4001`   | User rejected                                                                                                        |
| `4100`   | Unauthorized (not connected, a signing address other than the released one, or a secret-shaped argument was refused) |
| `4200`   | Unsupported method                                                                                                   |
| `4900`   | Wallet unavailable (locked without a pending unlock, or no signature returned)                                       |
| `4901`   | Chain disconnected (reserved; Enclave does not currently emit it)                                                    |
| `4902`   | Unrecognized chain (reserved; `wallet_switchKaspaChain` is unsupported)                                              |
| `-32602` | Invalid params (malformed `signInputs`, unknown permission name, malformed address, empty message)                   |
| `-32000` | Invalid input (an Igra setup transaction may have been submitted; see the Igra section)                              |
| `-32002` | Resource unavailable (reserved)                                                                                      |
| `-32003` | Transaction rejected (reserved; Enclave does not broadcast)                                                          |

### Message signing

`kaspa_signMessage` signs UTF-8 text under KIP-5 (`PersonalMessageSigningHash`) and returns the 64-byte Schnorr signature as 128 hex characters, verifiable against the released address. The message must be non-empty and at most 4096 bytes. If you pass an address it must be the one `kaspa_requestAccounts` released; any other address is refused with `4100` without prompting. The user sees the exact text, the signing address, and the origin. Use it for proof of address ownership; it does not move KAS and does not grant permission.

### Transaction signing

```js
const signed = await provider.request({
  method: "kaspa_signTransaction",
  params: [{
    transaction: JSON.stringify(tx),                 // the partially signed transaction, as JSON
    signInputs: [{ index: 0, sighashType: 1 }],
  }],
});
```

Rules the wallet enforces, which your integration must respect:

* `signInputs` must be non-empty and name only inputs the wallet controls; the wallet resolves each against its own Notes and refuses others.
* `sighashType` must be `1` (`SIG_HASH_ALL`). Any other value is refused; no mode is substituted.
* `signatureType`, if given, must be `"schnorr"`. `redeemScript` is not supported. Either is refused with `-32602` rather than guessed.
* Every input you did not list is returned byte-for-byte unchanged.
* The user reviews the whole transaction, including inputs that are not theirs. Do not expect the wallet to hide anything.
* Change is whatever the wallet itself derives. An output you label as the user's change is shown as an ordinary payment to that address.

The wallet does not broadcast a PSKT. Your application completes and submits it.

## Igra provider

Igra dApps see an Ethereum-style provider announced through EIP-6963 (`eip6963:announceProvider`, `rdns` `com.onargon.enclave.igra`) and also placed at `window.ethereum` when no other provider holds it (or appended to `window.ethereum.providers` when one does). It is also available as `window.enclaveIgraProvider`.

| Method class                                                                                                                                          | Behaviour                                                                                                                                                                                                                          |
| ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eth_requestAccounts`, `wallet_requestPermissions`, `eth_accounts`, `eth_chainId`, `net_version`                                                      | Connect prompt on first request; then the wallet's single Igra address and chain (`0x97b1` = 38833 on mainnet, `0x97b4` = 38836 on testnet-10).                                                                                    |
| Reads (`eth_call`, `eth_getBalance`, `eth_estimateGas`, `eth_getTransactionReceipt`, `eth_getLogs`, …)                                                | Proxied to the user's configured Igra endpoint after connecting.                                                                                                                                                                   |
| `eth_sendTransaction`                                                                                                                                 | Decoded by SureSign. If the contract and function are pinned, the user reviews a plain-language plan and the call is carried inside a Kaspa transaction; the result is the Igra transaction hash. If not pinned, refused (`4200`). |
| `personal_sign`                                                                                                                                       | Signed after review (EIP-191). Sign-In-With-Ethereum messages must parse, name the requesting origin as their domain, this wallet's address, and the Igra chain.                                                                   |
| `wallet_switchEthereumChain`                                                                                                                          | Accepted only for the Igra chain matching the wallet's current Kaspa network.                                                                                                                                                      |
| `eth_sign`, `eth_signTransaction`, `eth_signTypedData*`, `eth_sendRawTransaction`, `wallet_addEthereumChain`, `wallet_watchAsset`, `wallet_sendCalls` | Refused (`4200`).                                                                                                                                                                                                                  |

Because every Igra transaction is carried by Kaspa, expect the returned hash after the Kaspa transaction is accepted and Igra has produced a receipt; this takes longer than a direct Igra submission. Poll `eth_getTransactionReceipt` as you normally would.

## Requests while locked

`kaspa_accounts`, `kaspa_chainId`, `wallet_getPermissions`, and `wallet_revokePermissions` are answered immediately from public state and never open the wallet; `kaspa_accounts` is `[]` while locked. Any other request that needs the wallet unlocked waits while the user unlocks. Connection requests can be shown to a locked wallet; the user unlocks and then decides. Design your UI for the round trip.

## What your site never receives

Keys, seeds, or anything derived from one; a signature for anything the user did not see in a review; a signature under a mode the wallet does not honor; or permission that outlives the grant. If a request is refused, the error names why.

## Testing locally

Content scripts run on `https://` pages and on `http://localhost` and `http://127.0.0.1`, so a local development server works without TLS. Switch Enclave to testnet-10 under Settings → Network to test against free test coins; the provider reports `testnet-10` and Igra chain `0x97b4`.
