|
| 1 | +# NEXTSTEPS2 — configuration to finish the Bittensor / wallet sign in |
| 2 | +#### (and, at the end, the Stripe checkout config) |
| 3 | + |
| 4 | +Follow-up to [BITTENSOR.md](BITTENSOR.md). The code is built and compiling across |
| 5 | +`server`, `sdk`, `android`, `apple`, and `mmm/ur.io`. What remains is **configuration**: |
| 6 | +one WalletConnect project id in three config files, three deploys in order, and a |
| 7 | +short QA pass over four values that could not be verified from the repo. |
| 8 | + |
| 9 | +Nothing below blocks a build. Every unset value degrades gracefully (see |
| 10 | +[If the project id is left empty](#if-the-project-id-is-left-empty)). |
| 11 | + |
| 12 | +--- |
| 13 | + |
| 14 | +## 1. WalletConnect Cloud project id |
| 15 | + |
| 16 | +One project id is shared by all clients. |
| 17 | + |
| 18 | +**Create it:** a project at the WalletConnect / Reown Cloud dashboard → |
| 19 | +copy the **Project ID**. In the project settings: |
| 20 | + |
| 21 | +- Name: `URnetwork`, URL: `https://ur.io`, icon: the ur.io favicon |
| 22 | + (this metadata is what the wallet shows on the approval screen — the clients |
| 23 | + already send the same values, so keep them consistent). |
| 24 | +- Allowed domains / origins: `ur.io` (add `localhost` for local dev of the web ui). |
| 25 | + |
| 26 | +**Then set it in three places.** All three are placeholders today. |
| 27 | + |
| 28 | +### Android — `android/app/local.properties` |
| 29 | + |
| 30 | +```properties |
| 31 | +WALLETCONNECT_PROJECT_ID=<project id> |
| 32 | +``` |
| 33 | + |
| 34 | +Surfaces as `BuildConfig.WALLETCONNECT_PROJECT_ID` (wired in `app/app/build.gradle` |
| 35 | +next to `BUNDLER_RPC_URL`), and is passed to the bridge as `wc_project_id` by |
| 36 | +`ui/login/LoginUtils.kt`. Gradle prints a warning when it is unset. |
| 37 | + |
| 38 | +> `local.properties` is **not** in version control — it must also be set on the |
| 39 | +> build machine / CI, the same way `BUNDLER_RPC_URL` is. |
| 40 | +
|
| 41 | +### Apple — `apple/app/URnetwork-Info.plist` |
| 42 | + |
| 43 | +```xml |
| 44 | +<key>URWalletConnectProjectId</key> |
| 45 | +<string><project id></string> |
| 46 | +``` |
| 47 | + |
| 48 | +Read by `ConnectWalletProviderViewModel.openBittensorSignIn` and passed to the |
| 49 | +bridge as `wc_project_id`. |
| 50 | + |
| 51 | +### Web + bridge — `mmm/ur.io` build environment |
| 52 | + |
| 53 | +```sh |
| 54 | +PUBLIC_WALLETCONNECT_PROJECT_ID=<project id> |
| 55 | +``` |
| 56 | + |
| 57 | +**`PUBLIC_`, not `VITE_`** — production is built by Astro, whose `envPrefix` is |
| 58 | +`PUBLIC_`, so a `VITE_*` variable never reaches the bundle (this is also why the |
| 59 | +other client config there — `PUBLIC_SOLANA_MERCHANT`, `PUBLIC_SOLANA_USDC_MINT` — |
| 60 | +uses that prefix). A WalletConnect project id is a public client identifier meant |
| 61 | +to ship in the browser bundle, so `PUBLIC_` is correct on its own merits too. |
| 62 | +There is no `.env` file in the repo today — set it in the build environment, or |
| 63 | +add `mmm/ur.io/react/.env`. It is read by **both**: |
| 64 | + |
| 65 | +- `react/src/components/WalletConnect.jsx` — the `/wallet-connect` bridge the |
| 66 | + native apps open. Precedence: the `wc_project_id` query param the app sends |
| 67 | + **wins**; this env var is the fallback for direct visits. |
| 68 | +- `react/src/auth/walletAuth.js` — the web ui's own "Continue with Bittensor" / |
| 69 | + "Continue with Solana" buttons in the login dialog. |
| 70 | + |
| 71 | +The astro site imports these from `react/src` (`@ur` alias), so one value covers |
| 72 | +both builds. |
| 73 | + |
| 74 | +### If the project id is left empty |
| 75 | + |
| 76 | +No crash and no dead buttons — wallet sign in simply falls back to **injected |
| 77 | +wallets only**: |
| 78 | + |
| 79 | +| surface | with a project id | without | |
| 80 | +|---|---|---| |
| 81 | +| web login dialog (desktop) | extension, else QR | extension only | |
| 82 | +| web login dialog (mobile) | wallet app deep link | *no wallet path* | |
| 83 | +| app sign in → bridge (desktop) | extension, else QR | extension only | |
| 84 | +| app sign in → bridge (mobile) | wallet app deep link | wallet's in-app browser only | |
| 85 | + |
| 86 | +Desktop users with an extension (Phantom/Solflare; Bittensor Wallet, SubWallet, |
| 87 | +Talisman, polkadot-js) work either way. **Mobile wallet pairing is the thing the |
| 88 | +project id buys.** |
| 89 | + |
| 90 | +--- |
| 91 | + |
| 92 | +## 2. Deploy order |
| 93 | + |
| 94 | +1. **`server`** — sr25519 verification + the `TAO` blockchain. Must be live |
| 95 | + **before** any client that can produce a Bittensor login, or those logins fail |
| 96 | + with `unsupported blockchain`. No DB migration is needed (`blockchain |
| 97 | + varchar(32)` already fits `TAO`). |
| 98 | +2. **`mmm/ur.io`** — the `/wallet-connect` bridge (bittensor provider + |
| 99 | + WalletConnect) and the web login dialog. The shipped apps point at |
| 100 | + `https://ur.io/wallet-connect`, so the site must be redeployed before app |
| 101 | + releases reach users. |
| 102 | +3. **`android` / `apple`** releases, built against the rebuilt SDK artifacts |
| 103 | + (already regenerated locally: `.aar`, `.xcframework`, cgo headers). |
| 104 | + |
| 105 | +--- |
| 106 | + |
| 107 | +## 3. Verify in QA (four values written from spec, not from this repo) |
| 108 | + |
| 109 | +Each is isolated as a named constant with a comment. If a wallet rejects the |
| 110 | +session proposal or the server rejects a signature, start here. |
| 111 | + |
| 112 | +| # | value | where | |
| 113 | +|---|---|---| |
| 114 | +| 1 | Bittensor CAIP chain id `polkadot:2f0555cc76fc2840a25a6ea3b9637146` (first 32 hex of the finney genesis hash) | `react/src/components/WalletConnect.jsx`, `react/src/auth/walletAuth.js` | |
| 115 | +| 2 | Solana CAIP chain id `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` (mainnet-beta) | `react/src/auth/walletAuth.js` | |
| 116 | +| 3 | WalletConnect Solana signature is base58 → decoded to base64 for the server | `react/src/auth/walletAuth.js` (`signInWithSolana`) | |
| 117 | +| 4 | **One real-wallet signature end to end.** sr25519 is verified round-trip against `go-schnorrkel`, but not yet cross-implementation. Sign in once with a real wallet (Bittensor Wallet extension, polkadot-js, or a WalletConnect wallet) and confirm the server accepts it. | `server/model/auth_bittensor.go` | |
| 118 | + |
| 119 | +The injected-wallet path touches neither chain id — that is the common desktop |
| 120 | +case, and it exercises the server verification the same way. |
| 121 | + |
| 122 | +--- |
| 123 | + |
| 124 | +## 4. Behavior worth knowing before QA |
| 125 | + |
| 126 | +- **Signed message**: all clients sign the static `"Welcome to URnetwork"`, the |
| 127 | + same string the Solana flow already signs. No client sends a nonce; the server |
| 128 | + only enforces one *when present* (`handleLoginWallet`). If nonce presence is |
| 129 | + ever made mandatory, every wallet client must be updated together. |
| 130 | +- **Bittensor wallets are storage only.** They are recorded for future use and |
| 131 | + can never be the payout wallet: the apps hide "Make default", and the server |
| 132 | + rejects it in `SetPayoutWallet` **and** skips the auto-set-first-wallet-as-default |
| 133 | + on wallet creation. A Bittensor *signup* also creates no payout wallet |
| 134 | + (`NetworkCreate` only auto-creates one for `SOL`/`MATIC`). |
| 135 | +- **Connect wallet** for Bittensor is paste-an-address (ss58, checksum-validated |
| 136 | + server side) — no signature, per the decision in BITTENSOR.md. |
| 137 | +- **Sign-up parity**: an unlinked wallet routes to create-network with the wallet |
| 138 | + on every client, including the web dialog (which swaps the email/password |
| 139 | + fields for the connected wallet's address). |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## 5. Stripe checkout (the non-Apple upgrade path) |
| 144 | + |
| 145 | +`POST /stripe/create-checkout-session` now takes a `ui_mode`: |
| 146 | + |
| 147 | +- **`hosted`** (default, back-compatible) → returns `checkout_url` for the system browser. This is what the website already uses. |
| 148 | +- **`embedded`** → returns `client_secret` + `publishable_key`, for **inline** checkout: the desktop apps load `https://ur.io/checkout?client_secret=<cs>&redirect_link=urnetwork://…` in an embedded webview (WebView2 / WebKitGTK). On completion the page returns `urnetwork://…?status=complete&session_id=…`, and the app polls the subscription balance. |
| 149 | + |
| 150 | +A single Stripe Checkout Session **cannot** return both a `client_secret` and a `url` — the two are mutually exclusive by `ui_mode` — so the caller picks the mode. Note embedded checkout has **no cancel URL** (the customer never leaves the page), so the app must provide its own close affordance. |
| 151 | + |
| 152 | +The subscription is granted by the **`invoice.paid` webhook**, never by the client. The client only polls afterwards. |
| 153 | + |
| 154 | +### Config to fill in |
| 155 | + |
| 156 | +```yaml |
| 157 | +# config/<env>/stripe.yml (the config repo — outside android/apple/server) |
| 158 | +checkout: |
| 159 | + return_url: "https://ur.io/checkout?complete=1&session_id={CHECKOUT_SESSION_ID}" # NEW, required for embedded |
| 160 | +``` |
| 161 | +
|
| 162 | +```sh |
| 163 | +# mmm/ur.io build environment |
| 164 | +PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_… # pk_test_… on canary |
| 165 | +``` |
| 166 | + |
| 167 | +Both are optional-but-degrading: without `return_url`, embedded mode refuses cleanly ("Checkout is not configured") instead of stranding someone mid-payment in a webview; without the publishable key the build warns and `/checkout` says the same. A **malformed** key fails the build on purpose. |
| 168 | + |
| 169 | +--- |
| 170 | + |
| 171 | +## Appendix — unrelated build config still outstanding |
| 172 | + |
| 173 | +Not part of Bittensor, but needed to ship the desktop SDK artifacts (the cgo |
| 174 | +header already exports `TAO`): |
| 175 | + |
| 176 | +- **windows/arm64** SDK dll — needs `llvm-mingw` on the build host |
| 177 | + (`x86_64` builds today with the installed mingw-w64). |
| 178 | +- **linux** SDK `.so` — needs `zig` (`sdk/cgo/Makefile` pins the glibc 2.35 floor |
| 179 | + via `zig cc`). |
| 180 | + |
| 181 | +Until both are installed, `make -C sdk/cgo build_windows build_linux` cannot |
| 182 | +produce `URnetworkSdkWindows.zip` / `URnetworkSdkLinux.zip`, and the |
| 183 | +`windows` / `linux` apps cannot link the connect-drawer work against the current |
| 184 | +SDK. |
0 commit comments