From 26a40fd95aab9366dbe1924ecc9260b1f0264e18 Mon Sep 17 00:00:00 2001 From: Michael Turner Date: Wed, 5 Aug 2026 23:34:08 -0500 Subject: [PATCH] [Chore] Version packages to 0.7.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consumes the twenty pending changesets as a lockstep minor: 0.6.0 -> 0.7.0 across the fixed group, bridge 0.4.2 -> 0.4.3, and the core version constant synced by `scripts/sync-versions.mjs`. Unlike 0.6.0, the number did not have to be held by hand. That release recorded "changesets resolved the release as 1.0.0 because the workspace:^ peer ranges on veil-core make any 0.x minor out-of-range for peer dependents". Those ranges are now `workspace:>=0.6.0 <1.0.0`, so a 0.x minor stays inside them, `onlyUpdatePeerDependentsWhenOutOfRange` leaves the peer dependents alone, and `changeset version` produces the intended minor on its own. What ships, in short: the shield-swap CLI as its own package; blinded-identity reservation, tracking and recovery; `previewMint`, `planSwap`, `tokenData`, `listTokens`, `liquidityForAmount`, and typed unit converters; per-network DEX API hosts; the Q128 helpers on options objects with their positional forms deprecated; `SHIELD_WRAPPERS` removed; a one-minute confirmation default; and Provable API authentication in veil-aleo-sdk. Verified before tagging: `pnpm build` clean, `pnpm -r exec tsc --noEmit` clean, 1475 tests passing. Tarballs checked by packing rather than by inspection — the `workspace:` protocol resolves to `>=0.6.0 <1.0.0` in the published peerDependencies, and the shield-swap tarball carries 27 files with no state file or credentials among them. --- .changeset/blinded-identity-reservation.md | 58 --- .changeset/bump-provable-sdk-0-11-6.md | 19 - .changeset/confirmation-timeout.md | 11 - .changeset/confirmation-window.md | 29 -- .changeset/derived-host-undefined-baseurl.md | 14 - .changeset/dex-api-network-hosts.md | 32 -- .changeset/initialized-ticks-hint-source.md | 30 -- .changeset/liquidity-for-amounts.md | 20 - .changeset/owned-position-lag.md | 13 - .changeset/preview-mint.md | 32 -- .changeset/provable-api-session.md | 83 ---- .changeset/q128-options-objects.md | 47 -- .changeset/recover-abandoned-swaps.md | 28 -- .changeset/remove-shield-wrappers.md | 36 -- .changeset/rename-authenticate-api.md | 16 - .changeset/route-quote-decimals.md | 34 -- .changeset/shield-swap-cli-package.md | 27 -- .changeset/swap-identity-tracking.md | 49 -- .changeset/tick-hints-no-wasm.md | 20 - .changeset/tick-insert-hints.md | 25 - packages/bridge/CHANGELOG.md | 8 + packages/bridge/package.json | 2 +- packages/codegen/CHANGELOG.md | 8 + packages/codegen/package.json | 2 +- packages/core/CHANGELOG.md | 108 +++++ packages/core/package.json | 2 +- packages/core/src/version.ts | 2 +- packages/devnode/CHANGELOG.md | 18 + packages/devnode/package.json | 2 +- packages/leo/CHANGELOG.md | 2 + packages/leo/package.json | 2 +- packages/provable-sdk/CHANGELOG.md | 130 ++++++ packages/provable-sdk/package.json | 2 +- packages/react/CHANGELOG.md | 9 + packages/react/package.json | 2 +- packages/shield-swap-cli/CHANGELOG.md | 53 +++ packages/shield-swap-cli/package.json | 2 +- packages/shield-swap/CHANGELOG.md | 457 +++++++++++++++++++ packages/shield-swap/package.json | 2 +- packages/wallet-adapter/CHANGELOG.md | 2 + packages/wallet-adapter/package.json | 2 +- 41 files changed, 806 insertions(+), 634 deletions(-) delete mode 100644 .changeset/blinded-identity-reservation.md delete mode 100644 .changeset/bump-provable-sdk-0-11-6.md delete mode 100644 .changeset/confirmation-timeout.md delete mode 100644 .changeset/confirmation-window.md delete mode 100644 .changeset/derived-host-undefined-baseurl.md delete mode 100644 .changeset/dex-api-network-hosts.md delete mode 100644 .changeset/initialized-ticks-hint-source.md delete mode 100644 .changeset/liquidity-for-amounts.md delete mode 100644 .changeset/owned-position-lag.md delete mode 100644 .changeset/preview-mint.md delete mode 100644 .changeset/provable-api-session.md delete mode 100644 .changeset/q128-options-objects.md delete mode 100644 .changeset/recover-abandoned-swaps.md delete mode 100644 .changeset/remove-shield-wrappers.md delete mode 100644 .changeset/rename-authenticate-api.md delete mode 100644 .changeset/route-quote-decimals.md delete mode 100644 .changeset/shield-swap-cli-package.md delete mode 100644 .changeset/swap-identity-tracking.md delete mode 100644 .changeset/tick-hints-no-wasm.md delete mode 100644 .changeset/tick-insert-hints.md create mode 100644 packages/shield-swap-cli/CHANGELOG.md diff --git a/.changeset/blinded-identity-reservation.md b/.changeset/blinded-identity-reservation.md deleted file mode 100644 index 189c5f9..0000000 --- a/.changeset/blinded-identity-reservation.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Reserve blinded identities through a store, and expose `resolveDexImports` as an action. - -Swaps that ran in parallel from one local account reverted on finalize. A swap is -bound to a blinded identity, and the program asserts each blinded address appears -in `used_blinded_addresses` only once. With no `blindedIdentity` passed, `swap` and -`swapMultiHop` called `nextBlindedIdentity`, which scans for the first counter the -chain does not carry — correct in sequence, wrong in parallel. Two concurrent swaps -read the same unused counter and the second reverted, with nothing to see locally -because at proving time the address genuinely was unused. Disjoint input tokens did -not help: the identity is per account, not per token. - -`reserveBlindedIdentity` closes the window by recording a reservation before -returning it, and never issuing a counter at or below one already stored — so an -unconfirmed swap still holds its counter. It moves monotonically from the highest -known counter, and skips any address the chain already carries, which recovers a -store another process has moved past. An empty store scans from 0, so a lost store -costs reads rather than correctness. Local accounts only: a wallet derives and -tracks its own identities. - -Reservations persist through a `BlindedIdentityStore`. -`memoryBlindedIdentityStore` is the default — enough to keep one process's -concurrent swaps apart — and `fileBlindedIdentityStore` on the new -`@provablehq/shield-swap-sdk/node` entry point persists them across restarts, which -is what a bot or a test suite wants. Configure either with -`shieldSwapActions({ blindedIdentities })`. - -`recordBlindedSwap` attaches a swap id to a reservation, and -`syncBlindedIdentities` reconciles the store against the chain: `reserved` until -the address appears on chain, then `swapped` while its output is unclaimed and -`claimed` once the claim consumes it. That makes proceeds recoverable after a -crash — an identity is otherwise unrecoverable, since it is derived rather than -recorded anywhere the account can see. - -`resolveDexImports` is now on the client as `client.resolveDexImports()` alongside -the standalone export, which is unchanged. Every write needs its result and it -already took `(client, params)`, so the action form removes an import for callers -who have a composed client. - -`reconcileSwapHistory` recovers a store's past. Blinded identities are derived -rather than recorded, and a claim deletes the `swap_outputs` entry it settles, so -the `claim_swap_output` call is the only public trace tying an identity to its -swap — its inputs carry the blinded address, swap id, token pair, and amounts. The -action walks that history through `getProgramCallsPaginated` and `getTransaction`, -marks matched identities `claimed`, and returns what it found. It stops as soon as -every identity is accounted for, so a current store costs one page, and reports -`complete: false` when it hit `maxPages` with history left. Recommended once when -adopting a store for an account that already has history; `syncBlindedIdentities` -remains the cheap call for routine use. It cannot surface unclaimed swaps, which -by definition have no claim call. - -Verified against live testnet: seeded with a blinded address from a real claim, it -recovered the swap id, both token ids, and the amounts in two pages, and the -recovered id reads `null` from `swap_outputs` — which is what a settled claim -should look like. diff --git a/.changeset/bump-provable-sdk-0-11-6.md b/.changeset/bump-provable-sdk-0-11-6.md deleted file mode 100644 index 910a1bb..0000000 --- a/.changeset/bump-provable-sdk-0-11-6.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -'@provablehq/veil-aleo-sdk': minor -'@provablehq/shield-swap-sdk': minor -'@provablehq/veil-aleo-devnode': minor ---- - -Bump `@provablehq/sdk` to `^0.11.6`. - -0.11.6 adds a consensus version, so the devnode height lists grow from 17 -entries to 18. Both must match the SDK's count exactly and mirror each other — -`DEVNODE_CONSENSUS_HEIGHTS` in `@provablehq/veil-aleo-sdk` and the -`CONSENSUS_VERSION_HEIGHTS` default in `@provablehq/veil-aleo-devnode`. A short -list panics with an opaque wasm `unreachable`. - -The `aleo-devnode` binary now comes from the `@provablehq/aleo-devnode` npm -package rather than a GitHub release, so `pnpm install` provides it and the -version is pinned in `package.json` like any other dependency. `startDevnode` -still resolves it from `PATH` and still accepts `devnodePath`, so nothing -changes for a consumer pointing at their own build. diff --git a/.changeset/confirmation-timeout.md b/.changeset/confirmation-timeout.md deleted file mode 100644 index 3e0440a..0000000 --- a/.changeset/confirmation-timeout.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@provablehq/veil-aleo-sdk': minor ---- - -Expose `confirmationTimeout` on `createAleoClient`. - -`createProvingConfig` accepted it but `createAleoClient` did not forward it, so a -caller using the convenience factory was fixed at the default and had to compose the -proving config by hand to change it. Multi-hop swaps exceed that — one -measured at 322 seconds against a 300-second limit, surfacing as a timeout on a -transaction that was still pending and would confirm. diff --git a/.changeset/confirmation-window.md b/.changeset/confirmation-window.md deleted file mode 100644 index a6bb8d6..0000000 --- a/.changeset/confirmation-window.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -'@provablehq/veil-core': minor -'@provablehq/veil-aleo-sdk': minor ---- - -Shorten the confirmation window to one minute, and report what the polls saw. - -`waitForConfirmation` defaulted to 300 seconds. Measured against the live testnet -deployment, healthy confirmations land far inside that — a mint took 49.7s and an -increase 39s, both including proving — so a transaction still absent at the limit -is more often one the node never included than one about to arrive. The default is -now 60_000, and callers on a congested network or a slower path raise it per client. - -This is a behaviour change: a write that previously confirmed between one and five -minutes now throws `TransactionTimeoutError` instead of returning. Multi-hop swaps -are the known case — one was measured at 322 seconds — and a client submitting them -should set `confirmationTimeout` explicitly (around `400_000`) rather than take the -default. The shield-swap README and the `createProvingConfig` reference both say so -on the multi-hop path. - -The timeout error also reports what the polls observed. Every polling failure was -previously swallowed, so a node that answered cleanly and consistently did not have -the transaction was indistinguishable from one that could not be reached — and the -message asserted the transaction "may still be pending", which is exactly backwards -for a transaction that was dropped before inclusion. `TransactionTimeoutError` now -carries `polls` and `absentPolls`, and its message states which case it saw. It does -not diagnose why: the confirmed-transaction endpoint cannot tell a pending -transaction from a dropped one on its own, so the message reports the observation -and leaves the conclusion to the caller. diff --git a/.changeset/derived-host-undefined-baseurl.md b/.changeset/derived-host-undefined-baseurl.md deleted file mode 100644 index a5af75d..0000000 --- a/.changeset/derived-host-undefined-baseurl.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': patch ---- - -Keep deriving the DEX API host when `baseUrl` is passed as `undefined`. - -`shieldSwapActions` built its `ApiClient` by setting the derived host and then -spreading the caller's `api` options over it. A caller writing -`baseUrl: process.env.VEIL_DEX_API_URL` with that variable unset passes the key -with an `undefined` value, and the spread let it beat the derived host — after -which `ApiClient` fell back to its deprecated testnet constant. A mainnet client -would then read pools that do not exist on the program it proves against, with -nothing in the configuration to suggest it. The coalesce is now applied after the -spread, so only a `baseUrl` that is actually set overrides the derivation. diff --git a/.changeset/dex-api-network-hosts.md b/.changeset/dex-api-network-hosts.md deleted file mode 100644 index fc4f871..0000000 --- a/.changeset/dex-api-network-hosts.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Derive the DEX API host from the client's network. - -`DEFAULT_API_URL` shipped as `amm-api.dev.provable.com`, which indexes the -pre-migration `shield_swap_v3.aleo`. Since #110 moved this SDK to -`shield_swap.aleo`, that host serves pools which do not exist on the program the -SDK reads and proves against — so pool discovery returned keys and every chain -read of them came back `null`, surfacing as "pool does not exist" rather than as a -misconfigured URL. - -The API is deployed per-network on separate hosts, so a single constant cannot be -right for both. `shieldSwapActions` now derives it from the client's network — -`mainnet` to `api.swap.shield.fi`, otherwise `api.testnet.swap.shield.fi` — and an -explicit `api.baseUrl` still wins. `SHIELD_SWAP_API_URLS` and `defaultApiUrl()` -are exported for callers constructing an `ApiClient` directly. - -The host resolves per request rather than at construction, so `switchChain` -re-targets the API instead of leaving it on the network the client started from. -`ApiClientOptions.baseUrl` accordingly accepts `string | (() => string)`, and -`ApiClient.baseUrl` becomes a getter — still a readable string. - -`DEFAULT_API_URL` is deprecated and now points at the testnet host. It is removed -in the next major; a caller who needs a specific network should use -`defaultApiUrl(network)`. - -Three integration suites defaulted to `amm-api-staging.dev.provable.com`, which -now returns 404 for everything. They default to the testnet host instead — with it, -35 previously-failing live tests pass, including the route-quote test recorded as -known-red. diff --git a/.changeset/initialized-ticks-hint-source.md b/.changeset/initialized-ticks-hint-source.md deleted file mode 100644 index 94c9615..0000000 --- a/.changeset/initialized-ticks-hint-source.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Derive insert hints from the DEX API when the WASM peer is unavailable. - -`pickInsertHint` walks the contract's initialized-tick list, which needs -`@provablehq/sdk` to hash each tick key. Without the peer it fell back to the -slot's two neighbours — correct only for a target within one initialized tick of -the current price, and wrong for anything further out, which finalize rejects at -the caller's expense. - -The API already answers this exactly. `GET /pools/{key}/initialized-ticks` returns -the pool's full sorted tick list, and its own description names the purpose: -computing `tick_lower_hint` / `tick_upper_hint` for the AMM's hint-walk asserts. -It is now exposed as `client.api.getInitializedTicks(poolKey)`, and -`shieldSwapActions` supplies it to `pickInsertHint`, `mint`, and -`increaseLiquidity` automatically — so a wallet-backed client with no WASM gets -the exact predecessor instead of a guess. Verified against three live testnet -pools: the API-derived predecessor matched the chain walk on every one. - -Three sources now, in descending order of authority: the contract's own list -whenever the peer is present, the API list when it is not, and the slot's -neighbours only when neither is available. The chain stays preferred because the -API list is indexed from positions rather than read from the contract, so it can -lag a position minted moments ago — and a stale hint costs a fee. A failing or -unauthenticated API drops to the slot rather than failing the write. - -`mint` and `increaseLiquidity` accept `initializedTicks` for callers driving them -outside the decorator. diff --git a/.changeset/liquidity-for-amounts.md b/.changeset/liquidity-for-amounts.md deleted file mode 100644 index bb3d786..0000000 --- a/.changeset/liquidity-for-amounts.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Add `liquidityForAmounts`, the deposit-side inverse of `amountsForLiquidity`. - -The package could turn a liquidity figure into token amounts but not the reverse, -which is the direction a depositor starts from: a caller holds two balances and -wants to know what position they support. Without it, every caller had to invent a -liquidity number and work forwards, and a figure that balances at one pool's price -falls short at another — one side runs out and the mint reverts. - -`liquidityForAmounts` mirrors the contract's own derivation: at or below the range -token0 binds, at or above it token1, and inside the range the shorter side governs, -with the same branch boundaries as `amountsForLiquidity` (`price <= lower` counts as -below). Every step floors, so the result is a lower bound — feeding it back through -`amountsForLiquidity` with deposit-side rounding returns amounts that fit inside the -originals, which is what keeps a mint from reverting for want of a base unit. That -property is asserted across a sweep of ticks, range widths, and magnitudes rather -than on a single case. It returns 0 when the amounts are dust for the range's width. diff --git a/.changeset/owned-position-lag.md b/.changeset/owned-position-lag.md deleted file mode 100644 index b33654e..0000000 --- a/.changeset/owned-position-lag.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': patch ---- - -Document what a `null` `state` means on an owned position. - -`getOwnedPositions` and the README described it as a mint still finalizing, which -covers one end of a position's life. The other end behaves the same way and was -undocumented: the record scanner marks records spent on its own schedule, and was -measured still serving a burned position more than four minutes after the burn -confirmed. So a `null` state is equally a position that no longer exists, and a -caller rendering a portfolio should treat it as "not a live position" rather than -as a value still loading. diff --git a/.changeset/preview-mint.md b/.changeset/preview-mint.md deleted file mode 100644 index 8219fbf..0000000 --- a/.changeset/preview-mint.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Add `previewMint`, which answers what a mint would open before anything is signed. - -Everything needed to plan a deposit was already exported, but assembling it was -left to the caller: read the slot, floor both bounds onto the pool's tick spacing, -price them with `getSqrtPriceAtTickX128`, ask `liquidityForAmounts` what the -budget backs, then run it back through `amountsForLiquidity` with deposit-side -rounding to learn what the mint actually consumes. Six steps in a fixed order, -where getting the rounding direction wrong on the last one costs a reverted -transaction, and skipping the alignment on the second produces bounds the contract -rejects outright. - -`previewMint(client, params)` composes exactly those primitives — it introduces no -new math — and returns the aligned bounds, the resulting liquidity, the amounts -each side gives up, and the pool state they were derived from. The range comes -either from explicit ticks or from `rangePercent`, a half-width in percent of the -pool's current price that defaults to 5, so a caller who thinks in "±5% around the -market" does not have to convert to ticks. Bounds are reported after alignment, -because that is the range the mint opens. - -Two things it reports that a caller would otherwise have to know to look for: -`inRange`, since a position outside the active tick earns nothing and is funded -from one side only, and `feeTierSpacing`, the spacing the `fee_to_tick_spacing` -registry binds to the pool's fee — equal to the pool's own on a healthy pool, and -a signal that the pool has drifted from its fee tier when it is not. The pool's -spacing governs either way, because that is what `mint` aligns against. - -`liquidity` of 0 is a result, not an error: the budget backs nothing over that -range, so a mint would cost a fee and open nothing. diff --git a/.changeset/provable-api-session.md b/.changeset/provable-api-session.md deleted file mode 100644 index 40002d6..0000000 --- a/.changeset/provable-api-session.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -'@provablehq/veil-core': minor -'@provablehq/veil-aleo-sdk': minor ---- - -Add Provable API authentication to `@provablehq/veil-aleo-sdk`, and make `Client` carry the actions layered onto it. - -`createAleoClient` now builds a single Provable API session from its credential -options and shares it across delegated proving and record scanning, so one -credential mints one JWT rather than each service minting its own. The returned -wallet client carries `authenticateProvableApi()`, which resolves that session — -registering a consumer when none is configured — and reports the credentials, the -token expiry, whether a consumer was registered, and which paths the session -reaches. - -New in `@provablehq/veil-aleo-sdk`: - -- `registerProvableApi({ username })` — registers a consumer and returns its id - and API key. The key is issued once, so persist it. -- `createProvableSession({ credentials | store, username })` — a session that - caches its JWT, refreshes inside a five-minute expiry margin, and collapses - concurrent mints onto one request. -- `authenticateProvableApi(client, params?)` and `provableApiActions()` — the - action and its decorator. -- `ProvableCredentialStore`, with two implementations. `fileCredentialStore(path)` - from the new `@provablehq/veil-aleo-sdk/node` subpath persists to JSON at mode - `0600`, so a process registers on first run and reuses the consumer afterward; - it lives behind a subpath so `node:fs` never reaches a browser bundle. - `memoryCredentialStore()` holds credentials for the life of the process and is - the default when a client is given neither credentials nor a store, so delegated - proving works unconfigured — but a consumer registered there is lost at exit, - and the API issues each key once, so anything long-lived wants persistence. An - explicit `consumerId`/`apiKey` pair takes precedence over a store, so a rotated - key needs no state reset. -- `session` on `createProvingConfig`, `createRemoteScanner`, and - `createStandaloneScanner`, and `setSession` on the providers the first two - return. `consumerId` is now optional on both scanners — but required alongside - `apiKey` when no session supplies tokens, since a JWT is minted from the pair; - an incomplete pair throws at construction rather than 401ing on the first scan. -- `username` on `createAleoClient`, choosing the name a consumer is registered - under when one has to be. Used verbatim, so the consumer is identifiable; - defaults to a name derived from the account address plus a random suffix. - A taken name now fails with an error stating that credentials cannot be - recovered from a username — the API has no endpoint that reads a consumer back - and a duplicate registration returns nothing usable, so the stored key is the - only copy. - -The delegated-proving path also gains the 401 re-mint retry that only record -scanning had, and record scanning now replaces its token only when the token was -what the service rejected, rather than on every transient failure. - -**`proverUrl` is now a base URL, and defaults.** Pass -`https://api.provable.com/prove` and the active network is appended, mirroring -`createRemoteScanner`'s `url`. Omit it under `mode: 'delegated'` and it falls back -to the new `DEFAULT_PROVER_URL` export — `provingMode` already defaulted to -`'delegated'`, so a client built without a prover used to construct fine and then -fail on its first write. Local proving still resolves no endpoint. - -The base-URL shape is also a fix. Previously the network was baked into the value -the caller supplied, so `switchChain` left delegated proving pointed at the network -the client started from — and confirmation polling with it, since it read the -network the handle was loaded with rather than the one in force. Both now follow -the switch. A value that still carries a trailing `/mainnet` or `/testnet` is -re-targeted rather than doubled, so existing callers keep working, and -`ProvingConfig.url` reports the endpoint for the network currently in force rather -than echoing the input. - -**Scanner `url` is optional too**, defaulting to the new `DEFAULT_SCANNER_URL`. -It was `createRemoteScanner`'s only required field, so that factory now takes no -arguments at all, and `createStandaloneScanner` needs only a view key. Together -with the credential store's in-memory default, a delegated client and its scanner -are buildable from nothing but a private key and a node URL. - -In `@provablehq/veil-core`, `Client` takes an accumulating `extended` type -parameter, defaulting to `{}`, and `extend` returns -`Client` instead of `Client & extended`. Chained `extend` calls -previously dropped earlier layers from the type — a wallet client extended once -lost `writeContract` and `recordProvider` from its type, though not at runtime. -A decorator can now also build on the layer beneath it, and the new `Extended` -constraint stops a decorator from shadowing `request`, `transport`, or `uid`. -`PublicClient`, `WalletClient`, `TestClient`, and `BridgeClient` are expressed -through the parameter. Existing code needs no change: the parameter's default -makes a bare `Client` mean what it always did. diff --git a/.changeset/q128-options-objects.md b/.changeset/q128-options-objects.md deleted file mode 100644 index dae5c66..0000000 --- a/.changeset/q128-options-objects.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Give the Q128 position math options objects, and add `liquidityForAmount`. - -The math helpers took their arguments positionally, and the arguments are mostly -same-typed bigints: `amountsForLiquidity(sqrtPrice, sqrtA, sqrtB, liquidity, -roundUp)`. Swapping the price for a bound type-checks and returns a plausible -wrong answer — a position reported as one-sided when it straddles the price, or a -deposit sized against the wrong end of its range. Nothing catches it. - -They now take objects with named fields, matching `feeGrowthInside`, which was -already shaped that way, and the viem convention these packages otherwise follow: -positional for one or two obvious arguments, an options object as soon as the -arguments are confusable. - -```ts -const range = { - sqrtPriceX128: slot.sqrt_price, - sqrtLowerX128: getSqrtPriceAtTickX128(tickLower), - sqrtUpperX128: getSqrtPriceAtTickX128(tickUpper), -} -const liquidity = liquidityForAmounts({ ...range, amount0, amount1 }) -const amounts = amountsForLiquidity({ ...range, liquidity, roundUp: true }) -``` - -Nothing breaks yet. `amountsForLiquidity`, `amount0DeltaX128`, `amount1DeltaX128` -and `feeOwed` shipped in 0.6.0, so each keeps its positional form as a deprecated -overload returning identical numbers, removed in the next major; a test asserts -the two shapes agree, including the wrapping path in `feeOwed` where transposing -the growth figures is the specific mistake the object form prevents. -`liquidityForAmounts` was never released and takes the object form only. - -Also adds `liquidityForAmount`, which answers what ONE side alone supports. -`liquidityForAmounts` takes two ceilings and lets the shorter one govern, which is -right for "deposit what I have" and wrong for "deposit exactly this much of one -token" — there, a short balance on the other side silently shrinks the position -instead of reporting that it cannot be funded. Pair it with `amountsForLiquidity` -to get the other side's minimum. It returns `0` when the price puts the named side -out of use — above a range a position holds only token1, so token0 funds nothing — -which is a different condition from "deposit more" and worth distinguishing. - -`liquidity.ts --increase` uses it: naming one amount now derives the other as the -minimum that must accompany it, and fails with what is needed and what is held -when the balance cannot cover it, rather than depositing a fraction of what was -asked for. diff --git a/.changeset/recover-abandoned-swaps.md b/.changeset/recover-abandoned-swaps.md deleted file mode 100644 index aafea98..0000000 --- a/.changeset/recover-abandoned-swaps.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Recover abandoned swaps from chain, including their handles. - -`used_blinded_addresses` is written by `finalize_swap`, not by the claim — so an -identity the chain reports used with no claim naming it is a swap that landed and -was never collected, with its output still sitting in `swap_outputs`. Previously -those were reported as unreachable, on the grounds that a claim needs the whole -handle and only the process that made the swap held one. - -That was wrong. A swap request publishes almost everything a claim consumes: -`pool`, `zero_for_one`, `amount_in`, `amount_out_min`, `sqrt_price_limit`, -`nonce`, `deadline`, and both token ids are public inputs, and the swap id is a -public output. Multi-hop publishes its `SwapHop` structs the same way. The one -private piece is the blinding factor, and that is derived locally from the view -key and counter — which the store already holds. - -So `reconcileSwapHistory` now reads swap requests as well as claims in the same -walk, and rebuilds a claimable handle from each. It also records `soldAmountIn`, -the figure no claim reports: a claim says what came back, only the request says -what it cost. - -Verified by rebuilding a store from an empty file against 21 pages of testnet -history: 36 identities recovered, 32 settled, and four abandoned swaps rebuilt and -then claimed — 0.143939 USDCx and 4.068448 ALEO that had been sitting unclaimed, -two of them multi-hop. diff --git a/.changeset/remove-shield-wrappers.md b/.changeset/remove-shield-wrappers.md deleted file mode 100644 index 889868e..0000000 --- a/.changeset/remove-shield-wrappers.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Remove `SHIELD_WRAPPERS`, and with it a table that never had a caller. - -`SHIELD_WRAPPERS` named the three shield wrapper programs and the assets they -wrap. It shipped in 0.6.0 with testnet's underlyings hardcoded — `USDCx` mapped to -`test_usdcx_stablecoin.aleo` on every network, which is not the program that exists -on mainnet. The apparent fix was to split it per network, and the docblock claimed -the table was there because record selection needed an underlying program id before -any network round-trip. - -That claim was false. Nothing in the SDK read the table, at any commit since it was -introduced. Wrapped-ness and the underlying program come from the AMM's own -`from_wrapper_token_id` mapping via `resolveTokenRoute`, which is what `swap` and -`swapMultiHop` spend from; private balances come from the API registry's -`underlying_program`. Both are per network by construction and cannot name a -testnet program while pointing at mainnet. The table answered a question that was -already answered, and answered it from a hand-maintained copy that could drift. - -Callers wanting the underlying for a token id should read it the way the actions -do: - -```ts -const route = await client.resolveTokenRoute({ tokenId }) -if (route.wrapped) console.log(route.wrapperProgram, '→', route.underlyingProgram) -``` - -Removing rather than deprecating a published export is a break, and it is one on -purpose: a deprecation cycle would carry a symbol with no callers, whose only -tests asserted its literals against themselves, through another release. Mainnet -makes the drift concrete — mainnet runs two credits wrappers with confusable names, -`shield_swap_arc20_credits.aleo` (the one the AMM registers and every live pool -trades) and `arc20_wrapped_credits.aleo` (a bridge-family ARC-20 the AMM does not -know), and a curated list is exactly the artifact that gets that pair wrong. diff --git a/.changeset/rename-authenticate-api.md b/.changeset/rename-authenticate-api.md deleted file mode 100644 index c380a94..0000000 --- a/.changeset/rename-authenticate-api.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Rename the DEX authentication action to `authenticateShieldSwap`. - -`authenticateApi` did not say which API it signs into, and that became ambiguous -now that a client can also carry `authenticateProvableApi` from -`@provablehq/veil-aleo-sdk` — two auth actions on one client, one naming its -service and one not. The two are unrelated: this one signs a nonce with the -account and yields a DEX session; the other exchanges a consumer key for a JWT -covering delegated proving and record scanning. - -`authenticateApi` remains as a deprecated alias with identical behaviour and is -removed in the next major, so upgrading this minor breaks nothing. Both names -call the same function rather than one wrapping the other, so they cannot drift. diff --git a/.changeset/route-quote-decimals.md b/.changeset/route-quote-decimals.md deleted file mode 100644 index 05b439c..0000000 --- a/.changeset/route-quote-decimals.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Fix the units of the route quote, add `planSwap`, `parseUnits`, and `formatUnits`. - -`ApiClient.getRoute` typed `amount_in` as `bigint` and stringified it, implying the -raw base units every other amount in this SDK uses. The endpoint wants a decimal -string in the input token's units, and returns `estimated_amount_out` the same -way. Measured against testnet: `amount_in=0.5` quotes `0.000268655644950769` ETH, -while `amount_in=500000` — the base-unit form of the same half-token — quotes -`1.030419082712717843`, which is the pool's whole depth. - -That is expensive rather than merely wrong. A caller who follows the type builds a -slippage floor three orders of magnitude above any achievable fill, and the swap -reverts on finalize with the fee consumed. It cost exactly that to find. - -`amount_in` is now `string`, documented as the one place the API departs from base -units. The agent tool had the same defect twice over: its handler called `BigInt()` -on the value, which throws on `'0.5'`, and its schema told agents to pass "raw base -units (u128)" — the instruction that produces the revert. Both corrected. - -`parseUnits` and `formatUnits` convert either way, named after viem's helpers and -parsing on the string because a double cannot hold 18 significant decimals. - -`planSwap` turns "sell this for that" into an executable plan: the route from the -API, every hop's tradeability and liquidity checked on chain because the index can -list a pool the contract refuses to trade, the quote in base units, a slippage -floor, and the `imports` every hop needs — the thing callers most often get wrong -on multi-hop. A missing quote yields a zero floor and says so, rather than -inventing a guarantee. - -Verified live: 0.5 USDCx → 0.000268655644950769 ETH, claimed in the same run, the -received amount matching the quote exactly. diff --git a/.changeset/shield-swap-cli-package.md b/.changeset/shield-swap-cli-package.md deleted file mode 100644 index 1e95732..0000000 --- a/.changeset/shield-swap-cli-package.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@provablehq/shield-swap-cli': minor -'@provablehq/shield-swap-sdk': minor ---- - -Move the trader scripts out of `@provablehq/shield-swap-sdk` and into a new -`@provablehq/shield-swap-cli` package, which installs a `shield-swap` binary. - -The scripts previously shipped as raw TypeScript under `skills/scripts/` and ran -with `npx tsx` from inside `node_modules`. They are now subcommands — -`shield-swap setup`, `pools`, `balances`, `positions`, `swap`, `swap-concurrent`, -`history`, `mint`, `liquidity`, `collect`, `liquidity-e2e` — compiled and -typechecked like the rest of the workspace. `swap-history` is now `history`; every -other name is unchanged, as are all flags and the `--execute` and `--json` -contracts. - -The CLI is a separate install so a project that only needs the client does not -pull it in: `@provablehq/shield-swap-sdk` no longer ships `skills/scripts/`, and -its tarball carries only `dist` and the runbook markdown. - -Migrating: install `@provablehq/shield-swap-cli` and replace -`npx tsx node_modules/@provablehq/shield-swap-sdk/skills/scripts/.ts` with -`shield-swap ` (`npx shield-swap ` for a project-local install), and -import the session helpers from `@provablehq/shield-swap-cli/session` rather than by -path. Invoke the binary rather than the package: `npx @provablehq/shield-swap-cli` -resolves against the registry, so the version can change between two commands and -it needs a network. diff --git a/.changeset/swap-identity-tracking.md b/.changeset/swap-identity-tracking.md deleted file mode 100644 index 82fa494..0000000 --- a/.changeset/swap-identity-tracking.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Track blinded identities inside the swap actions when a store is configured. - -Reservation existed but had to be driven by hand — reserve, swap, record — and the -default path still derived identities by scanning the chain, which is safe in -sequence and reverts in parallel. `swap` and `swapMultiHop` now reserve before -submitting and record the resulting handle after, and `claimSwapOutput` marks the -identity claimed. Two concurrent `client.swap()` calls can no longer collide. - -Tracking follows the store. `shieldSwapActions` supplies an in-memory one when -none is configured, so a composed client is concurrency-safe out of the box — -without persistence, so a restart rescans the chain for its next counter and -forgets any unclaimed swap. Configure `fileBlindedIdentityStore` for anything -long-running. The standalone `swap(client, params)` tracks only when handed a -store, so its behaviour is unchanged from before. - -Two per-call opt-outs, and no boolean flag to contradict the config: pass -`blindedIdentity` to supply your own identity, or `blindedIdentities: undefined` to -skip tracking for that call. Wallet accounts are untouched either way, since they -derive identities the client never sees. - -Records now carry the whole handle, not just the swap id, because -`claimSwapOutput` consumes a handle. That makes crash recovery real: a process can -claim a swap it did not make. `SwapHandle` holds bigints and `JSON.stringify` -throws on those, so handles persist through an explicit shape with decimal strings -(`toPersistedHandle` / `fromPersistedHandle`) rather than a bigint reviver, which -cannot round-trip — a string field of digits would come back a bigint. -`recordBlindedSwap` accordingly takes `{ handle }` instead of -`{ blindedAddress, swapId }`. - -Two deliberately asymmetric failure policies. A store write that fails *after* a -swap lands throws `SwapRecordingError` with the handle attached: the swap -succeeded, so resubmitting would spend more input, but the swap id is knowable -only at that moment — nothing on chain links an identity to its swap until a claim -exists — so a swallowed failure means unclaimable proceeds. A store write that -fails after a *claim* warns and continues, because the funds have landed and -`reconcileSwapHistory` can repair the record. - -`getUnclaimedSwaps` summarizes what a store is still owed: one entry per output -still sitting in `swap_outputs`, per-token totals across both sides of every swap -(the output token plus any unfilled input a claim refunds), and a handle rebuilt -from the store so each entry can be claimed by a process that did not make the -swap. It reads the mapping rather than trusting stored statuses, so an entry -appears exactly when a claim would succeed. Identities the chain has consumed whose -swap id was never recorded are reported separately as `unresolvable`, since nothing -on chain locates their proceeds until a claim exists. diff --git a/.changeset/tick-hints-no-wasm.md b/.changeset/tick-hints-no-wasm.md deleted file mode 100644 index a85b201..0000000 --- a/.changeset/tick-hints-no-wasm.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': patch ---- - -Keep `pickInsertHint` working without the optional WASM peer. - -Walking the initialized-tick list reads the `ticks` mapping, which is keyed by a -hash of pool and tick — so it derives keys through `@provablehq/sdk`. `mint` calls -`pickInsertHint` whenever hints are omitted, and `mint` deliberately uses the soft -loader while `increaseLiquidity` never loads WASM at all, so making the hint walk -require the peer broke wallet-backed browser installs that previously minted fine. -That contradicted the design stated in `utils/sdk.ts`: read-only and wallet-backed -paths never touch WASM. - -An absent peer now falls back to the slot's neighbours — one mapping read keyed by -the pool, deriving nothing, and exactly what this returned before the walk existed. -Callers with the peer keep the correct predecessor for any target; callers without -it are no worse off than before. The fallback is best-effort, correct only for a -target within one initialized tick of the current price, so a wallet-backed caller -needing a distant range should pass `tickLowerHint` and `tickUpperHint` explicitly. diff --git a/.changeset/tick-insert-hints.md b/.changeset/tick-insert-hints.md deleted file mode 100644 index ef21707..0000000 --- a/.changeset/tick-insert-hints.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -'@provablehq/shield-swap-sdk': minor ---- - -Return the true predecessor from `pickInsertHint`, and export the tick-list sentinels. - -`pickInsertHint` read only `slot.next_init_below` / `next_init_above`, which -bracket the pool's *current* tick rather than the target. Any position bound -further out than one initialized tick therefore got a hint above itself, which the -contract rejects on finalize — the transaction is mined, reverts, and consumes the -fee. On a live ETH/USDCx pool at tick `-200996`, a lower bound of `-203230` -returned `-200996`; the correct predecessor is `-273894`. The docblock carried this -as a known limitation with an exact walk listed as a follow-up. This is that -follow-up: it now walks the initialized-tick list, which holds one entry per -initialized tick — 3 to 18 on live pools — so the added reads are few and bounded. - -`MIN_TICK_SENTINEL` and `MAX_TICK_SENTINEL` are now exported. The list is anchored -one step outside the usable range (`∓400_001`, against `MIN_TICK`/`MAX_TICK` of -`∓400_000`), and with no constant for it callers hardcoded `-400001` — as the -devnode lifecycle tests did, which works only for a pool whose tick list is still -empty. - -Verified against every live testnet pool: 30 hints across 5 pools, each confirmed -initialized, strictly below its target, and with its successor at or beyond the -target. diff --git a/packages/bridge/CHANGELOG.md b/packages/bridge/CHANGELOG.md index 4c6044a..dcc8853 100644 --- a/packages/bridge/CHANGELOG.md +++ b/packages/bridge/CHANGELOG.md @@ -1,5 +1,13 @@ # @provablehq/veil-aleo-bridges +## 0.4.3 + +### Patch Changes + +- Updated dependencies [e93d7a3] +- Updated dependencies [4be5291] + - @provablehq/veil-core@0.7.0 + ## 0.4.2 ### Patch Changes diff --git a/packages/bridge/package.json b/packages/bridge/package.json index ba52d05..3dff2cb 100644 --- a/packages/bridge/package.json +++ b/packages/bridge/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-aleo-bridges", - "version": "0.4.2", + "version": "0.4.3", "private": true, "description": "Veil client for swaps between Aleo and other chains (SOL, ETH, BTC, etc.).", "license": "MIT", diff --git a/packages/codegen/CHANGELOG.md b/packages/codegen/CHANGELOG.md index 3e4777e..ae8a333 100644 --- a/packages/codegen/CHANGELOG.md +++ b/packages/codegen/CHANGELOG.md @@ -1,5 +1,13 @@ # @provablehq/veil-codegen +## 0.7.0 + +### Patch Changes + +- Updated dependencies [e93d7a3] +- Updated dependencies [4be5291] + - @provablehq/veil-core@0.7.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/codegen/package.json b/packages/codegen/package.json index ab41a43..f8bc083 100644 --- a/packages/codegen/package.json +++ b/packages/codegen/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-codegen", - "version": "0.6.0", + "version": "0.7.0", "description": "Generates executable TypeScript contracts from Aleo program ABIs.", "license": "MIT", "repository": { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index b87e38b..e942b14 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,113 @@ # @provablehq/veil-core +## 0.7.0 + +### Minor Changes + +- e93d7a3: Shorten the confirmation window to one minute, and report what the polls saw. + + `waitForConfirmation` defaulted to 300 seconds. Measured against the live testnet + deployment, healthy confirmations land far inside that — a mint took 49.7s and an + increase 39s, both including proving — so a transaction still absent at the limit + is more often one the node never included than one about to arrive. The default is + now 60_000, and callers on a congested network or a slower path raise it per client. + + This is a behaviour change: a write that previously confirmed between one and five + minutes now throws `TransactionTimeoutError` instead of returning. Multi-hop swaps + are the known case — one was measured at 322 seconds — and a client submitting them + should set `confirmationTimeout` explicitly (around `400_000`) rather than take the + default. The shield-swap README and the `createProvingConfig` reference both say so + on the multi-hop path. + + The timeout error also reports what the polls observed. Every polling failure was + previously swallowed, so a node that answered cleanly and consistently did not have + the transaction was indistinguishable from one that could not be reached — and the + message asserted the transaction "may still be pending", which is exactly backwards + for a transaction that was dropped before inclusion. `TransactionTimeoutError` now + carries `polls` and `absentPolls`, and its message states which case it saw. It does + not diagnose why: the confirmed-transaction endpoint cannot tell a pending + transaction from a dropped one on its own, so the message reports the observation + and leaves the conclusion to the caller. + +- 4be5291: Add Provable API authentication to `@provablehq/veil-aleo-sdk`, and make `Client` carry the actions layered onto it. + + `createAleoClient` now builds a single Provable API session from its credential + options and shares it across delegated proving and record scanning, so one + credential mints one JWT rather than each service minting its own. The returned + wallet client carries `authenticateProvableApi()`, which resolves that session — + registering a consumer when none is configured — and reports the credentials, the + token expiry, whether a consumer was registered, and which paths the session + reaches. + + New in `@provablehq/veil-aleo-sdk`: + + - `registerProvableApi({ username })` — registers a consumer and returns its id + and API key. The key is issued once, so persist it. + - `createProvableSession({ credentials | store, username })` — a session that + caches its JWT, refreshes inside a five-minute expiry margin, and collapses + concurrent mints onto one request. + - `authenticateProvableApi(client, params?)` and `provableApiActions()` — the + action and its decorator. + - `ProvableCredentialStore`, with two implementations. `fileCredentialStore(path)` + from the new `@provablehq/veil-aleo-sdk/node` subpath persists to JSON at mode + `0600`, so a process registers on first run and reuses the consumer afterward; + it lives behind a subpath so `node:fs` never reaches a browser bundle. + `memoryCredentialStore()` holds credentials for the life of the process and is + the default when a client is given neither credentials nor a store, so delegated + proving works unconfigured — but a consumer registered there is lost at exit, + and the API issues each key once, so anything long-lived wants persistence. An + explicit `consumerId`/`apiKey` pair takes precedence over a store, so a rotated + key needs no state reset. + - `session` on `createProvingConfig`, `createRemoteScanner`, and + `createStandaloneScanner`, and `setSession` on the providers the first two + return. `consumerId` is now optional on both scanners — but required alongside + `apiKey` when no session supplies tokens, since a JWT is minted from the pair; + an incomplete pair throws at construction rather than 401ing on the first scan. + - `username` on `createAleoClient`, choosing the name a consumer is registered + under when one has to be. Used verbatim, so the consumer is identifiable; + defaults to a name derived from the account address plus a random suffix. + A taken name now fails with an error stating that credentials cannot be + recovered from a username — the API has no endpoint that reads a consumer back + and a duplicate registration returns nothing usable, so the stored key is the + only copy. + + The delegated-proving path also gains the 401 re-mint retry that only record + scanning had, and record scanning now replaces its token only when the token was + what the service rejected, rather than on every transient failure. + + **`proverUrl` is now a base URL, and defaults.** Pass + `https://api.provable.com/prove` and the active network is appended, mirroring + `createRemoteScanner`'s `url`. Omit it under `mode: 'delegated'` and it falls back + to the new `DEFAULT_PROVER_URL` export — `provingMode` already defaulted to + `'delegated'`, so a client built without a prover used to construct fine and then + fail on its first write. Local proving still resolves no endpoint. + + The base-URL shape is also a fix. Previously the network was baked into the value + the caller supplied, so `switchChain` left delegated proving pointed at the network + the client started from — and confirmation polling with it, since it read the + network the handle was loaded with rather than the one in force. Both now follow + the switch. A value that still carries a trailing `/mainnet` or `/testnet` is + re-targeted rather than doubled, so existing callers keep working, and + `ProvingConfig.url` reports the endpoint for the network currently in force rather + than echoing the input. + + **Scanner `url` is optional too**, defaulting to the new `DEFAULT_SCANNER_URL`. + It was `createRemoteScanner`'s only required field, so that factory now takes no + arguments at all, and `createStandaloneScanner` needs only a view key. Together + with the credential store's in-memory default, a delegated client and its scanner + are buildable from nothing but a private key and a node URL. + + In `@provablehq/veil-core`, `Client` takes an accumulating `extended` type + parameter, defaulting to `{}`, and `extend` returns + `Client` instead of `Client & extended`. Chained `extend` calls + previously dropped earlier layers from the type — a wallet client extended once + lost `writeContract` and `recordProvider` from its type, though not at runtime. + A decorator can now also build on the layer beneath it, and the new `Extended` + constraint stops a decorator from shadowing `request`, `transport`, or `uid`. + `PublicClient`, `WalletClient`, `TestClient`, and `BridgeClient` are expressed + through the parameter. Existing code needs no change: the parameter's default + makes a bare `Client` mean what it always did. + ## 0.6.0 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index 9529fae..dcda541 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-core", - "version": "0.6.0", + "version": "0.7.0", "description": "Viem-style TypeScript interface for Aleo.", "license": "MIT", "repository": { diff --git a/packages/core/src/version.ts b/packages/core/src/version.ts index e67ca42..7b14072 100644 --- a/packages/core/src/version.ts +++ b/packages/core/src/version.ts @@ -13,4 +13,4 @@ * clientHeader: `my-dapp/1.2 veil-core/${version}`, * }) */ -export const version = '0.6.0' +export const version = '0.7.0' diff --git a/packages/devnode/CHANGELOG.md b/packages/devnode/CHANGELOG.md index 8724648..2653199 100644 --- a/packages/devnode/CHANGELOG.md +++ b/packages/devnode/CHANGELOG.md @@ -1,5 +1,23 @@ # @provablehq/veil-aleo-devnode +## 0.7.0 + +### Minor Changes + +- cda4f20: Bump `@provablehq/sdk` to `^0.11.6`. + + 0.11.6 adds a consensus version, so the devnode height lists grow from 17 + entries to 18. Both must match the SDK's count exactly and mirror each other — + `DEVNODE_CONSENSUS_HEIGHTS` in `@provablehq/veil-aleo-sdk` and the + `CONSENSUS_VERSION_HEIGHTS` default in `@provablehq/veil-aleo-devnode`. A short + list panics with an opaque wasm `unreachable`. + + The `aleo-devnode` binary now comes from the `@provablehq/aleo-devnode` npm + package rather than a GitHub release, so `pnpm install` provides it and the + version is pinned in `package.json` like any other dependency. `startDevnode` + still resolves it from `PATH` and still accepts `devnodePath`, so nothing + changes for a consumer pointing at their own build. + ## 0.6.0 ### Patch Changes diff --git a/packages/devnode/package.json b/packages/devnode/package.json index fcf159f..93a85a4 100644 --- a/packages/devnode/package.json +++ b/packages/devnode/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-aleo-devnode", - "version": "0.6.0", + "version": "0.7.0", "description": "TypeScript interface for orchestrating local Aleo test networks for testing & developing Aleo programs.", "license": "MIT", "repository": { diff --git a/packages/leo/CHANGELOG.md b/packages/leo/CHANGELOG.md index 544bb03..0accf48 100644 --- a/packages/leo/CHANGELOG.md +++ b/packages/leo/CHANGELOG.md @@ -1,5 +1,7 @@ # @provablehq/veil-leo +## 0.7.0 + ## 0.6.0 ## 0.5.0 diff --git a/packages/leo/package.json b/packages/leo/package.json index 1063d93..f2a8714 100644 --- a/packages/leo/package.json +++ b/packages/leo/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-leo", - "version": "0.6.0", + "version": "0.7.0", "description": "TypeScript interface for using the Leo CLI from TS/JS.", "license": "MIT", "repository": { diff --git a/packages/provable-sdk/CHANGELOG.md b/packages/provable-sdk/CHANGELOG.md index 6390069..633928a 100644 --- a/packages/provable-sdk/CHANGELOG.md +++ b/packages/provable-sdk/CHANGELOG.md @@ -1,5 +1,135 @@ # @provablehq/veil-aleo-sdk +## 0.7.0 + +### Minor Changes + +- cda4f20: Bump `@provablehq/sdk` to `^0.11.6`. + + 0.11.6 adds a consensus version, so the devnode height lists grow from 17 + entries to 18. Both must match the SDK's count exactly and mirror each other — + `DEVNODE_CONSENSUS_HEIGHTS` in `@provablehq/veil-aleo-sdk` and the + `CONSENSUS_VERSION_HEIGHTS` default in `@provablehq/veil-aleo-devnode`. A short + list panics with an opaque wasm `unreachable`. + + The `aleo-devnode` binary now comes from the `@provablehq/aleo-devnode` npm + package rather than a GitHub release, so `pnpm install` provides it and the + version is pinned in `package.json` like any other dependency. `startDevnode` + still resolves it from `PATH` and still accepts `devnodePath`, so nothing + changes for a consumer pointing at their own build. + +- e93d7a3: Expose `confirmationTimeout` on `createAleoClient`. + + `createProvingConfig` accepted it but `createAleoClient` did not forward it, so a + caller using the convenience factory was fixed at the default and had to compose the + proving config by hand to change it. Multi-hop swaps exceed that — one + measured at 322 seconds against a 300-second limit, surfacing as a timeout on a + transaction that was still pending and would confirm. + +- e93d7a3: Shorten the confirmation window to one minute, and report what the polls saw. + + `waitForConfirmation` defaulted to 300 seconds. Measured against the live testnet + deployment, healthy confirmations land far inside that — a mint took 49.7s and an + increase 39s, both including proving — so a transaction still absent at the limit + is more often one the node never included than one about to arrive. The default is + now 60_000, and callers on a congested network or a slower path raise it per client. + + This is a behaviour change: a write that previously confirmed between one and five + minutes now throws `TransactionTimeoutError` instead of returning. Multi-hop swaps + are the known case — one was measured at 322 seconds — and a client submitting them + should set `confirmationTimeout` explicitly (around `400_000`) rather than take the + default. The shield-swap README and the `createProvingConfig` reference both say so + on the multi-hop path. + + The timeout error also reports what the polls observed. Every polling failure was + previously swallowed, so a node that answered cleanly and consistently did not have + the transaction was indistinguishable from one that could not be reached — and the + message asserted the transaction "may still be pending", which is exactly backwards + for a transaction that was dropped before inclusion. `TransactionTimeoutError` now + carries `polls` and `absentPolls`, and its message states which case it saw. It does + not diagnose why: the confirmed-transaction endpoint cannot tell a pending + transaction from a dropped one on its own, so the message reports the observation + and leaves the conclusion to the caller. + +- 4be5291: Add Provable API authentication to `@provablehq/veil-aleo-sdk`, and make `Client` carry the actions layered onto it. + + `createAleoClient` now builds a single Provable API session from its credential + options and shares it across delegated proving and record scanning, so one + credential mints one JWT rather than each service minting its own. The returned + wallet client carries `authenticateProvableApi()`, which resolves that session — + registering a consumer when none is configured — and reports the credentials, the + token expiry, whether a consumer was registered, and which paths the session + reaches. + + New in `@provablehq/veil-aleo-sdk`: + + - `registerProvableApi({ username })` — registers a consumer and returns its id + and API key. The key is issued once, so persist it. + - `createProvableSession({ credentials | store, username })` — a session that + caches its JWT, refreshes inside a five-minute expiry margin, and collapses + concurrent mints onto one request. + - `authenticateProvableApi(client, params?)` and `provableApiActions()` — the + action and its decorator. + - `ProvableCredentialStore`, with two implementations. `fileCredentialStore(path)` + from the new `@provablehq/veil-aleo-sdk/node` subpath persists to JSON at mode + `0600`, so a process registers on first run and reuses the consumer afterward; + it lives behind a subpath so `node:fs` never reaches a browser bundle. + `memoryCredentialStore()` holds credentials for the life of the process and is + the default when a client is given neither credentials nor a store, so delegated + proving works unconfigured — but a consumer registered there is lost at exit, + and the API issues each key once, so anything long-lived wants persistence. An + explicit `consumerId`/`apiKey` pair takes precedence over a store, so a rotated + key needs no state reset. + - `session` on `createProvingConfig`, `createRemoteScanner`, and + `createStandaloneScanner`, and `setSession` on the providers the first two + return. `consumerId` is now optional on both scanners — but required alongside + `apiKey` when no session supplies tokens, since a JWT is minted from the pair; + an incomplete pair throws at construction rather than 401ing on the first scan. + - `username` on `createAleoClient`, choosing the name a consumer is registered + under when one has to be. Used verbatim, so the consumer is identifiable; + defaults to a name derived from the account address plus a random suffix. + A taken name now fails with an error stating that credentials cannot be + recovered from a username — the API has no endpoint that reads a consumer back + and a duplicate registration returns nothing usable, so the stored key is the + only copy. + + The delegated-proving path also gains the 401 re-mint retry that only record + scanning had, and record scanning now replaces its token only when the token was + what the service rejected, rather than on every transient failure. + + **`proverUrl` is now a base URL, and defaults.** Pass + `https://api.provable.com/prove` and the active network is appended, mirroring + `createRemoteScanner`'s `url`. Omit it under `mode: 'delegated'` and it falls back + to the new `DEFAULT_PROVER_URL` export — `provingMode` already defaulted to + `'delegated'`, so a client built without a prover used to construct fine and then + fail on its first write. Local proving still resolves no endpoint. + + The base-URL shape is also a fix. Previously the network was baked into the value + the caller supplied, so `switchChain` left delegated proving pointed at the network + the client started from — and confirmation polling with it, since it read the + network the handle was loaded with rather than the one in force. Both now follow + the switch. A value that still carries a trailing `/mainnet` or `/testnet` is + re-targeted rather than doubled, so existing callers keep working, and + `ProvingConfig.url` reports the endpoint for the network currently in force rather + than echoing the input. + + **Scanner `url` is optional too**, defaulting to the new `DEFAULT_SCANNER_URL`. + It was `createRemoteScanner`'s only required field, so that factory now takes no + arguments at all, and `createStandaloneScanner` needs only a view key. Together + with the credential store's in-memory default, a delegated client and its scanner + are buildable from nothing but a private key and a node URL. + + In `@provablehq/veil-core`, `Client` takes an accumulating `extended` type + parameter, defaulting to `{}`, and `extend` returns + `Client` instead of `Client & extended`. Chained `extend` calls + previously dropped earlier layers from the type — a wallet client extended once + lost `writeContract` and `recordProvider` from its type, though not at runtime. + A decorator can now also build on the layer beneath it, and the new `Extended` + constraint stops a decorator from shadowing `request`, `transport`, or `uid`. + `PublicClient`, `WalletClient`, `TestClient`, and `BridgeClient` are expressed + through the parameter. Existing code needs no change: the parameter's default + makes a bare `Client` mean what it always did. + ## 0.6.0 ### Patch Changes diff --git a/packages/provable-sdk/package.json b/packages/provable-sdk/package.json index aa0f384..494a9aa 100644 --- a/packages/provable-sdk/package.json +++ b/packages/provable-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-aleo-sdk", - "version": "0.6.0", + "version": "0.7.0", "description": "Local signing and proving for the Veil Aleo SDK, backed by the Provable SDK.", "license": "MIT", "repository": { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index c7a5529..2f47615 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -1,5 +1,14 @@ # @provablehq/veil-aleo-react-hooks +## 0.7.0 + +### Patch Changes + +- Updated dependencies [e93d7a3] +- Updated dependencies [4be5291] + - @provablehq/veil-core@0.7.0 + - @provablehq/veil-aleo-wallet-adapter@0.7.0 + ## 0.6.0 ### Patch Changes diff --git a/packages/react/package.json b/packages/react/package.json index 3f5c63e..99aacfa 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-aleo-react-hooks", - "version": "0.6.0", + "version": "0.7.0", "description": "React hooks and providers for the building web apps.", "license": "MIT", "repository": { diff --git a/packages/shield-swap-cli/CHANGELOG.md b/packages/shield-swap-cli/CHANGELOG.md new file mode 100644 index 0000000..387a964 --- /dev/null +++ b/packages/shield-swap-cli/CHANGELOG.md @@ -0,0 +1,53 @@ +# @provablehq/shield-swap-cli + +## 0.7.0 + +### Minor Changes + +- cda4f20: Move the trader scripts out of `@provablehq/shield-swap-sdk` and into a new + `@provablehq/shield-swap-cli` package, which installs a `shield-swap` binary. + + The scripts previously shipped as raw TypeScript under `skills/scripts/` and ran + with `npx tsx` from inside `node_modules`. They are now subcommands — + `shield-swap setup`, `pools`, `balances`, `positions`, `swap`, `swap-concurrent`, + `history`, `mint`, `liquidity`, `collect`, `liquidity-e2e` — compiled and + typechecked like the rest of the workspace. `swap-history` is now `history`; every + other name is unchanged, as are all flags and the `--execute` and `--json` + contracts. + + The CLI is a separate install so a project that only needs the client does not + pull it in: `@provablehq/shield-swap-sdk` no longer ships `skills/scripts/`, and + its tarball carries only `dist` and the runbook markdown. + + Migrating: install `@provablehq/shield-swap-cli` and replace + `npx tsx node_modules/@provablehq/shield-swap-sdk/skills/scripts/.ts` with + `shield-swap ` (`npx shield-swap ` for a project-local install), and + import the session helpers from `@provablehq/shield-swap-cli/session` rather than by + path. Invoke the binary rather than the package: `npx @provablehq/shield-swap-cli` + resolves against the registry, so the version can change between two commands and + it needs a network. + +### Patch Changes + +- Updated dependencies [c2124ee] +- Updated dependencies [cda4f20] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] +- Updated dependencies [cda4f20] +- Updated dependencies [4be5291] +- Updated dependencies [cda4f20] +- Updated dependencies [cda4f20] +- Updated dependencies [cda4f20] +- Updated dependencies [4be5291] +- Updated dependencies [cda4f20] +- Updated dependencies [cda4f20] +- Updated dependencies [c2124ee] +- Updated dependencies [e93d7a3] +- Updated dependencies [e93d7a3] + - @provablehq/shield-swap-sdk@0.7.0 + - @provablehq/veil-aleo-sdk@0.7.0 diff --git a/packages/shield-swap-cli/package.json b/packages/shield-swap-cli/package.json index e68da1e..e323fc8 100644 --- a/packages/shield-swap-cli/package.json +++ b/packages/shield-swap-cli/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/shield-swap-cli", - "version": "0.6.0", + "version": "0.7.0", "description": "Command line trader for the Shield Swap AMM DEX on Aleo.", "license": "MIT", "repository": { diff --git a/packages/shield-swap/CHANGELOG.md b/packages/shield-swap/CHANGELOG.md index 3c49dcb..1f8fbda 100644 --- a/packages/shield-swap/CHANGELOG.md +++ b/packages/shield-swap/CHANGELOG.md @@ -1,5 +1,462 @@ # @provablehq/shield-swap-sdk +## 0.7.0 + +### Minor Changes + +- c2124ee: Reserve blinded identities through a store, and expose `resolveDexImports` as an action. + + Swaps that ran in parallel from one local account reverted on finalize. A swap is + bound to a blinded identity, and the program asserts each blinded address appears + in `used_blinded_addresses` only once. With no `blindedIdentity` passed, `swap` and + `swapMultiHop` called `nextBlindedIdentity`, which scans for the first counter the + chain does not carry — correct in sequence, wrong in parallel. Two concurrent swaps + read the same unused counter and the second reverted, with nothing to see locally + because at proving time the address genuinely was unused. Disjoint input tokens did + not help: the identity is per account, not per token. + + `reserveBlindedIdentity` closes the window by recording a reservation before + returning it, and never issuing a counter at or below one already stored — so an + unconfirmed swap still holds its counter. It moves monotonically from the highest + known counter, and skips any address the chain already carries, which recovers a + store another process has moved past. An empty store scans from 0, so a lost store + costs reads rather than correctness. Local accounts only: a wallet derives and + tracks its own identities. + + Reservations persist through a `BlindedIdentityStore`. + `memoryBlindedIdentityStore` is the default — enough to keep one process's + concurrent swaps apart — and `fileBlindedIdentityStore` on the new + `@provablehq/shield-swap-sdk/node` entry point persists them across restarts, which + is what a bot or a test suite wants. Configure either with + `shieldSwapActions({ blindedIdentities })`. + + `recordBlindedSwap` attaches a swap id to a reservation, and + `syncBlindedIdentities` reconciles the store against the chain: `reserved` until + the address appears on chain, then `swapped` while its output is unclaimed and + `claimed` once the claim consumes it. That makes proceeds recoverable after a + crash — an identity is otherwise unrecoverable, since it is derived rather than + recorded anywhere the account can see. + + `resolveDexImports` is now on the client as `client.resolveDexImports()` alongside + the standalone export, which is unchanged. Every write needs its result and it + already took `(client, params)`, so the action form removes an import for callers + who have a composed client. + + `reconcileSwapHistory` recovers a store's past. Blinded identities are derived + rather than recorded, and a claim deletes the `swap_outputs` entry it settles, so + the `claim_swap_output` call is the only public trace tying an identity to its + swap — its inputs carry the blinded address, swap id, token pair, and amounts. The + action walks that history through `getProgramCallsPaginated` and `getTransaction`, + marks matched identities `claimed`, and returns what it found. It stops as soon as + every identity is accounted for, so a current store costs one page, and reports + `complete: false` when it hit `maxPages` with history left. Recommended once when + adopting a store for an account that already has history; `syncBlindedIdentities` + remains the cheap call for routine use. It cannot surface unclaimed swaps, which + by definition have no claim call. + + Verified against live testnet: seeded with a blinded address from a real claim, it + recovered the swap id, both token ids, and the amounts in two pages, and the + recovered id reads `null` from `swap_outputs` — which is what a settled claim + should look like. + +- cda4f20: Bump `@provablehq/sdk` to `^0.11.6`. + + 0.11.6 adds a consensus version, so the devnode height lists grow from 17 + entries to 18. Both must match the SDK's count exactly and mirror each other — + `DEVNODE_CONSENSUS_HEIGHTS` in `@provablehq/veil-aleo-sdk` and the + `CONSENSUS_VERSION_HEIGHTS` default in `@provablehq/veil-aleo-devnode`. A short + list panics with an opaque wasm `unreachable`. + + The `aleo-devnode` binary now comes from the `@provablehq/aleo-devnode` npm + package rather than a GitHub release, so `pnpm install` provides it and the + version is pinned in `package.json` like any other dependency. `startDevnode` + still resolves it from `PATH` and still accepts `devnodePath`, so nothing + changes for a consumer pointing at their own build. + +- e93d7a3: Derive the DEX API host from the client's network. + + `DEFAULT_API_URL` shipped as `amm-api.dev.provable.com`, which indexes the + pre-migration `shield_swap_v3.aleo`. Since #110 moved this SDK to + `shield_swap.aleo`, that host serves pools which do not exist on the program the + SDK reads and proves against — so pool discovery returned keys and every chain + read of them came back `null`, surfacing as "pool does not exist" rather than as a + misconfigured URL. + + The API is deployed per-network on separate hosts, so a single constant cannot be + right for both. `shieldSwapActions` now derives it from the client's network — + `mainnet` to `api.swap.shield.fi`, otherwise `api.testnet.swap.shield.fi` — and an + explicit `api.baseUrl` still wins. `SHIELD_SWAP_API_URLS` and `defaultApiUrl()` + are exported for callers constructing an `ApiClient` directly. + + The host resolves per request rather than at construction, so `switchChain` + re-targets the API instead of leaving it on the network the client started from. + `ApiClientOptions.baseUrl` accordingly accepts `string | (() => string)`, and + `ApiClient.baseUrl` becomes a getter — still a readable string. + + `DEFAULT_API_URL` is deprecated and now points at the testnet host. It is removed + in the next major; a caller who needs a specific network should use + `defaultApiUrl(network)`. + + Three integration suites defaulted to `amm-api-staging.dev.provable.com`, which + now returns 404 for everything. They default to the testnet host instead — with it, + 35 previously-failing live tests pass, including the route-quote test recorded as + known-red. + +- e93d7a3: Derive insert hints from the DEX API when the WASM peer is unavailable. + + `pickInsertHint` walks the contract's initialized-tick list, which needs + `@provablehq/sdk` to hash each tick key. Without the peer it fell back to the + slot's two neighbours — correct only for a target within one initialized tick of + the current price, and wrong for anything further out, which finalize rejects at + the caller's expense. + + The API already answers this exactly. `GET /pools/{key}/initialized-ticks` returns + the pool's full sorted tick list, and its own description names the purpose: + computing `tick_lower_hint` / `tick_upper_hint` for the AMM's hint-walk asserts. + It is now exposed as `client.api.getInitializedTicks(poolKey)`, and + `shieldSwapActions` supplies it to `pickInsertHint`, `mint`, and + `increaseLiquidity` automatically — so a wallet-backed client with no WASM gets + the exact predecessor instead of a guess. Verified against three live testnet + pools: the API-derived predecessor matched the chain walk on every one. + + Three sources now, in descending order of authority: the contract's own list + whenever the peer is present, the API list when it is not, and the slot's + neighbours only when neither is available. The chain stays preferred because the + API list is indexed from positions rather than read from the contract, so it can + lag a position minted moments ago — and a stale hint costs a fee. A failing or + unauthenticated API drops to the slot rather than failing the write. + + `mint` and `increaseLiquidity` accept `initializedTicks` for callers driving them + outside the decorator. + +- e93d7a3: Add `liquidityForAmounts`, the deposit-side inverse of `amountsForLiquidity`. + + The package could turn a liquidity figure into token amounts but not the reverse, + which is the direction a depositor starts from: a caller holds two balances and + wants to know what position they support. Without it, every caller had to invent a + liquidity number and work forwards, and a figure that balances at one pool's price + falls short at another — one side runs out and the mint reverts. + + `liquidityForAmounts` mirrors the contract's own derivation: at or below the range + token0 binds, at or above it token1, and inside the range the shorter side governs, + with the same branch boundaries as `amountsForLiquidity` (`price <= lower` counts as + below). Every step floors, so the result is a lower bound — feeding it back through + `amountsForLiquidity` with deposit-side rounding returns amounts that fit inside the + originals, which is what keeps a mint from reverting for want of a base unit. That + property is asserted across a sweep of ticks, range widths, and magnitudes rather + than on a single case. It returns 0 when the amounts are dust for the range's width. + +- cda4f20: Add `previewMint`, which answers what a mint would open before anything is signed. + + Everything needed to plan a deposit was already exported, but assembling it was + left to the caller: read the slot, floor both bounds onto the pool's tick spacing, + price them with `getSqrtPriceAtTickX128`, ask `liquidityForAmounts` what the + budget backs, then run it back through `amountsForLiquidity` with deposit-side + rounding to learn what the mint actually consumes. Six steps in a fixed order, + where getting the rounding direction wrong on the last one costs a reverted + transaction, and skipping the alignment on the second produces bounds the contract + rejects outright. + + `previewMint(client, params)` composes exactly those primitives — it introduces no + new math — and returns the aligned bounds, the resulting liquidity, the amounts + each side gives up, and the pool state they were derived from. The range comes + either from explicit ticks or from `rangePercent`, a half-width in percent of the + pool's current price that defaults to 5, so a caller who thinks in "±5% around the + market" does not have to convert to ticks. Bounds are reported after alignment, + because that is the range the mint opens. + + Two things it reports that a caller would otherwise have to know to look for: + `inRange`, since a position outside the active tick earns nothing and is funded + from one side only, and `feeTierSpacing`, the spacing the `fee_to_tick_spacing` + registry binds to the pool's fee — equal to the pool's own on a healthy pool, and + a signal that the pool has drifted from its fee tier when it is not. The pool's + spacing governs either way, because that is what `mint` aligns against. + + `liquidity` of 0 is a result, not an error: the budget backs nothing over that + range, so a mint would cost a fee and open nothing. + +- cda4f20: Give the Q128 position math options objects, and add `liquidityForAmount`. + + The math helpers took their arguments positionally, and the arguments are mostly + same-typed bigints: `amountsForLiquidity(sqrtPrice, sqrtA, sqrtB, liquidity, +roundUp)`. Swapping the price for a bound type-checks and returns a plausible + wrong answer — a position reported as one-sided when it straddles the price, or a + deposit sized against the wrong end of its range. Nothing catches it. + + They now take objects with named fields, matching `feeGrowthInside`, which was + already shaped that way, and the viem convention these packages otherwise follow: + positional for one or two obvious arguments, an options object as soon as the + arguments are confusable. + + ```ts + const range = { + sqrtPriceX128: slot.sqrt_price, + sqrtLowerX128: getSqrtPriceAtTickX128(tickLower), + sqrtUpperX128: getSqrtPriceAtTickX128(tickUpper), + }; + const liquidity = liquidityForAmounts({ ...range, amount0, amount1 }); + const amounts = amountsForLiquidity({ ...range, liquidity, roundUp: true }); + ``` + + Nothing breaks yet. `amountsForLiquidity`, `amount0DeltaX128`, `amount1DeltaX128` + and `feeOwed` shipped in 0.6.0, so each keeps its positional form as a deprecated + overload returning identical numbers, removed in the next major; a test asserts + the two shapes agree, including the wrapping path in `feeOwed` where transposing + the growth figures is the specific mistake the object form prevents. + `liquidityForAmounts` was never released and takes the object form only. + + Also adds `liquidityForAmount`, which answers what ONE side alone supports. + `liquidityForAmounts` takes two ceilings and lets the shorter one govern, which is + right for "deposit what I have" and wrong for "deposit exactly this much of one + token" — there, a short balance on the other side silently shrinks the position + instead of reporting that it cannot be funded. Pair it with `amountsForLiquidity` + to get the other side's minimum. It returns `0` when the price puts the named side + out of use — above a range a position holds only token1, so token0 funds nothing — + which is a different condition from "deposit more" and worth distinguishing. + + `liquidity.ts --increase` uses it: naming one amount now derives the other as the + minimum that must accompany it, and fails with what is needed and what is held + when the balance cannot cover it, rather than depositing a fraction of what was + asked for. + +- cda4f20: Recover abandoned swaps from chain, including their handles. + + `used_blinded_addresses` is written by `finalize_swap`, not by the claim — so an + identity the chain reports used with no claim naming it is a swap that landed and + was never collected, with its output still sitting in `swap_outputs`. Previously + those were reported as unreachable, on the grounds that a claim needs the whole + handle and only the process that made the swap held one. + + That was wrong. A swap request publishes almost everything a claim consumes: + `pool`, `zero_for_one`, `amount_in`, `amount_out_min`, `sqrt_price_limit`, + `nonce`, `deadline`, and both token ids are public inputs, and the swap id is a + public output. Multi-hop publishes its `SwapHop` structs the same way. The one + private piece is the blinding factor, and that is derived locally from the view + key and counter — which the store already holds. + + So `reconcileSwapHistory` now reads swap requests as well as claims in the same + walk, and rebuilds a claimable handle from each. It also records `soldAmountIn`, + the figure no claim reports: a claim says what came back, only the request says + what it cost. + + Verified by rebuilding a store from an empty file against 21 pages of testnet + history: 36 identities recovered, 32 settled, and four abandoned swaps rebuilt and + then claimed — 0.143939 USDCx and 4.068448 ALEO that had been sitting unclaimed, + two of them multi-hop. + +- cda4f20: Remove `SHIELD_WRAPPERS`, and with it a table that never had a caller. + + `SHIELD_WRAPPERS` named the three shield wrapper programs and the assets they + wrap. It shipped in 0.6.0 with testnet's underlyings hardcoded — `USDCx` mapped to + `test_usdcx_stablecoin.aleo` on every network, which is not the program that exists + on mainnet. The apparent fix was to split it per network, and the docblock claimed + the table was there because record selection needed an underlying program id before + any network round-trip. + + That claim was false. Nothing in the SDK read the table, at any commit since it was + introduced. Wrapped-ness and the underlying program come from the AMM's own + `from_wrapper_token_id` mapping via `resolveTokenRoute`, which is what `swap` and + `swapMultiHop` spend from; private balances come from the API registry's + `underlying_program`. Both are per network by construction and cannot name a + testnet program while pointing at mainnet. The table answered a question that was + already answered, and answered it from a hand-maintained copy that could drift. + + Callers wanting the underlying for a token id should read it the way the actions + do: + + ```ts + const route = await client.resolveTokenRoute({ tokenId }); + if (route.wrapped) + console.log(route.wrapperProgram, "→", route.underlyingProgram); + ``` + + Removing rather than deprecating a published export is a break, and it is one on + purpose: a deprecation cycle would carry a symbol with no callers, whose only + tests asserted its literals against themselves, through another release. Mainnet + makes the drift concrete — mainnet runs two credits wrappers with confusable names, + `shield_swap_arc20_credits.aleo` (the one the AMM registers and every live pool + trades) and `arc20_wrapped_credits.aleo` (a bridge-family ARC-20 the AMM does not + know), and a curated list is exactly the artifact that gets that pair wrong. + +- 4be5291: Rename the DEX authentication action to `authenticateShieldSwap`. + + `authenticateApi` did not say which API it signs into, and that became ambiguous + now that a client can also carry `authenticateProvableApi` from + `@provablehq/veil-aleo-sdk` — two auth actions on one client, one naming its + service and one not. The two are unrelated: this one signs a nonce with the + account and yields a DEX session; the other exchanges a consumer key for a JWT + covering delegated proving and record scanning. + + `authenticateApi` remains as a deprecated alias with identical behaviour and is + removed in the next major, so upgrading this minor breaks nothing. Both names + call the same function rather than one wrapping the other, so they cannot drift. + +- cda4f20: Fix the units of the route quote, add `planSwap`, `parseUnits`, and `formatUnits`. + + `ApiClient.getRoute` typed `amount_in` as `bigint` and stringified it, implying the + raw base units every other amount in this SDK uses. The endpoint wants a decimal + string in the input token's units, and returns `estimated_amount_out` the same + way. Measured against testnet: `amount_in=0.5` quotes `0.000268655644950769` ETH, + while `amount_in=500000` — the base-unit form of the same half-token — quotes + `1.030419082712717843`, which is the pool's whole depth. + + That is expensive rather than merely wrong. A caller who follows the type builds a + slippage floor three orders of magnitude above any achievable fill, and the swap + reverts on finalize with the fee consumed. It cost exactly that to find. + + `amount_in` is now `string`, documented as the one place the API departs from base + units. The agent tool had the same defect twice over: its handler called `BigInt()` + on the value, which throws on `'0.5'`, and its schema told agents to pass "raw base + units (u128)" — the instruction that produces the revert. Both corrected. + + `parseUnits` and `formatUnits` convert either way, named after viem's helpers and + parsing on the string because a double cannot hold 18 significant decimals. + + `planSwap` turns "sell this for that" into an executable plan: the route from the + API, every hop's tradeability and liquidity checked on chain because the index can + list a pool the contract refuses to trade, the quote in base units, a slippage + floor, and the `imports` every hop needs — the thing callers most often get wrong + on multi-hop. A missing quote yields a zero floor and says so, rather than + inventing a guarantee. + + Verified live: 0.5 USDCx → 0.000268655644950769 ETH, claimed in the same run, the + received amount matching the quote exactly. + +- cda4f20: Move the trader scripts out of `@provablehq/shield-swap-sdk` and into a new + `@provablehq/shield-swap-cli` package, which installs a `shield-swap` binary. + + The scripts previously shipped as raw TypeScript under `skills/scripts/` and ran + with `npx tsx` from inside `node_modules`. They are now subcommands — + `shield-swap setup`, `pools`, `balances`, `positions`, `swap`, `swap-concurrent`, + `history`, `mint`, `liquidity`, `collect`, `liquidity-e2e` — compiled and + typechecked like the rest of the workspace. `swap-history` is now `history`; every + other name is unchanged, as are all flags and the `--execute` and `--json` + contracts. + + The CLI is a separate install so a project that only needs the client does not + pull it in: `@provablehq/shield-swap-sdk` no longer ships `skills/scripts/`, and + its tarball carries only `dist` and the runbook markdown. + + Migrating: install `@provablehq/shield-swap-cli` and replace + `npx tsx node_modules/@provablehq/shield-swap-sdk/skills/scripts/.ts` with + `shield-swap ` (`npx shield-swap ` for a project-local install), and + import the session helpers from `@provablehq/shield-swap-cli/session` rather than by + path. Invoke the binary rather than the package: `npx @provablehq/shield-swap-cli` + resolves against the registry, so the version can change between two commands and + it needs a network. + +- c2124ee: Track blinded identities inside the swap actions when a store is configured. + + Reservation existed but had to be driven by hand — reserve, swap, record — and the + default path still derived identities by scanning the chain, which is safe in + sequence and reverts in parallel. `swap` and `swapMultiHop` now reserve before + submitting and record the resulting handle after, and `claimSwapOutput` marks the + identity claimed. Two concurrent `client.swap()` calls can no longer collide. + + Tracking follows the store. `shieldSwapActions` supplies an in-memory one when + none is configured, so a composed client is concurrency-safe out of the box — + without persistence, so a restart rescans the chain for its next counter and + forgets any unclaimed swap. Configure `fileBlindedIdentityStore` for anything + long-running. The standalone `swap(client, params)` tracks only when handed a + store, so its behaviour is unchanged from before. + + Two per-call opt-outs, and no boolean flag to contradict the config: pass + `blindedIdentity` to supply your own identity, or `blindedIdentities: undefined` to + skip tracking for that call. Wallet accounts are untouched either way, since they + derive identities the client never sees. + + Records now carry the whole handle, not just the swap id, because + `claimSwapOutput` consumes a handle. That makes crash recovery real: a process can + claim a swap it did not make. `SwapHandle` holds bigints and `JSON.stringify` + throws on those, so handles persist through an explicit shape with decimal strings + (`toPersistedHandle` / `fromPersistedHandle`) rather than a bigint reviver, which + cannot round-trip — a string field of digits would come back a bigint. + `recordBlindedSwap` accordingly takes `{ handle }` instead of + `{ blindedAddress, swapId }`. + + Two deliberately asymmetric failure policies. A store write that fails _after_ a + swap lands throws `SwapRecordingError` with the handle attached: the swap + succeeded, so resubmitting would spend more input, but the swap id is knowable + only at that moment — nothing on chain links an identity to its swap until a claim + exists — so a swallowed failure means unclaimable proceeds. A store write that + fails after a _claim_ warns and continues, because the funds have landed and + `reconcileSwapHistory` can repair the record. + + `getUnclaimedSwaps` summarizes what a store is still owed: one entry per output + still sitting in `swap_outputs`, per-token totals across both sides of every swap + (the output token plus any unfilled input a claim refunds), and a handle rebuilt + from the store so each entry can be claimed by a process that did not make the + swap. It reads the mapping rather than trusting stored statuses, so an entry + appears exactly when a claim would succeed. Identities the chain has consumed whose + swap id was never recorded are reported separately as `unresolvable`, since nothing + on chain locates their proceeds until a claim exists. + +- e93d7a3: Return the true predecessor from `pickInsertHint`, and export the tick-list sentinels. + + `pickInsertHint` read only `slot.next_init_below` / `next_init_above`, which + bracket the pool's _current_ tick rather than the target. Any position bound + further out than one initialized tick therefore got a hint above itself, which the + contract rejects on finalize — the transaction is mined, reverts, and consumes the + fee. On a live ETH/USDCx pool at tick `-200996`, a lower bound of `-203230` + returned `-200996`; the correct predecessor is `-273894`. The docblock carried this + as a known limitation with an exact walk listed as a follow-up. This is that + follow-up: it now walks the initialized-tick list, which holds one entry per + initialized tick — 3 to 18 on live pools — so the added reads are few and bounded. + + `MIN_TICK_SENTINEL` and `MAX_TICK_SENTINEL` are now exported. The list is anchored + one step outside the usable range (`∓400_001`, against `MIN_TICK`/`MAX_TICK` of + `∓400_000`), and with no constant for it callers hardcoded `-400001` — as the + devnode lifecycle tests did, which works only for a pool whose tick list is still + empty. + + Verified against every live testnet pool: 30 hints across 5 pools, each confirmed + initialized, strictly below its target, and with its successor at or beyond the + target. + +### Patch Changes + +- e93d7a3: Keep deriving the DEX API host when `baseUrl` is passed as `undefined`. + + `shieldSwapActions` built its `ApiClient` by setting the derived host and then + spreading the caller's `api` options over it. A caller writing + `baseUrl: process.env.VEIL_DEX_API_URL` with that variable unset passes the key + with an `undefined` value, and the spread let it beat the derived host — after + which `ApiClient` fell back to its deprecated testnet constant. A mainnet client + would then read pools that do not exist on the program it proves against, with + nothing in the configuration to suggest it. The coalesce is now applied after the + spread, so only a `baseUrl` that is actually set overrides the derivation. + +- e93d7a3: Document what a `null` `state` means on an owned position. + + `getOwnedPositions` and the README described it as a mint still finalizing, which + covers one end of a position's life. The other end behaves the same way and was + undocumented: the record scanner marks records spent on its own schedule, and was + measured still serving a burned position more than four minutes after the burn + confirmed. So a `null` state is equally a position that no longer exists, and a + caller rendering a portfolio should treat it as "not a live position" rather than + as a value still loading. + +- e93d7a3: Keep `pickInsertHint` working without the optional WASM peer. + + Walking the initialized-tick list reads the `ticks` mapping, which is keyed by a + hash of pool and tick — so it derives keys through `@provablehq/sdk`. `mint` calls + `pickInsertHint` whenever hints are omitted, and `mint` deliberately uses the soft + loader while `increaseLiquidity` never loads WASM at all, so making the hint walk + require the peer broke wallet-backed browser installs that previously minted fine. + That contradicted the design stated in `utils/sdk.ts`: read-only and wallet-backed + paths never touch WASM. + + An absent peer now falls back to the slot's neighbours — one mapping read keyed by + the pool, deriving nothing, and exactly what this returned before the walk existed. + Callers with the peer keep the correct predecessor for any target; callers without + it are no worse off than before. The fallback is best-effort, correct only for a + target within one initialized tick of the current price, so a wallet-backed caller + needing a distant range should pass `tickLowerHint` and `tickUpperHint` explicitly. + +- Updated dependencies [e93d7a3] +- Updated dependencies [4be5291] + - @provablehq/veil-core@0.7.0 + ## 0.6.0 ### Minor Changes diff --git a/packages/shield-swap/package.json b/packages/shield-swap/package.json index 65b23fc..1cd1131 100644 --- a/packages/shield-swap/package.json +++ b/packages/shield-swap/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/shield-swap-sdk", - "version": "0.6.0", + "version": "0.7.0", "description": "TypeScript SDK for the Shield Swap AMM DEX on Aleo.", "license": "MIT", "repository": { diff --git a/packages/wallet-adapter/CHANGELOG.md b/packages/wallet-adapter/CHANGELOG.md index d06b2ec..c34c843 100644 --- a/packages/wallet-adapter/CHANGELOG.md +++ b/packages/wallet-adapter/CHANGELOG.md @@ -1,5 +1,7 @@ # @provablehq/veil-aleo-wallet-adapter +## 0.7.0 + ## 0.6.0 ### Patch Changes diff --git a/packages/wallet-adapter/package.json b/packages/wallet-adapter/package.json index 5d9289d..9450116 100644 --- a/packages/wallet-adapter/package.json +++ b/packages/wallet-adapter/package.json @@ -1,6 +1,6 @@ { "name": "@provablehq/veil-aleo-wallet-adapter", - "version": "0.6.0", + "version": "0.7.0", "description": "Aleo wallet adapter bindings for the Veil Aleo SDK.", "license": "MIT", "repository": {