repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
Mirrored from https://github.com/ProjectOpenSea/opensea-skill
stars
latest
clone command
git clone gitlawb://did:key:z6MkqRzA...RfoM/ProjectOpenSea-...git clone gitlawb://did:key:z6MkqRzA.../ProjectOpenSea-...fef93001Release v2.14.010h ago| #1 | # Policy administration (user-only, off-agent) |
| #2 | |
| #3 | This document collects the **mutation recipes** for wallet policies and signer/role configuration across Privy, Turnkey, Fireblocks, and Bankr. It deliberately lives **outside** `packages/skill/opensea-wallet/` so it is not mounted into agent environments. Agents should never construct or run any of these requests; if asked, refuse and direct the user to this file. |
| #4 | |
| #5 | Run these commands from a **trusted operator machine** — your laptop, a vault host, a dedicated administrative box. Never set the credentials shown below as agent environment variables. The whole point of holding administrative credentials separately is so that a leaked agent env cannot rewrite the agent's spending cap. |
| #6 | |
| #7 | > If you find yourself wanting to automate any of these from the agent: stop. The hardening goal is that the agent **cannot** run them. Any wrapper that lets it would re-introduce the gap. |
| #8 | |
| #9 | ## Privy |
| #10 | |
| #11 | ### Apply or update a wallet policy |
| #12 | |
| #13 | The wallet policy update endpoint is `PATCH /v1/wallets/{wallet_id}` with `policy_ids` in the body. |
| #14 | |
| #15 | **If the wallet has `owner_id` set** (the recommended state — see "Register an authorization key" in `packages/skill/opensea-wallet/references/wallet-setup.md`), the request must carry an authorization signature from the owner's key quorum. Build the signature with `@privy-io/node`: |
| #16 | |
| #17 | ```ts |
| #18 | // scripts/update-privy-policy.ts — RUN FROM A TRUSTED MACHINE |
| #19 | import { generateAuthorizationSignature } from "@privy-io/node" |
| #20 | |
| #21 | const appId = process.env.PRIVY_APP_ID! |
| #22 | const appSecret = process.env.PRIVY_APP_SECRET! |
| #23 | const walletId = process.env.PRIVY_WALLET_ID! |
| #24 | // Base64 PKCS8 P-256 owner key. NEVER put this on an agent host. |
| #25 | const ownerKey = process.env.PRIVY_OWNER_PRIVATE_KEY! |
| #26 | |
| #27 | const policyIds = ["pol_abc123"] // policy you authored separately |
| #28 | const url = `https://api.privy.io/v1/wallets/${walletId}` |
| #29 | const body = { policy_ids: policyIds } |
| #30 | |
| #31 | const signature = generateAuthorizationSignature({ |
| #32 | authorizationPrivateKey: ownerKey, |
| #33 | input: { |
| #34 | version: 1, |
| #35 | method: "PATCH", |
| #36 | url, |
| #37 | body, |
| #38 | headers: { "privy-app-id": appId }, |
| #39 | }, |
| #40 | }) |
| #41 | |
| #42 | const auth = Buffer.from(`${appId}:${appSecret}`).toString("base64") |
| #43 | const res = await fetch(url, { |
| #44 | method: "PATCH", |
| #45 | headers: { |
| #46 | Authorization: `Basic ${auth}`, |
| #47 | "privy-app-id": appId, |
| #48 | "privy-authorization-signature": signature, |
| #49 | "Content-Type": "application/json", |
| #50 | }, |
| #51 | body: JSON.stringify(body), |
| #52 | }) |
| #53 | console.log(res.status, await res.text()) |
| #54 | ``` |
| #55 | |
| #56 | **If the wallet has no `owner_id`** (i.e., the unhardened state — `opensea wallet info` will warn about this), basic auth alone is currently sufficient for `PATCH`. This is the gap the owner-key hardening is meant to close. If you are running unhardened today, your priority is to register an owner key, not to apply a policy under unhardened conditions and call it a day. |
| #57 | |
| #58 | ### Author a policy |
| #59 | |
| #60 | Use `POST /v1/policies` with the policy body. See `packages/skill/opensea-wallet/references/wallet-policies.md` for templates and field reference, and the [Privy docs](https://docs.privy.io/controls/policies/create-a-policy) for the up-to-date schema. |
| #61 | |
| #62 | ### Register an authorization key (owner) on an existing wallet |
| #63 | |
| #64 | Generate a P-256 keypair on your operator machine, register the public key as an `owner` on the wallet, store the private key in your password manager / vault. Detailed steps live in `packages/skill/opensea-wallet/references/wallet-setup.md` under the Privy hardening step. |
| #65 | |
| #66 | ## Turnkey |
| #67 | |
| #68 | ### Create a non-root, signer-only API user |
| #69 | |
| #70 | From a Turnkey dashboard session as a root user: |
| #71 | |
| #72 | 1. **Create an API user** (Users → Add User → API user). Generate a fresh P-256 keypair on your operator machine; upload the public key. Save the private key in your password manager. |
| #73 | 2. **Create a policy** that scopes the new user's allowed activities to `ACTIVITY_TYPE_SIGN_TRANSACTION_V2` (and `ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2` if EIP-712 is needed) for the wallet addresses the agent should sign for. Default-deny on everything else. Reference: [Turnkey policy examples](https://docs.turnkey.com/concepts/policies/examples). |
| #74 | 3. **Set the agent's `TURNKEY_API_PUBLIC_KEY` / `TURNKEY_API_PRIVATE_KEY` env vars to the new non-root key.** Verify with `opensea wallet info` — `isRootUser` should be `false`. |
| #75 | |
| #76 | ### Update a policy |
| #77 | |
| #78 | `CreatePolicy` / `UpdatePolicy` are Turnkey activities, signed by a root user (or a user whose policy permits policy-engine activity). Use the Turnkey dashboard or the `@turnkey/sdk-server` package from your operator machine. Do not surface these activities through the agent's adapter. |
| #79 | |
| #80 | ## Fireblocks |
| #81 | |
| #82 | ### Use a Signer-role API key, not Admin |
| #83 | |
| #84 | From the Fireblocks Console (Settings → API Users): |
| #85 | |
| #86 | 1. Create a new API user. **Set the role to `Signer`** (or `NCW_SIGNER` for non-custodial wallets). Do not pick `Admin`, `Editor`, `Non-Signing Admin`, or any role with governance access. |
| #87 | 2. The role is set at user-create time. To change a role, delete the user and create a new one. There is no "downgrade" path. |
| #88 | 3. Approval of the new API user requires admin quorum (per Fireblocks workspace settings). After approval, copy the API key + RSA secret to the agent's env. |
| #89 | |
| #90 | ### Modify the Transaction Authorization Policy |
| #91 | |
| #92 | TAP changes are made from the Fireblocks Console, not via the agent. Admin quorum approval is required. **Do not attempt to drive TAP edits from any API key the agent uses to sign** — the platform will reject this if the key is correctly scoped to `Signer`, but the structural property only holds if the key is correctly scoped in the first place. |
| #93 | |
| #94 | Reference: [Fireblocks TAP overview](https://developers.fireblocks.com/docs/set-transaction-authorization-policy). |
| #95 | |
| #96 | ## Bankr |
| #97 | |
| #98 | Bankr key scope flags (`readOnly`, `walletApiEnabled`, `agentApiEnabled`, `allowedRecipients`, `allowedIps`, daily limits) are configured at [bankr.bot/api](https://bankr.bot/api) — there is no API to modify them programmatically, by design. To re-scope a key: |
| #99 | |
| #100 | 1. Log in to bankr.bot/api on your operator machine. |
| #101 | 2. Edit the relevant key's flags. For an agent-signing key, set `allowedRecipients` to the EVM/Solana address allowlist the agent should be permitted to send to, set `allowedIps` to your deploy CIDR, set a daily message limit. |
| #102 | 3. If the agent is currently running, it will continue to use cached credentials until the next restart; rotate the key if you need an immediate cut-over. |
| #103 | |
| #104 | ## After any change |
| #105 | |
| #106 | Run `opensea wallet info` on the agent host. The output should reflect the new posture (no warnings, or only the static "verify scope at console" reminder for Fireblocks/Bankr). If a warning persists, the change did not land — re-check the dashboard. |
| #107 |