From 60448e5b87b32b05be58fe3c4003262469159907 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 01:05:31 +0100 Subject: [PATCH 01/44] feat(mobile): Skur for iOS and Android An Expo React Native app after Safe's mobile companion: open a vault by address, the demo vault, or one the device signer belongs to; Home with balances, mode, pending queue and policy at a glance; Transactions with queue and history and a detail screen that confirms, executes, vetoes or cancels by role; Send with the vault's own risk preview before signing; Security with posture, mode changes, guardians, maximum loss and mode history; Settings with vault label, signer management and a biometrics switch. Deep links open vaults and proposals. Signing uses a key created on the phone or imported, kept in the device keychain and gated by Face ID or Touch ID; every write is simulated against the vault first so refusals read as plain language. The web app's pure modules are shared rather than copied: contract reads move from the React hook into web/src/lib/vaultReads.ts, error texts into lib/errors.ts and posture checks into lib/posture.ts, and the mobile bundler resolves them through an @web alias. Finished proposals keep their historical confirmation counts. --- .github/workflows/ci.yml | 13 + README.md | 1 + mobile/.claude/settings.json | 5 + mobile/.gitignore | 41 + mobile/App.tsx | 109 + mobile/LICENSE | 21 + mobile/README.md | 22 + mobile/app.json | 20 + mobile/assets/android-icon-background.png | Bin 0 -> 17549 bytes mobile/assets/android-icon-foreground.png | Bin 0 -> 78796 bytes mobile/assets/android-icon-monochrome.png | Bin 0 -> 4140 bytes mobile/assets/favicon.png | Bin 0 -> 1129 bytes mobile/assets/icon.png | Bin 0 -> 393493 bytes mobile/assets/splash-icon.png | Bin 0 -> 17547 bytes mobile/index.ts | 5 + mobile/metro.config.js | 20 + mobile/package-lock.json | 6620 +++++++++++++++++++++ mobile/package.json | 39 + mobile/src/components/ui.tsx | 163 + mobile/src/hooks/useTx.ts | 63 + mobile/src/hooks/useVault.ts | 40 + mobile/src/lib/client.ts | 5 + mobile/src/lib/describe.ts | 42 + mobile/src/screens/Home.tsx | 73 + mobile/src/screens/Onboard.tsx | 60 + mobile/src/screens/Receive.tsx | 17 + mobile/src/screens/Security.tsx | 76 + mobile/src/screens/Send.tsx | 99 + mobile/src/screens/Settings.tsx | 76 + mobile/src/screens/Transactions.tsx | 42 + mobile/src/screens/TxDetail.tsx | 87 + mobile/src/state/store.tsx | 62 + mobile/src/theme.ts | 33 + mobile/tsconfig.json | 10 + package.json | 4 +- web/src/hooks/useTx.ts | 55 +- web/src/hooks/useVault.ts | 272 +- web/src/lib/errors.ts | 54 + web/src/lib/posture.ts | 22 + web/src/lib/vaultReads.ts | 273 + web/src/pages/Security.tsx | 20 +- 41 files changed, 8224 insertions(+), 340 deletions(-) create mode 100644 mobile/.claude/settings.json create mode 100644 mobile/.gitignore create mode 100644 mobile/App.tsx create mode 100644 mobile/LICENSE create mode 100644 mobile/README.md create mode 100644 mobile/app.json create mode 100644 mobile/assets/android-icon-background.png create mode 100644 mobile/assets/android-icon-foreground.png create mode 100644 mobile/assets/android-icon-monochrome.png create mode 100644 mobile/assets/favicon.png create mode 100644 mobile/assets/icon.png create mode 100644 mobile/assets/splash-icon.png create mode 100644 mobile/index.ts create mode 100644 mobile/metro.config.js create mode 100644 mobile/package-lock.json create mode 100644 mobile/package.json create mode 100644 mobile/src/components/ui.tsx create mode 100644 mobile/src/hooks/useTx.ts create mode 100644 mobile/src/hooks/useVault.ts create mode 100644 mobile/src/lib/client.ts create mode 100644 mobile/src/lib/describe.ts create mode 100644 mobile/src/screens/Home.tsx create mode 100644 mobile/src/screens/Onboard.tsx create mode 100644 mobile/src/screens/Receive.tsx create mode 100644 mobile/src/screens/Security.tsx create mode 100644 mobile/src/screens/Send.tsx create mode 100644 mobile/src/screens/Settings.tsx create mode 100644 mobile/src/screens/Transactions.tsx create mode 100644 mobile/src/screens/TxDetail.tsx create mode 100644 mobile/src/state/store.tsx create mode 100644 mobile/src/theme.ts create mode 100644 mobile/tsconfig.json create mode 100644 web/src/lib/errors.ts create mode 100644 web/src/lib/posture.ts create mode 100644 web/src/lib/vaultReads.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b1e0b4d..ef7e0f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,3 +71,16 @@ jobs: - name: Test run: npm test + + mobile: + name: Mobile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install + run: cd mobile && npm ci + - name: Type-check + run: cd mobile && npx tsc --noEmit diff --git a/README.md b/README.md index ae5ca85..18279b6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Skur is a self-custodial vault whose security requirements change with transacti |---|---| | [contracts/](contracts/) | Foundry project: `SkurVault`, `SkurFactory`, `SkurPolicyLib`, `SkurRisk`, the devnet stablecoin, tests, invariants and deploy script | | [web/](web/) | Client-side interface (Vite, React, wagmi/viem). Reads contract state and events directly; submits user-signed transactions | +| [mobile/](mobile/) | iOS and Android app (Expo, React Native). Same vault reads, risk engine and error texts as the web app, shared from `web/src/lib`; signs with a key kept in the device keychain behind Face ID or Touch ID. | | [docs/DECISIONS.md](docs/DECISIONS.md) | Every open question from the blueprint, resolved | | [docs/SECURITY_MODEL.md](docs/SECURITY_MODEL.md) | Roles, lifecycle, the twelve invariants and the tests that prove each | | [docs/scriipture-capability-report.md](docs/scriipture-capability-report.md) | Why the contracts are plain Solidity instead of Scriipture TypeScript | diff --git a/mobile/.claude/settings.json b/mobile/.claude/settings.json new file mode 100644 index 0000000..176e6a5 --- /dev/null +++ b/mobile/.claude/settings.json @@ -0,0 +1,5 @@ +{ + "enabledPlugins": { + "expo@claude-plugins-official": true + } +} diff --git a/mobile/.gitignore b/mobile/.gitignore new file mode 100644 index 0000000..d914c32 --- /dev/null +++ b/mobile/.gitignore @@ -0,0 +1,41 @@ +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +# Expo +.expo/ +dist/ +web-build/ +expo-env.d.ts + +# Native +.kotlin/ +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo + +# generated native folders +/ios +/android diff --git a/mobile/App.tsx b/mobile/App.tsx new file mode 100644 index 0000000..a026442 --- /dev/null +++ b/mobile/App.tsx @@ -0,0 +1,109 @@ +import { DMMono_400Regular, DMMono_500Medium } from "@expo-google-fonts/dm-mono"; +import { DMSans_400Regular, DMSans_500Medium, DMSans_700Bold } from "@expo-google-fonts/dm-sans"; +import { SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold } from "@expo-google-fonts/space-grotesk"; +import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; +import { DarkTheme, NavigationContainer, type LinkingOptions, type NavigatorScreenParams } from "@react-navigation/native"; +import { createNativeStackNavigator } from "@react-navigation/native-stack"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { useFonts } from "expo-font"; +import * as Linking from "expo-linking"; +import { useEffect } from "react"; +import { isAddress } from "viem"; +import { StatusBar } from "expo-status-bar"; +import { ActivityIndicator, Text, View } from "react-native"; +import { SafeAreaProvider } from "react-native-safe-area-context"; +import { Status } from "@web/lib/types"; +import { Notice, Screen } from "./src/components/ui"; +import { useVault } from "./src/hooks/useVault"; +import { Home } from "./src/screens/Home"; +import { Onboard } from "./src/screens/Onboard"; +import { Receive } from "./src/screens/Receive"; +import { Security } from "./src/screens/Security"; +import { Send } from "./src/screens/Send"; +import { Settings } from "./src/screens/Settings"; +import { Transactions } from "./src/screens/Transactions"; +import { TxDetail } from "./src/screens/TxDetail"; +import { StoreProvider, useStore } from "./src/state/store"; +import { C, F } from "./src/theme"; + +const queryClient = new QueryClient(); +const Tabs = createBottomTabNavigator(); +const Stack = createNativeStackNavigator(); +const navTheme = { ...DarkTheme, colors: { ...DarkTheme.colors, background: C.canvas, card: C.panel, border: C.border, primary: C.accent, text: C.text } }; + +function TabIcon({ glyph, color }: { glyph: string; color: string }) { + return {glyph}; +} + +function VaultApp() { + const { vaultAddress } = useStore(); + const { data: vault, error, isLoading, refetch, refreshing } = useVault(vaultAddress); + if (!vaultAddress) return ; + if (error && !vault) return Could not read the vault: {(error as Error).message}; + if (isLoading || !vault) return Reading the vault from the chain…; + const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; + const TabsScreen = () => ( + + }}>{() => } + , tabBarBadge: pending || undefined, tabBarBadgeStyle: { backgroundColor: C.accent, color: C.onAccent, fontFamily: F.bodyBold } }}>{() => } + }}>{() => } + }}>{() => } + + ); + return ( + + + {() => } + {() => } + {() => } + + ); +} + +/** Deep links: skur://vault/
opens a vault; skur://dev/signer/ loads a signer in development builds only. */ +function useDeepLinks() { + const { setVaultAddress, importSigner } = useStore(); + useEffect(() => { + const handle = (url: string | null) => { + if (!url) return; + const { hostname, path } = Linking.parse(url); + const segs = (path ?? "").split("/").filter(Boolean); + if (hostname === "vault" && segs[0] && isAddress(segs[0])) void setVaultAddress(segs[0] as `0x${string}`); + if (__DEV__ && hostname === "dev" && segs[0] === "signer" && segs[1]) void importSigner(segs[1]).catch(() => undefined); + }; + void Linking.getInitialURL().then(handle); + const sub = Linking.addEventListener("url", (e) => handle(e.url)); + return () => sub.remove(); + }, [setVaultAddress, importSigner]); +} + +function Gate() { + const { ready } = useStore(); + useDeepLinks(); + if (!ready) return ; + return ; +} + +type TabParams = { Home: undefined; Transactions: undefined; Security: undefined; Settings: undefined }; +type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined }; +const linking: LinkingOptions = { + prefixes: [Linking.createURL("/"), "skur://"], + config: { screens: { Main: { screens: { Home: "home", Transactions: "transactions", Security: "security", Settings: "settings" } }, TxDetail: "tx/:id", Send: "send", Receive: "receive" } }, +}; + +export default function App() { + const [fontsLoaded] = useFonts({ SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold, DMSans_400Regular, DMSans_500Medium, DMSans_700Bold, DMMono_400Regular, DMMono_500Medium }); + if (!fontsLoaded) return ; + return ( + + + + + + + + + + + ); +} diff --git a/mobile/LICENSE b/mobile/LICENSE new file mode 100644 index 0000000..30b20e3 --- /dev/null +++ b/mobile/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/mobile/README.md b/mobile/README.md new file mode 100644 index 0000000..7a08ec8 --- /dev/null +++ b/mobile/README.md @@ -0,0 +1,22 @@ +# Skur mobile + +The phone companion to the Skur web interface: open a vault, read its balances, queue, policy and security posture, and confirm, execute, veto or propose from the phone. Built with Expo and React Native for iOS and Android. + +## What it shares with the web app + +Everything that decides something is imported from `web/src` through the `@web/*` alias configured in `metro.config.js` and `tsconfig.json`: the contract ABI, chain configuration, types, the risk engine, policy rules, the max-loss and posture calculators, the contract reads (`lib/vaultReads.ts`) and the error texts. The mobile code holds only screens, navigation, storage and signing. + +## Signing + +There is no wallet connection. A signer key is created on the phone or imported, stored in the device keychain through `expo-secure-store`, and used to sign after a Face ID or Touch ID prompt (`expo-local-authentication`, switchable in Settings). Add that address as a member of a vault to act for it; without a role the app is read-only. Every write is simulated against the vault first, so a policy refusal reads as plain language before anything is signed. + +## Run it + +```sh +cd mobile +npm install +npx expo start # then press i for the iOS simulator or a for Android, or scan with Expo Go +npx tsc --noEmit # type-check, including the shared web modules +``` + +The app reads the Ark Constellation devnet (chain 9000) through the endpoints in `web/src/config/chain.ts`. It ships no key and no backend. diff --git a/mobile/app.json b/mobile/app.json new file mode 100644 index 0000000..1636f64 --- /dev/null +++ b/mobile/app.json @@ -0,0 +1,20 @@ +{ + "expo": { + "name": "Skur", + "slug": "skur", + "scheme": "skur", + "version": "0.1.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "userInterfaceStyle": "dark", + "backgroundColor": "#212529", + "splash": { "image": "./assets/splash-icon.png", "resizeMode": "contain", "backgroundColor": "#212529" }, + "ios": { "supportsTablet": false, "bundleIdentifier": "io.skur.vault", "infoPlist": { "NSFaceIDUsageDescription": "Skur uses Face ID to approve signatures from this device." } }, + "android": { + "package": "io.skur.vault", + "adaptiveIcon": { "backgroundColor": "#212529", "foregroundImage": "./assets/android-icon-foreground.png", "backgroundImage": "./assets/android-icon-background.png", "monochromeImage": "./assets/android-icon-monochrome.png" }, + "predictiveBackGestureEnabled": false + }, + "plugins": ["expo-secure-store", "expo-local-authentication", "expo-font"] + } +} diff --git a/mobile/assets/android-icon-background.png b/mobile/assets/android-icon-background.png new file mode 100644 index 0000000000000000000000000000000000000000..5ffefc5bb57a3d7b39ec6ff4e96979226522cc49 GIT binary patch literal 17549 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

f!0B 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 literal 0 HcmV?d00001 diff --git a/mobile/assets/android-icon-monochrome.png b/mobile/assets/android-icon-monochrome.png new file mode 100644 index 0000000000000000000000000000000000000000..77484ebdbca253297baea4a7d416233aa47a45c0 GIT binary patch literal 4140 zcmds4`#;nD``_G?M(cKNH;M{5n{L+KorqWtQBFDAMuoN!a)@COO1e8JiX5_%Lu_&w zVuqV?OF3_C4wZ9SzO~SheO~K+e7`?^|ANmRkN0Em_w~LG&*$~JuIu%FT|Mc13?Z!| z4S_%q_I5U|5D1hmzP4@wl9$dXJ@5xVZ|5BaffzW7FX-dLIpshIjdDF^4XJ*uwg4Vr z!B$RI5J=4pnGL)o1oCUUy^WQ79F#wPI98Qiu;qVbTx=VBN_q0@@RCT??3)$*Q6o3_ zChT_aGStaF=bZO=%-LrCs4ipw-~VU{;MUPb{MQGiQX=>Lw$T49AYBvHC`w3fiz4g1 zxV0P@vdjE;!8TV35ca?4$GK-OVKLvHDzz@`t;#jVPBceMb*qmqMz5}}hejpk9oJ6o z5lz(Q9|$j;QC~8Ls%x>{?QHJ<=aSi*$qm{D+u-{ANTp}+!T!xU24l4VmAa~cJ8!ka zuL(ZhyF1d7)Nsas#D4p;jFfFjjub27jK2*S)!~8zPs&kEw+_dBn;+i6bFt}TXtAE6A;jap7sj;sp5ja4aL zlTH1ENx?+3pG%~B2InPzo}7c^Ylqx}Q0=dEefT3;Xxe4Q5C7xRS-w`takgJTYy7f* zW_WyD+;_pk!osg`l}DEb9(?}hTk#@7^hh@3F9=ol*s)^*_jj)sRhpmc6lsUtgiy_1 zlv_j{xX`}`iuqlShz*}sJ{5%Ol!BvtTm@E40=^c8ki(fioLyPYQ^pWr$f}U{?<|Ho zLasun@rHFYb{)!R4=cpVQ7YOn>+Duk#i-@}b9pKyX#>(wOnozH`1Jn!PgX+krdAY} zs*!Wi2h2v90l@qcgzA7`h|MeZvC3R0kCc|v-V56I)?yzOq{jd=DF`b=J@xZ;q9-H3RSSwSTYK|&-o6R6KaIVr;EtiVAozdX$KGnC7Ac#l$rw9(LMRlIEfS z#e`hz3e0JHC4V#&?|zgb$34AYh>p+&o@8;Cqc2=AJ#pQVzM2VuYp|}oD#-A>%?BMt#7bLRE)X22(>NL6gkiBYrLR6$ol)^SV9JObVi4M;311p>qpD-70*?F{61`ytpXx zG^|5q?q%s%BiPKy)D7JOcQX4@FiH6g>Vlz!7gF~Ek zVaVsoYdDTs1-XxKUT3CwT|3#klrxJ>63$e?4r#ME_Z_(G+G=nA*+bK;^*xfg$%rj; zpB_Mha!VLA!Lb{=4%_7p`|I~UkuQ48IV)tFIMR=TaAgk@qhoiL>Nj5$%%;vWMxQHp zSHn>;THo4fgp;|4qvKpQnU+=T#W!w5ALJn|7IHkWX1;@vm+~>sE$rmvBSQSf_b>aC zg+`L4X*G@#SuWA4C2A0XqF1c`Ml_dgJC4}d&H&AIXfF#na<0BPKM=dFQYTcYNGII` zp|+wh3ayF$F#5x?ojBumW}j|Z zl3>}JdwV8QIMv?Xz9hIIP}eP8c>n(Wwa@Kca7@W1lg#<0ep)REks=NOD%_WC*-9=< zY5qJ*D3fl$4jg5@Xk6^g9D`| zqRHfP%Zk~`|7ptOi0&fIbZ_a99Y9awryhn<6Y8>LKGyS7i_T1QQXt-g1O=_Fm^rn7 ziU*kAkvPm7zIas_GGB37!(;fms=9ofD(F~_DYP2{3&YwHndu)H_}wS8&f$r9kRUhf zT@M_%WW>n0?r#@VN9*a{DPRWs`3|pmaQ_#J6To8KnCjXljK7&8-GaymsJ`xOC zm_TXycg7|@JbX!TMabyyasM+1w>Agw!Xyk@GlbIX7kz1lpjozW-@cjCCM?p; zStvLZTR2xFx|l-fXEi<(&uU2m)&-3{YCA4YT?%B%p?T$QC$2E1N9uK;`i^K1D+azg zErKMGr4Q#aUl*BQbRFxAr|Ex0AD5YGh9PrD88j)~dsoCc4Ffr?wxvXb%1s_THcmz; zMXToIZw$daHCc^!HZR5q6z#r&LXczNg>8LRNtw`GZSbO)ufG8p7xPf;jz;-Is4a`J z*nPS=dH|H;YyypJ1b5T4;XIKV#U#ziG8kWgY*5-zs+++>IfyV{}4{UnmEXY)1hnl(1 zBv3oA8q-#Eo^=S0O4{qQ{!FN1#1-fEC=9tIKU<6!L>~mSz#g(Hhud&?v~oreZ8p$= zZ%RvRx_>1Cj+#&|Pkc-EccGIw2BO$Pt+;EDsp~j4lgO;z%|*YeM@@hgak-LuxsQDo zCPu#jSgJGEK2|2^+JSJ~2X^B6Veqx`*yA(x0W{IR=g5T`p}5nPBOk-02SF^f@t_#=9_VNz7$B)^b4i?_erJ0F zsGTqA5Q5)o|FB{)z)A9aB<@;*#8do_dYY`dFJ4fec&Pzj+ZFgFwB#ZXUz+IQlCNtF zq79_@LpB1K7jN}e~_om2L!D*1CqWBm@<~!dZdByG^B^^Dr0V(3k;;vtfCo>7MLxdE0;5&nv%k zFHs&vLPyg-@N)Y+g?osdYszRR@B!sf9gZDxN9EIyDa6i|#4(3MFs~n(o1H{~lH*Mh z$4`ck3aRwE3Ccj}_+>GUEznbpL6IzvEU9?<=Nu_HC-KzvF~c~Y#sO|4WuE7j7%-;he19q{tgq-Ysm;L@d5h` z(0L37a#HQL44Zlwl3F9IaJ%ycLA8*0YJE^Mb8MbN9;qA#3Vp41?v9j^1@pTvW-9|9 zhjo5k=&J=LUTJGNwa3%w!gEKj^5|r=HO1pN#Y3-6HK|Yyl4~jfNWP(hlPvD;;w0R7 zsFBFzyhXn{P2DN+6p`$_w?_D(WGAuH*)Nuq0U;dOekZ%ed4@y&(qIDS)r&Q^lHU@p zeiV;W3*mHja?ftGqwnx!^TrFG2;Oo$D_4~gBJ z^xupa$0%kcle0v=&%M4K>d*M3d%kl#O%^xub^~kn+U|xX#P5D#*$~3ZhOlymFtCh7 z>ipUkdmntx6J9A#lyk`@oSX)HSV1_b!dKe9z=>x~4=Cp~E`jbZ@zm-^=mWt8Ct<<2 z9TUPxrTjndHU`jIx2S5fREB?CY6It?U^cvFBT@a&=$9VLw00hN`fN78*Nuy|H`Q0S zDHZPgwAy6vl#x{QnKEQ%{Ju-uZ`q79e%rW37WarsrCzkqQA?iJ7*sbcj81irReKg1 zkm{EP1`YXSR literal 0 HcmV?d00001 diff --git a/mobile/assets/favicon.png b/mobile/assets/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..408bd746615785760b09e6f23fa8378d3e614331 GIT binary patch literal 1129 zcmV-v1eW`WP)_aY0~Jks(?}v7_xUud z^7&IRydH}ITNsLl({49i1>{P6S;TY(+6r8WMRB%aw0 z;rtJIzFmzc5HNL=9nP`82+ya4@oUf#@Yz^2v_e<5fcycE^D5sGmvQI}3cr41BGHS5 zqZDE=37um+VRnU?J;~S+$dyt83jNjd>z;2;pUk?vq zeO3i60?7N6KB`a@Xqwf576E=dI{Wq;=pe8Fuime*W0heiTZW(n7BKrp?#Y*rF2M3c zzx4i+hFS*>P=l^%%#EN?@GW4Y z$)Z)i=b??9ER}*r!M6aJ=O|?;b?O;SL}2Vnx2Jch;7fqa`;;bgN%_uX<$k~Gwwj{g zXC@mNPJ0%YD-DO?$pM#BSL4dY&-pd{e^mwi|7(`GFw^DZY9WITPR3M8QA1nicpRJhj$ zyC5jC6?({2N=y4_(Q5S+eTj23=C^QVEZpro<|KMQeWwB$gK@sC^5hGVE;SL4Meh13 zTp7;YD+y6uQ-tlGF#nS$Ioc=FEuq}}alo`1@8om-5H5>%D<4B5PGEMAn`h5(I@~?& zUYJ*`Sky=ubjHp(Uxf}s*t|~v+OayU7}V|1cUW`sSVq`L(}gX7q98OaK!-qW*IMuR zU$s!riFH6Kk&VutaYLImSFDQeI8H)4!uWcuCzNsyHOyD^Ks!c)Y^pb&aGh|6&WC11 zPnH_W7MwQpBM{M6C7axCH~p~(wO?6mb412^vTU?i$?PJ!pX7u1RnS?(TymxO;GS`H-A*@45HC zw_dNsVo!Hf@2cwRs_LrVVM+>8C`kB70000*Mp|4M0DyUVgaIHxJ^efKY5MW>59pvQ zB?>4VA^i391JPDm-2nhV#(Mq(0#ed&pTOPC->NyP$;VlS_qJ<$t#hH+1MMCax#ON!Q_HS zq@<+$_C_YW%HooLp+Ef+AUAV#wB==CadB~Bc423>u{UL5<>BFB0kg5Nu`xYCFgdtc zJL8M~VQFKEvrf6#vO_2+f`&y(@0D;qo5SUNqECCJ6b|N9O9(fM!s z{viAt{++eCqu}2t|JD89SZefrMf8qRp1OJUF@kFPpvHfrIz-(-Pzw4jf|BWJMV`Xb&{UitnF&k?Wb5ke# zKN9&j+|yeAR#O#YyML_hUn~5qXO`yAT>bU*A9#PGK0!RK;{O4`{(nL|$>D#R<4^B@ zlJ_qu|6knk|6UDAOMM5krv?6(@L0ir3;n-`{>|VY)Zc2M{=cimKZgE7{X_3RcIzKg z@SC?MTOf$U&+;$3B8b!pd$a+7z2lG(7kTSCyLWFMN7?_G5`j$!;~n3;0RKTBRoazosXkB*|<2pI>@!9j(I;Hl4OpAT*K_}iDK z29xy!oU_Uk3_y8AQ+R}}V=#3=>^koM+NrnV_`OuB_<0!9_v3ThdPzvk_)`c0MHkn6 zlN<#cr+%0NTR~j?JoXwu|J*V(Lw|I^z3mbve|rH{NgB`zBdehP2Urh%5g&%kGX(@pZ^-26{gF5Xi*V4=z#mWam-k%~L}Z{v(K}4j}Up zluYb0Dvv0bcJQ{RI12Fgxj`vCgB|mWO+1=wB2(7mNy7wO?uHV6UM4Dn`|=NVULr7B zwhbve^MKTJwDIyw=|km?=iIrKe$_o z`k9;XG^(e4cW@O|0EQM%J^oYfx=JIIn`DoPGw_){n`vSQGh$O>rNXB}d#X0TXOaA& z?=AllApl?$C@)HiBp<1PP4$)VR!(Sao&@SKRPSQ;6 zKySSI`U!LBA}E8fKN*8x#z8ygZsV)BPZkAP?pA0@%Z^^TYn`P}4HedPv~hDZCzf!1 z`K8NS$3q%8(akU59Q7z2HP8toYG5yGEhA^(z4JYLC+%4&|7hivG)Uk?o=PiaPBpgr zsJO?Tu1r2vhz@F9?dwOr2p}%<@rN?W%BSbIiR~;tEhNc~^o+CyU)QDx z((;iUbjPwgWk3YUcZ_Fcdh>?4l_YK59s8LuW}I+$6Q>qB4L{|xXvNGPoBHdiIbE#s z64rSpGzF`dcZxrI`CxB?zkqzIzRt+ds&XD**ex84sW>0gSUzar!{Y}pF(f2G3#^Hy zde2-T#&Z?ChI=N)w*mUu9<%<8;FI5sJ|MOzYD=S^i7ea1p+c{jz3eOy9y`HKen^_+ zv&Pr5)IM~a@6`?(>u%knko$Hyep`EN%>D5T9F&&w7%30sr@-VZko##P{razk{aNJ5 zGI$jlAKAuMHXA!E>5l;=_rcZbQ{##qA8dGtbV5%M9$m$2_t;_N`@4MOFPL?|Qk*05OJ6_l zG_#*6z(o+pDkjT8CqiM|t4t>vzN>Nu4(wtT_ywnjs3^D$$iLKqsPsDQ-lGYm~d6dC=)P%P{?n)aRJeLtTrBYt#X99`k`6c7M5{=Db5 z<5QhYs#7T9& zI}0>zSzZ|Ovr5bqX|1}Ca(?WeE?sJJ8_49n!VPiHbjHM7usV$~_Xsg|ImjA;e)bZU z-=%jz&t45yQn5c$&8yM*hooGNc1L-B3f|73KC0{01+2gzwSQvjNX-?f7a!3vSh>gk zHq)}XGW<}_H3iYu!LI-S9H6YSd~rnL<9Nv33p%KJy!7!hT**bjI4%~5*}oM0xjKi} z39)QdEaS1ebVY47In5~Oti^L(N3kZwRK984C zCm$v~#%~w;+o2eI6Yp0_d4$qak^dEIl((;%2^ivZ+Ih>7`sU=s%Ow-(eHGZuO!E9e z7)H|SH5u6)?`OT2Ix9!DhW&z`Z*<<{paY;<<{&gpSL=LwYVeMD)YU-0qX<9Q>9*JN zT#L7u2-CDJ{V4^&nw^JZh`z2K1+FOZV^!0JOb3TLl)TNm*#6uXx#SI$2zlzX{NKPa z$K0CPG$x(M8Qw!UQn-Q?QxX$7&%Wian6hR^jAU-O+pz`a!QN~=F~xr8rf@GWS-#;y z*^z!wHb^67B;Ps6EL7}WGgW|{A6(|^yW?;+&Qw^JGekOy+p|I%$js;bJ!Z1T!u0{_ z!ojLWMLxK*q0+-CGCn+B3mD`R>A{(*!H9M_dl^c~OvvmnUvv;zjEOjwUVJhva=V!% zGC0TFfYd)b3;`$~hzEr+060@H!KHN#wv(0S_!i24Tju~}$9NeOrX~N=Yo@TR?VZ|% z)xevPjFP(S*VT3bdXyZ01x~+X(~5dx`@Y6mPg#2V`|!oHx$*e%B$Bj;!AziF(yy4ll`SI~MUyPSkgJ{|K4a&PO>e_GGJk21k0~jZxq2ytPD{(0@G@{NROC z`Ei3AbI> z!~@7kF|ydhm6KtVjtAuAL3>TR+WYeL1$xiEKHF2#_@A9ia^B=VR?)y{a0kxtd7*F;3PjD^`m!j!o+QG`N2Dg~fpCj{vZlCPor^VkUA<#QO*2xljf*idfi}kdU=52r z1Vc5L1IU$jp))O@=G;cGxGfMEWLCo(o-z$r&x^l7J!ogdMTyz^1WXD}@Fo+hF-GFx zy|lek)S)d6xeGW(vCavRl7U=RkAHTFwhhSB`XY%nBOYF`VKB+bX_IFy&S?9%i5YZRX95kHe{D+@EswnreOL;JsG90EAA}tz<9z)n{xUk|G^z)n0;b~kI zGmpc_fuQQO7-mx9M_2nkY;luFPF_RR$)xGs096UGBwW&f2^DZ4dJ1l?I+hs7qz9KV z2@fw~j4|m`s9%NL3n_4$FQ7}go(td$!{K^~AauV!rvCbqcl|L-v-9cA&+Kjm67knO zD9VH{2|JhD#Xa~L8XG+ZGPGwt%~vsO%x|SBkIXonP?CvpEX`TeUO zc4XaOjoPglc6u}H>;?$$InIYDzYZ%d-0^5MIdFM?RHRb25~n{4Pvn>H`K+?*PBC%$ z<^YNuS-ay`z3T4S`g*mZhLici)*i0xbWCx7rSdlgo6izQx=%sx$Lo`xcQ9bM*wFSA zTz`F=iqLk0YHAIvF-Z=LcCZa6R<#POwj7U@CxM?BEx7gvXXj&hHueE^%%T{R_c=hw z?eYyt#14-4#Y>BfXP>6mAnRQ7m^6OkCXd3S>_r>B5`;=vor!;&u zU-6?0tIsR{Ey$*}FiU3toUoeDh~4r>Dl)V5)CuKe#?E_Tioqx2dL=TwT5araf#-8SMy|;I_=h>`r zN!KX>j`!hpJS+UF^+Ho_cDk?7o;J6F2c8~3wT(KkChSywPW<4zCHY)|xn@tOU6Qi_ z>dWNO5tlPiY_*Esc)EaJjOIrkO217J;liJmg1YJL1b2mpLf)}SqI$NF-ZJe)pWE}! zpcq8_q*F#1SEUez&DJin`NFyOYcF~} zkZm%08XR1RzM2XgZBg#m;t+Fte{=yZKU=gP28$zGRU4iyTEX2Q4`gv@c7JprmLpk0l41hP82g6#JD)2*=B)lwZ%{0vDK){% znRqie48bOD3~=GQ-!9`h>CwFfPo5S8@Fi_Vs1MeX>0fV8-!Ss z1ea zP`GVqf%l_)ipo&73)Et$a33PfeskkhzYR&5RR#!Apk&GPA$*ss#T6OPwH>K`3T zbkYtJVH(8qaTOmBbh;mLxK}PdJ{=RgnDxp01q|`L|v{1nc+%H>h<3ggRvTJe3 zC=Z8?7G`8mH|KO4E6uWrQP>6GlZ07Hr8~DS%rOD{FZ{Gbu{_TR$U{EIae#0{REUI}wJ7$>HVHKP>-+)H3t`iv1CaNRl# ziQ?T!Qgjj9X;m8c)B#ngUu0+ub*bq0&nerm^{2q%83A;;~I~od3uZjsA>d*a3lLje^spJ%fJr|5Gn}EwCEtZ(j zS>_w6<#~)!X{Y+r?hMA%l$%$ZD6?#G#)EBwEm=wvlKqN-rL%zZ6T*g`Woo%uD)ou2 zkDyIOn&Bd8u)fYD*i0Hsz3>648A(j}Gc_ki-Kb|UzO|j%bgG#>dAMVjeKG&))aCJ- z?$Ytaa`EM;IFty|BA15O`FX0%qIe$|;wRWQ29JUKs-E2I8y`S%EQ3wITq0yBI1EWF zqX$zmhg(h?nUZbPG|h=y({N#Joj<+o_Fd*A-Fd&cUmhRSTzqBUXcr}9zyyFT2UmE5 zU=y&8zJ!icwj0BVp($cbZ>T(j zMgZbisrR<`MJad84l9WKJ*?8-X~N91qJC8=2if)}I+vag1rhL|$m<0&Re=CiY<(^n zjZAE4rZ%E+a83&0q(Qpfkj&-s5xI-5HWjm0DIMEuKR4iu(92>%6wr_1-=}+Lxyt7@Q-Ltdn~7i!-y( zML_lL=>&a2hM#GPi`BwG#A=6&%sfFtA3*C5n+HOqTRS7%+WO`BomVq|?QDjUm9Pc{uD?}%UFA{FSdG(_QF_-wNF%#q zQ~uS|*%oCI13nKy0M1+L^rFvi{v|ywBrr~{#CR_9nI3zICRO9>&&2_|B zgkXZpR}Nzen6$LD?K}@hPv^zkU%VymMv`hOd3SyFSNn1k@RE3+8=VNOSZyv6PMbG8 zE0*p3+yZ(q>hSuRP&_Esll>#f^f^OS;iMk3XV=uG#mQ1oTtrumo{d#lIMWO3#p6;6EA9nMv)o2!S8u!Pysvk`=`ZYBR`M z@BDxVuT^l_h|%pgD*Yk2xeOV`0^gQotzZyG7=*r8*#(u3n zt@u$h&P!BeCPU>jVdo_IGFDLvXbFxI5 zwY|qkxo7dAui~RygQ17~0HmzkC{c6KlR|EXD`A_3W|lR5i?0rJ8(J=xAI9DYYINOQ zywqu~h&c6Kr<3wWXt~boNa)-sv|X#8z9m5fgw#i!ByN=8(k)ewBgTK#igdF|)q}mp zU6CW$;^zLf3C%u66X=T`!;Wxa_N(!f9E3~WABQS?nez8p zRYi>dY@xQDtkRt!7} zw7Kn;{lmqyr(&VZ8)?HGqslIc48cl!0gPELp|)ZyY0lh&on!qw zmJ34sycmNy8?8~9z0Ks` zf)A|fSn3o^a@JgpnyR;;h>OLADPV4Z3q`~z z5AcpiT3zgWBsWV`ALnYzszo``lZ-i{NHK6vT>DwwElAvDJd|mA# z4S`7VkxaVc){tY>UH=Gfoq4-#C!O&me_mOt7|^OkIFBG1Qx&SMMF?lZGGP&$*#&iUb^c4JE~4y96sy~Y_-1+dz%HIej{kshhl&};_Gv_IEJW+mh$Ut z$>;V)3pxN%`KaB&L|TTRiQAYqmEQR3x+*^g!tXt&tC(gLI}#1s?A+hA**SiN7RFC+ z~*_Q-M>#u~Let8k> zkK21c6=KK7FHDlSltd{zxa%7c?dj{4yOuA7>NKO=-q0iMlJN`Y*&qPwG|vq~Q#zdY zT`O=sB*V%UT3f-}cXT8^U|=2>b~k_5oIgMgr`utLq~-FeYm?_nuGi=CqQv+>Dh>|- z66~T!rj=>isH$e$zMH`W2;QIixYRcutId9&UWy6aAI1g9Wkt{N*37&~YMH&Gd+`FY ze)6_wQufY4JkhqHV~mcND3d6&^oFvw&Uv6X?|q#o;q3^Jhn8v1c0FvqgL;e<|Vk}DkdB6Cs{z%gWjO@FM8|?ZSFLYc3{waZVg9O`WRPZ zilxJUFI2l~3mbKRl0F+hq3HcB@TbDt4pUnm63e*20t9auqrohdtRdWyK%c9JdzGOV z+^2D^KDU!>E@MD&oDN*#t0p>@Udxn^aDr>N8V0FMRwUQM6$>{IIuCq&-K~RGd}nXY z5E`=-lC}ineNMO2v4(-c*?a_llXkgS)BHUg!|SOHw|uaRh^TX#ldEU7`_=kgzk2OR z0v=upra35gorgx*syylDUftnZ@9-plbDS6lgSxB(c7I*}!@COfpQym;6+mFk zs%;5}tBc3On%38v!Pyf0vns1)oMx4RH%7|CQ@J(-J=jvpim*dLRU|n4= zx5CsrS`pjgpb>6(YvLdVj$uwrqm)1_1V zK*>9rr?MW;+K_me+6+tH`_>PHU=j)(_>;){ZLHix?Tj&ofLxTzSA;Ia=TA{YMrj;7 zHw9x|3>ENGc@vU!q&`n{h{x%(+t@Q)gmQ~F0~otchnjUmFNU`u_%;ri0qJB39QtK` z2ytIVyA$hgLEh{Q%L}<0R+g5$tvZQdV!h_1YO6we?JZt-S5>+oXG@Mpn@WYgEr#O| z!y`)K`uc9-@}Pu+rlSM$cv)M<#10p(7@*>Y?-FB4^Uc`;Yn{D`;+G*IWPia=d&*Oe zeQ~xx=cP$it$F?OMJl2HApZu0gla zjknPX3h%WO=s0F(wSs?AG3-!KomO*&zh_~x)>7A6>}&#kFWSqm_?H@kj~3~G+mtw$BRer7Zigf znBG_{uUg;h33~OG9x7ou!MX$6yFbuSTjXH4DA~I{?cCF{UZ+mD9*{q7C zDSsmvS%E*-^maB9V|nDmio|9EUSdMcNT%t@^L?G)mwp7%V1yM&hDUjR3U}5mQ;V84 z9P%Z-3S7iDnpn^-)#DIzcHxnRqxdxL-Y5HdQH^oH2#H+8!4S$lfIxwdpZ8pMsbz}C zL2?A{Rrf-da6_uH_y?v#metPz-9HCU@2OVJimQxEc}8Xqs%J7w*RDOnx3s$lV1+UZ zEeO0F!yYW5%C+5mBw--+>`jb&;&$>_u(|bL=WlTh4yHNCs9{pj2kVb-;mygZ8ueR5Z$960u1>vPq zUsO``z#S+dQM*ow^G#b=>*(t6RU1Q}nT2f&i-L~!I69I(5hY8GRv{zwC@D{5<**lHv9}YB`q}N1I=<*_V{fCHbcdwM%3G{94!=n416`ogHm zKy(FxyH2!&32&l0zYx8F77=-9<|jxv)|$l)o-8rJ1^R5P{cVR7&xe3MrvzBIfWUZ|%FtT~CNbf!kIUc$hEMU2Jr&<5nZbk9e6sDdP0y_!8Z>&;>yK9U={Qo56$79jT~b zdpMRH;(0y3Sdt$Uk%tXM(fRf0@!=r-v`#Vn)bsAJ)ypf{p${m|#xr<;9`y_!234vv z)7l`cQWHkW^-|AJXI3@NM>!)xP*iM84YBQz+o!}8ULTZ<9uufjcWUd^v_q0!tT0s{ zSO3Zy1NGGML@%%q(CS(4dOh3z*=z4R!p0g&?TJ?3Ou!3|oa|TN73h<@6-O(rb$YgJ>H4CS-<_WOW3Rs50_%oMzHoSd2qF{`EuJK3W|R+x zw9RkC?y*m(>2Z6^JQ1A;BSIpb#23IxDNu{?Y+ZFMO80VENfjG>6sqEB74CJO2qy<@ zj7}%GZQuY$lV*!zXLmu(6a?O9Rk^ply&q0=EFKRC%3k5Ik{4PMH~2oDdbo^qvQ4Bs zYzy7(4~C}=Lj$;2PRhj}2GN#;cp~gUeA3u1RDzoIh@B4rDYEzX zo8v=z~%)A7K3FUIeClwIqjlmek2{-Rs@>fdEFwU_@-tfRLnKlv>#>{C>N81cWa`=T& z_&cC~jOx~V{~EV%HurXT^0w}julp{nnQt&Tv2{<4C;LiHrYoXdA0X~ zGT74flG*zv^_JMMV>nuFB6sV)dL<5&8Pod&P{x5f z#>r=0R(n}cRO^}KN=CMl`}*wBb0q$>LsvJPcvh@<2n$4((8Wb zfN6)oOu4dxcp${n>f>lXX;BhW@(K1O0<7y%OTMlK$9tB2Z2?QvM6)1nq}Fcb_X)1~ zOfHFUNc{ElzT=>i$N(gz6r#lS@Szf9^eF+x9{Gjo(2pl;G>WR?ps2Meo4v=4!CQ7R zI9JRnOOw{R-NSjem^?1s=Ifpp98^5&U?XAC?Y_r{A{rNk@#MLt$oGa1b7i_2d^w)Q zAgM=M<;Lz+6K*x!UcQ~JTRsIntCtfh=~gBO^peE~Ib$F%Nu;L(aI@6)!&+|DdQmYk zFq_WQIxt6h?Y?s5yX@^0Gn2J8Y%^`Ouy1he2Y&Cs^`2eC*>!p?+MAFIp-d)}Z~vi3 zIfkf`Tb`ElKGcP;MXBN6G7@Pb3WJee~pb%-LT;H~G zAy1)Q>NIe+R>K?ju_Eh*0LHc%>B+ID#PujNxxk~#0ruM8eXq0$v&8N2I4)*GhyckP z`OCb?{ohx((2lB>_=l2=by>C+YFkdmOYjUNm805Y<}vKW(axf9M|nHc!cy4$L;;I@ z?a@nKXJ*5koboO=?`;-5*LX$!Q8MXkw3UM*@Ao8JvR(tcX}r*I#~DtxzcCU3P!NYltFVIGa{_`(sCp4t+lY zLwmZqLaT2gjcuO2m?G!n~K~T3rtm@+W zbkpd!)2}51%v1#li*|;VB!-eJ)?1lk@|$)GgE8k-47o74x!|(aUJ7ucixof-KC`s_=x>Zl(bWz6(O!k_ zkTK4*i|5$KYfAyu;~+`>VSpiVv95j8aE!DNL<%>^gKV7eA~)SK8J<|sCwo@>p;U2- zlY-AUR5bOg7l!2@o;~lPdYBH1>D|yxR8{-i1TOc1KD4Sy9SyB6C|=UJ2nfb=}88* zOZN>{gE@v+5~9k4O@FY{-!d7tD{la%UDYR{R@X2A5mC32>w>T3H47y8vS=P|AqR`P z5L}ZQ_mfG6#MZL`OGz8Qv;`&{DD?OMEu(^Kvm0{R_|ymqM}_AL$eBLn?vE>OA)LaA zDF^#yx&jEHs1)`Ctmv4Lbfy|@&WzJ0@L8C?OAZePTw(6FX?Q$s;8HQNzQQJ6t58lh zm>xN!EUb*Qm5YFbkxm+<;ctq}UDFz&eRw<)o3f|2y94c!gLY%2_Geq4@eN1tlo3oM zT@vRDma9)v2=lUW9{#$!eW#h;I*<^3wXj zl6;|tHQ2sHQ(r$KQwe^u8dUvGX%|5^xOV-@5?Rk-Q4jyi3>64w#TOb(DaGPx+v;K8 z;BMc*d$`W&ApW@?`jDdemC(F}ZhgJaKDs;rQ?!HMUtA%E9~a}~JqTQS0NkX-iU@95DVE+^{CQ!Lb@u5qZ z$Xd?%ZDr<0eVA2djPNUN2hT%Y52rTS?XOZG7ylHB?`BcCvW; ziDU#NzkEo9-1<X4sX*I4rOe*3ZWeHjx4)F=$CYzCA_N+M|y-Ayf~Z?puU zS{5KZR->Fy*r8)Me{yhlPF>*=&J^!3F4D(Hz}wr;L(Ko{P>`30ci)2}f{C$?FCKcK zDOF;=$@%)b=J018PZZ;)%PgeuR22CfM$j=}_lg&*Rie^Q#_Er?DuyiOAhY`WThxh# zOZ#J4<5J`t9kF`ft_099P;=5n8^en$R%PK_=UarZ=w^~I!Y>I^_>&bHVdDmqD}qUJ zV?tD05NL>KktpNlmQ`BaKE2docg8e&lMmCHd&9!yG)E4=N9EKWvJT~UxVy;kzHV~AlU=@<%H3J^)kXobnqjQi^g;#QSNtBnTv;(&MiBe zXJt*Eze?Vl*j8gKGK_w5h-fFurDOWO0w6Ib)n&Ew4d3cf?Z9U_$Y90l22OH{%>jl) zSSIeX!A>ESZN=M!y^qaZAJZ3n?A^zWgX-Ch#v)Ybo0}RdmKGb_ZSRp%xnVvAeVP`@ zuLmE9V+)|~V*C6RU_MfB+0xw*#SVdj87WDzh;0|wIz6sC8_`A@7iTwSG|J)L8ip2x zI)bC0q7B{VF>x{kY8Ww)Et%;nl=&+0(O^UfV_$%N$_e&RZLE0jSQnEIgy}P6U8(B> z*#j$L+ZQxEL}55_Ha5TT09U65qlpD{^qEiMQz8WcUy7+_C zMSP))P^Ai84=(~HoOaTZ$-*m1@%e{;k}%I{PBH7Y`l}05LIEI3oG~1+n9JbUptteu zx<>8#RCCAyuwR0+$R}U}I*@~k%h%u=hJp0JEA3q=$B&!(w9VTF%#*@V)EI?`j~nnL zrB;iqY-KISv+apGDYXJ7;@5;5#L)TcZ%LByUfoE+k@krwMrgv2B1@N|6F{ZgO5R;q zKm7DS^Bv97<-EGkZQ|e>LZHTr^`lZZIKsyNFtz$t9l0x71W-PhRNJ~dk~S1mTM-6I zmHtj3%jkeNMMnf|H|`es=vW7LfB;@+`-WBiy6zTGdnm-CalXY-h=Jtm_907hF{S0C zJMr?R8V48{r3da4z^jd0sylC~slDVDgmafcXFH$;1`P*7*J>g-rI!Es#BHn8H!c;q zd%knXstzURhaUc*7lW50JR3U#^s?B9#R_WkR)N+0f{L|R7GEWMu!GSnD@=CV4BJ~` z!6pyK8fQ}k)&{nCLnVcx>*9JRojv1Hxuwpc;YNcBq?A~2jSIe7t2m>{&(W9~3fRrA+zQ zBlg_?-ZQC&OWrhu2O6_qPP*iOoBM(!9Ma(0-gAJMC}4PUl%bC07I)H;RzDS{j~VE__-N!!;Ip$O8^O5%$_ z+hQw1qlUBx(|^0N=_52-ts-e^bU$nl+b+{udfc=aoV*>6%CAGT&8?KhVPk|& zuJfwBom%p)`*4xQUw&6oHs4esEUkB7YNfTc&QU1ulrIz5WDVeF373Bj(r$ZJLy~zf z*UF2CNem)TdraK5`^;+3%F}UUV`Y(&=chr zyQhWJkIL6|S+B*qSt zx+mk1wtZoyL9N#Sw2U+%9-d!SMnDcghKeD=>-T6lWlIg7_W+c(2w@loW&O`NORs}1 zr~sLoQ05BiL;BOe^7RA&sf3#6R_WvFy@wRtaAH;d^_*_2n_lRE(lH9Yi9KBdKMZ@P zUB}}kJPF}eUmMT+M~F?U;3>cA<2t%H1M;4VL4>yY`(R4Xt=`(hk~FfwgEN*z_xiFW~dFO`3 z)F_}`3DfTv9lGD-2>(l)KZ@XRFV$;VF7BR{&Vs z4$x)OI`)o|#B(o*V2F>hq5RNWqMJs)4q$9UABASnNAWxY-`_0of#B(|V(_v-REE|8 zIxTh^-!-2$rv@5gi?kO)f(Xgot(uXLSad1QhfFCb01d4qO^_wCiFz<@ll;hS;nfPu z;-LKA%}=f+_xp{aY$q5uypqL>6|zs-93^ItSLtYt<&N|hPvzO#GRQ*sygxxuqOSoZ zM38~QE*%}e$)ommBLrDAH0OnQivwn;)528fD*c>oQ+#rbqR(!vaS=&AG`-&ksH0vI?~h~GA46J6DvH2NNJ>kMJ7h zaYgqaUH_nfYUJ@ivvyN`j@JS8fq4e1nK25z0R|rPc=7(hb3t39E3tG)gIu&=XqAgS z!ruWOmZWIlc0&U(2zTxxjQn3#EJ=)qYm-~07XoSZk!5im(&VD*isk2s&JX8bPYW5^ZN?c>}V za2=#`Nrr$Ntd9WC@>v{dc6iJf6e)%#9~Y;sF`2?7Y!AF_b@ZR9g$(e6Q@XQ_mC*nW zaa^p%`2~l9Pevm%jP?;nY2O}s;f}7U0Hl7)fMr#}x8iM;^#ogLrj$?}{=)vBzhVLj zZ;B=0ev8t!|9Scq?pe>^+Du|&M-9B^vMJGB%3=Ax#0TaLaO6To;x|E`7zZg4YMB4Bm zsqsFcwp6FV&B@!`Pq>Sf0E!u<9oD4VX=vTCum{_SfHRuIS!^gBPxwgbIeq?|`h<`G zr_D&WCFY{_aofOAFxV^Sqf8X=UV_m6R4aL%<{c29+pD@k8H{Whuizg^5@#iuUMm{} zTsGC+`F!a1qyfSp+eBG;LsI2nelDDkbBoT0t(d+LI$+zVFc(T3*_sbMcWk4_ zB<<#^VHjgd%az?f6V7CrEYKDYtz@N>$X)o&IKaa zbP1kma`A5$9rE%oY<6?l(7OoIJe6o;%K^p^owT7x3CmFU;#<0l0GNvPsLY$C!?>?nDl=Cv_I!8#x3+hZ9>Pl?P7$_Ls_YabjN?U~1M zh7ulWTqy@{f(vZvx|i>d^hwC!Xx+Z{6)Xw?T*~OPAPk;+zf`J~=Tr4E#0_F9s1_xo7tHAib)WW?}3X zZ`G&o>QLB81ZP~#Oghcpw&wtLX!ZdEkl5=pY9^x-iRqM=bQHAsQ;N+TPj?lblDx-h z={l(Al-$_YKrp(3QJ5sMuPhxb7{6+7z8@#7?h>Z;`e=JaW{QHGqu*gdO$o`(3*5;t z#j@1IKWBkK=sbq%DeGQg#m+GsSk>@>pDSjoC9ECxB}NWkd^6EUHW!CNLJoBdS#Ef~ zub2%mysu~-#6R*wKm2Np9x2DRDqVZJk+9P-@nwO_il^fL(exHvadb`F=-?jQgABnT zxVw9R06~KV5ALpmy9Rf6cXuBwKyY_=hcox{e&-MLS~Fd{chzMT*{+g)2QytCf-!{n zJJc_NLkSt!2h~FXXo)Yt;?TJAs%T>UX>|;-TjsI4Fcn2|^Td8;S@p@;@NxTKTp}_& zYbY8mwf&O!EPwO(JUPzIY$OF662HvDMH0+o_)ys(0YXEW(H&SYhn$4}I|}Gf7z>oB znBi&wU@sg2K`i^KpcFf~nQ;z!i)-YA4cUe;pLo5KW!o+#wBz*iSe^UX{#KMYhaWEy z^q@{?de;R(7f0i5dEB~VyH^g|Ah1U^m?u^)Bnno22bVQ#Y<%_VUAvt&Vi z+-8QDX^vT))A&AcYaFaA@uRAeaN+qbQ^n>PNF}%blmajjOqxr%N!=SdqBzAnBW$)( z0Qf;Gs@spZgO4+cQyfGuu<#WmWI{dd52Pf{S(TF;k2U~QCs-D=$=0vCj zzA9fSRsugW_K7Xhh}8G^Io%oDFHeHfLqeh1mI2VZi#l}3!|TF@XKhh)XYH>V*6+e* zumC6--YwfRQWi^%-5Ih zR;~x1iZdSbx(F$2*RSY-u<^Tg{-{N4J!1RolNGPT#A!p&%74G$PGLe36vwk@KcLFn zr{K_dbI(hNg^oo3AhHtoee0dssqd23bY2om;ha&Go(dUXvTSD36&|RA!Xg5)^m`Jk zNx=s@K-Jsxkmtku|G#4Yyspg7COb>1GAKd}`z*w5P5bWAx%G~@-tBpN*q}pa3jayU zU01x@zUARK3RM1r7!4l^3*poQ@Vts8R8xCCpM(2wE;&{gip|sn$YA}bji=joRyKLAmGt*{_*>q>j2>!~?SRaa5_tL-Nm@gSLshm}G1~oX#oHdxmsRfuA2+8i zIlJJWSr^`x?$vwc+z@PI5>LWTLadaV{gd~{WPoF`^+E7|BBcMFYzzQ3J_tAeHW&8- znt=E=8hmw$)7|O#dRTEnz*qcbK%}TX_#{0fV$tSjR~;%l$ON_rz}rCpd8z$5q;kJc zH9y&$|DzaW%?=A#rH68>LIlu~V-h;>1Ob9)-AS;EBETX4c);f}ehoiraiK5QUd%L6 zv2vPiCj^t9NsWO~(?cmH^zaDpntTnEJpzv*Sn$k!Ts?^S@Sn*2e?Z>~RPqobnb
    H|zz{j8vX-lqku;-NW2E3;BMf3f>Jhxt3 zUn;Of^JmnxO!y#JolSAE{{KzOS@_U?xzX3XZ)AAnC6Zyj@U65$nV0}&Px#e=Kv9M{CF8hj1?qT z#4%W;dvYr69aIZ!Wm~jP3pXKbAGrz$wgdwJhDe0EA$Zg~VQ3b#mrw5lI+jKRxMbJsJ(MHn5bJM6MkI&kQpK2r zl7QY8x2rmtkboQ>#>!orWmIL{n};u+e!KJA!jFbv5sXXJo~RsLy43$44c~U>ZwD|0 zrBJfNQ9{T>ix^j1GC@AANyGP1w&B)LQ1*L>?V4udz9r$xT2bZBpC1-5$?qQoXTJ$5M1h8x12XtxewcE3o*YCe z3@cuGizGtNDy)wH!&|ao@hqeu13+E-;IxSbA_ZHIUxI3f=fUBc^og)jitKvD+Rdv;R|6Sil_dmX8Zi*;0lRvh6~>h zR&=uqM<>l#_3>Jz3ys4=6*(r}sVvvna0}BQ3Pk+^$y6cNw0N6cO9(a0>p>zw(-Ok; zi?T90fs3*3$Q{(#6~X;*IjQ8>MHm!vp=K^#w#0gDDTyq?KNlRi=<-d!Qm_?iH&GvBHd~-NZ$2t;VP# zmqNl<2mmc2x1l~&S(82+JNjL&4sD7xK0^F&WL}jcQuYYhhlk|0da|z+&6~)SWe{Md0$g!5xw7_3wbr{ z|7zWR>i^hVu_YxE8v_RJ^1}JEpkv?Q)Q`2p(Gs_ewdjAh78gcGi#v;dCR|LYymrTk z6nqP;%&0y>O8p5F&coY};HqdV%%gL#nd{6}*kwIkPN1R+3c! z(N?0<;{&zWxnY&E;(y|Z7g1SqM4*GO`dy>D9wHuW$tqPc+Bta-QkMdr_T(eF-EI~Z z^*7pADV)sVh>c$rdAMRMNE7%y@um%ys=mhCU6FkPc_p-Z4tBq(%zeVgHdHsBlH7yC zGMzX_24Z%5C}nbw?k{O`R1!;lTMYX2e4CQRg7e!{2FZb-HZt<4qFy!Wh| z-cyEEib(!to)(}Ryp38fue30II_v4Gkt%{n=k8v`T$XDBi-GncX!Ul@5M+_yc|LNX80U~n6FbT{@dY;Z=^ z*_2+l`%~dK;wL5ZFB7q73m96sEnmiIi8naoFmP6y&gi) z+d1?fyoqm!nWxr0tgG)nCr!c_@08&j2Ea(c0SqW$;r!2Sz8%JS2I{{*Z>>qwblzUy z_1pSvIqZ-vmT!bvtv6&rVr=7v6AX&ttP1kv3^#;%BJ=SoA9=FX_vjA^SAaGrNv%Ml2!}GG*4~aHJy&9 zu_Q}RM5OPbu-}&IX=i^!-3BmoKmH?LbGXFW)m#23Ok*C!6l@899DFH;j0g%DdsW?a zWbfDG$;^`&N#7KMiW_D?hh#>d0O1u1Hoeaoj7_>jGhy)uCmO#-5Xtx}T*e<~LwfN%4=h!I=)u8;|dtW>^2^tQL#`Qs+$dgsIA z){?fNY3`4)@1>G$9g(&jUVB5pSPV3OmL9>F_p_mRd}Y@n{eRFUe-Fk$@e$OKN7BD) zP8~u`9ePWH(LG;p(1m$4uq(ojA(Zi5vrX-l7^T{fZ|T?icf)V^3=aa=P-$96&bDg#Oz-@3crcsNlsy74u9ZyJ-U2(?3ocwtdZCG3dx zGNX`i#d}g@P5ASfKJZ=Mh;KH3$8u`RrzXwiA_%o)ueaY^y6r6y4QRQzWiN+z;@NgM zJPlDb^iV*T^1z|#5;FV4?n4K$+$l3DB%|-38L3fZ+uZ!W=J7xh5bWviEwR+?{yR*D zB+^^1eKt}8Pox5iG<&ntljb2tgT%-dUYTwZ2L0e_-twhdZ#Y0Xgt{jw-1raBPkqd% zHM~*zO;c|gI+PmmSR79@HEc!{3Z5o@mtHTNTH5w;#b@8j?x z!;UWcbSTfP`xK#JYK;ye{*0`O(Wsh7n?m3+2 zU@|YaU^+ctdMyr+Sii(ueLGgFK5w?|^foyV;GW;?P^8GgR^)f;;lIdU_jFp%NBXvMka+E}6buIe z5JQ+ZBFEv6r&Vrbo?>$o{S&2ieEUfJIUo0fr~!)Ky-!J4f;Lg1;fg;KC88^b)=s&( z1%Euxy|ijgv)w!;>vuj6>P%KhGo~vU+dmYG;1G$1k)sGs4}mkW@@kdrXgOfxR-q&= z6Dpe7@)_$D!a2gvmu7bT^w+_{Pn)!ymD6WIug&^xKF+~In2E!h$1{0_C5aLYuzn8o zT8*XNTZSVnFsSaQ8}ji71dQ!$-~35yzz}#Fa;o2De~CHehRwV%v2^;JT#qlNz4-;@ z0uSw&y?EOX%;R>Fyi_uyU;swiQvV@K|NTGa<l6)dthJ`ox!o8t!JxWIX+jc`&Le3pv1F4D3J%g4ggh?g2spF(7io2n7IbxLhv2 zG3hrvN@UVlhfm+W~KHsOKgb+&&M5r}ljpPkCZ(dgg z@gbpBO*H?y&woV{v6BF=ychsv6AT~aEg2~Sk=CENVY({RO9n|bF0aRLHwe-PW|{n7 z7@?7miEkk#^R}$lQWru_4g$y{>Vl0LyGIdHRAy_p;FZ>3|Bo(zyeWI9nG2o4&s$|w z*_bq~+&w213;bf%TyzwVaR`70V?&PXM!W0lqrl#DaFc(0+l@(2`65%dOJ`>XEH)3% zf#?K*)rv*kXtHYJoaCZiOogKb^XXj^hM$!n?afdIJd$>?Pc658wL@sGJa~b$`f5tJ z!!ggqN+(O$?d1eQW&|FZBkfx4)EEKtXh{!q;Hg$5p>rY$QXSp9bPTQ)C{RtavO}SA z)Q%JZEIbmfZbsc*F=QY6HqjBM?wE@k?_-sgmYpo~cOH>q zAj2BDbJHNLmYEzN^Tcotj^X&(Hv>o!{Z~V;yjXtUYJ2S~T*(3TTvdyilxeao5tQwe z9H*ac+}r{;)_q<#%^TJEbx12zlV_hMW-A#ytA7f%v<*O;OZfoXY}YQsA3X^GB)iK@ zrg22WR1A6}C)TAygAzRgHGk=G0$LgF*1^9HMlgk6=SLABpR#1RH-_ZCMZJyg4nVv# z%+EyJ{?C~1G9FBwQviFG^5u9y>I^m@(2sG31Ge-yAu1!$L7yc~Nb!dX#V%0b=nAAS z)aDybYPIZT)b0K3s&!|i$g+=LdB z&a{Of%F(gt%k2E#UH{TMYE%xa2@7CkrL}LcL~#(+$Xt|{vxGN8J@ZKK-<>*rOs%IP zcQmgxhx`&+Zz9{5T`je{kaZugmVeLQE z!zdokdP^sdi27Ly4}SlQu`9X+b`x&DJHS>IDjE&*90L&5RCDU7KatP>9Es}nNZ#%F za3$L(>%xVGba&Djyoi3^^?Ixa(*R}7xTu#sn1>_>Olijl7B}Vf{x>PZLey5_!e-Dt zwRLgUT6V}ISmH3^*-#+A8&Wc%u?sJ|YWbpRK4@T>aLUTKMlv_^WYy^x9*1k?Z56l~ zS+aY)B9R}8Drk`=u|qHVmA-oB&@7KmHmUJ*qAe2e>{&Dge%YPv&u5^W3Bc6i{c>}+ zQ;V5-SfU4Pf^wvif?6u9!DvoGD<+rv0pWCsJAi{Fh`^LL0wYQ*+k9K1Kpc?Agm>Ht zke6Yan7HeD4iuy0Csu9qQ_49j_K zdv;(f7uI4Mnd&Al6M%A0{Nam{x;vX8^0QGb(+fN?wc{@ipx41gJ&!lM4smQ2lo1lt zbppW$(_s5gZp%;vCfUxNKmG?79caX&waVv5=6bbzZ5Z0fL@Us4ZW+BkuOY-JzPPy8 zXuB2!gmrn`4HYu43h-p)Vg|qj$SaP*_U(#iJ2_a8yN*1SE{Q?`IPg|L!Z3sS4Qo(7ZkTO-vG9Y!&Kjq(1I(K9ic-1Sq)88U|&Ct9gE z=OrN6gb3Z(wMD=ze`Ne)e1~{~^?$3@X8|Uu5X5POc>23vZ|~hxbQ+rY-xn73I_>=q z%>ji>L)7i)2bt6$JZM8puh#9LpRXfMvH7SD+9HFWot_VQ_uZE?3(G@2CEBzoNHe$l z5zH>ugv9E976cQMen`A?dfybHl(osRcgJ2%E(ub=Pw_p7_T z2tI%3#WU+S7!46y4PHfrwj)+;G9c0vMS^As;uPC0)1T3vmZ;!sKqK-Fpxmsp85Wx? zVVPI_75;64?k>D@i(lCHddptQ%1Efwx#e-0IGL#tQLscpCBSOgomeS$i*qsHRFWFd zzZxoo_DdQn=VC}56*ZUOpQ$UBDPtvWvN0ymsc%R1^)-{Gc$9xxJ5~8s;ERoJ_v>+# zOSdEr1%{ufW`pC>#@G}jvhP1wdCK}tsSNZL^AoJR1T~o5M)+`}^X9PuJ3YuC@bHbX zU{SyAIVc^7JQ1o6E9f9Q_z$d^LEBW9%5^qdn{ccO!V?ds(&Q{H|D@lF?210tt5w&`w)qFn9&xTQ3{W$`=ngAl3Qz{b z22STCU_7NiEHqz`RXX^b+(8&v!xJ)oB)4fBo)pA1ZW9bm39;X4u_^(aB=!#k8y|P0 z^z3z(4bLac-CieHX@TUjdb`p@+++$8hHRjEWvU*?MT?hzhzTOIGK5QDacIF&gh$d# zyOVNt?PW~qC1ElKpnBmPwFM7@%7s7pDSH3b4jBN)9Q)tgg^iC zKe=n#p2CGhH4mb=XK$&8F-ON#PHxzrx-NU0*0N94WF4ZpMql>puf8nV+E%j>t_Yd9 z*}fg&+nm0gaoc)b6;A)g;F8E&l_iMuCtqEwzbQQ?Bc4=x5?0h!Q|CO+?rn3DNjIro zf@V`@f-b*tbU#>ITAgit+uz4^qeB-3`?`?h5# zbve7+^95bcF3kr9iafYQ&-L5fZX$)f30d-i`CCR;uuAuNCjydd3{W%GZ=7^0xpl@WvH>kqpGxq>0uZO{sh+@z>!f}?hzmv`95ivHU3vizB$NIGT^ zAU0kpAUf~0xVL5JpuTi2m_Iul?CfTj;Zg3IhED*!dWf?HWkWl+MXi}F0MB-iu7Q_) z&^4SeE&x$E%R5SdaBXo?Aedd}$0(9oUa+CuKMoloJPu+NQO)vFo0wu-+zoOT>MS;UddIrEFH`Wfc-i=l;Z%&|F9r*6mgD7$nd+EIk=9$H@%TqG za~Q*_Tg0ZrlClylTe3?C!9v@8iwYSh-gY7Qxb@W)l?d#nQQ`&1kRpIp8yveCpMx>U zuDI}Kf4%q1v? zigGaxAK05LMifMdi%VAT2gdQIPKZ@iM1~R*H=aU1{cQEsj3W?>qIU`(idM(GzbzYL zuWe@t)a07`$@V1_Y#2P`A8E))T2#BiJmN-74z3+k120#Xy6p@(DcBNuD42c4LnCbfAh=5`w4_`(s!)_bDx3`SbK}m^Yt%C|H^*Maf~NW(6*8=Z%QjLbu^Rk)bNvI$gR5t?gM%j@J> z)Y9D=qe6>rmH(*gr5<9c=+r|hMwZe25I-gPe7e}+ux>U*>9(72AVrwyjy7CseE^&}#w3lm*wU3*7fj7fc@t8P zn~RJe+?TjIF@w~G%3uPEu7z7hWj_`VdO{G*oUnR8m)oo}7k8`y-)jC-Iiw|d34}*)k zF(ROdmC^_~RZL-}E>6GmkKud0eVc#qaef#@wy9rz5ik(mKaqdk(@ECvHhqBt0>z|c zWa!XbQ!9^smoXql(9XS4o-F<<#hOThwC}O)2<&_c%HZpXsgJvZd>@hQ6o!m9W>|Y$e=%sItUAV;2)Q^Zb^X zw?*E~aHSTZ5Cxv^+vFhDUcZcba`t$ZPfs}6%_f6!zl7h~#1MgjVYv7;sZ4lzT~|S1e^@c?Yrl*^QU{EzR?-XOBv0SfX$f6p02)!|ox0FO!= zC%)I|2r=L-u8Rcd#>n^M#=YilkDbco;Id-2f7V1;^;W1O+soJRV z6=LZnyCWxf(aVz+vhJQd-=-@39l$}T?fd}tFR{||K71xxhs(8=SF2oL7*33du_cJwxfNl1M?6GdZunk3Cc9>5SVHO4T$mlb z4rO`YOrGfb8o5u4=~|4z19{?rGf3QYkyxK1XFq1IovPobammUhMq8U@=-NAYA`|TJ zCBN*EPJE7K{f@jfhc(oKzTRk3`lniW65DpQ@*im=YyIw0+NNE^z8s~>u{f%CcA9x2 zYT&rcNREea*`rYzAv{ZbAdKEfp>c1XD=#0@)KwJox%W=giH2$GnbOxnp%C0Z-EFS7 z8$S1!Z$`IY;{h`X2+$*Vi2`Bdk%;r~4gZ^Dr|3-U;SIoaLx^=#pHNbZ@XY#RHh4d_ zs?PjZiWWx_tOch@_>R(t*AG8o>(M>lI%uYeC+!74`g__n@LEO3N-$?MKlrDvkkbpt&Mri#|&fE!6Udc!T0GY0bS8v z%&FIaD}55I#9z3|1td7Zu=~H$vqp9 zv^r6(cyA8(Nd&YD&u=29Q^VJDNrlEc_pRl7y@aX55*aItfKz{+|4^z47xs#asc+j0 zk2>-lup&i4_#^^@&O4RF-2ABD<@`38j=<*|@HaIm&@I0I!S`tszxgc#GF%}U%z?G> zXX{OSAR9||JWBTgY8}cbe428KY1pH72S`5m@A(M>ickjf7S0~t)lb*>RS=&6dQBn> zFp3)$#L&+670{1*Sz-ew$diZgc{$KQu>%Bcl<2Q}o(Ihrf-Xwj)#tu9lMGS)l**}0 zSjYniIvofUt^hNDC5J%B-S+~I?8$dbuWhB_-()wI9x%jF{| zM9F+>VSZfS-JO*N8cGAOw#A83u^rQer0|_(GiOVIHx;g42Ede$h;OwQjHd*?oYNQV zaGed>>veY+JrG4edq1umPu6arm31M7-g35A@8Bt!R~U>?Ghj6#*Ziaj)9u#%GE;q? zaVx{tD!m)4ZrkZ~c4qsty*38UkZ#x@2g#vT&Mw8j@J6_WP;sV@S}ja$kgQq6g4cg& z4%bFlfLHb>>$;Cq;_xNkr)9WQgY5N*(Sj$sd7rEOC+uAfj+ubkFn`EKkL~`DVd+ki zz039f{CrM<9C;?XLaaHB?^hvA4$8ag@UKpU8Y>*VR?4|i<9b;{1u1s_wjm=t-P9SX!vHqLb9P~cR1A*9u3^{0UXoB&eBGUY;WM3~O^|YwWd`ZD}jO6zxv*8yq z0U<5k<+oKv79G=Q(jBpx3^?FpF|QK^Br%1GSnA%^4wc;}+ z19V$5>7t|CiQ62-VSmDywv%12AAEc+*01PU$2i$1m%3e?pDLO4-OuRr@_`hF28#4U zS)=nbu5^JiY3@o)fW)t!#Rpd zfCYmPbNc0zFYh&~x|~lOb`H?kbF8jfhJ`;4?>%FtC2u8~wp{YBjF~;r=jgiM2!5G2 z)ps|OmbK#Jel($#@O2^X^yMtrQ0Ai=PNH2<;OZbHdzl%z!E@lG(bu-u8SMPW^{ucgwQ}Xrp-VcS2 z(^|C`K`YwHHs}m<;Ok9+0WgO_+rYB@9I_e%4KP&DI!Z*3bI5Bldj39P=AJ%F&cq1~fK)t>c9##9~mA6T`Kq z6oT&AH3k=cbWsk9U!q;$jYrX7UaSj#Ty9UZ{Vncpr@MV1k+fR$ z7?R9CT5X-;T##ZOyz|Pn-r)GQ_;5~Y6dM~q23?2u5My_7$Oz>4 zCZX+n)Of-U1o#>K;~)?a`7p0))fy^@a|*j0N9nkmeaE*wBLfTH5c{Rd_OXD;p>O(T$8~8F2K4wpv^}2@CLnUv8J;bfJf?1m&Ye?RE9Qx_f5QryT>PG3{ z-N3;HH5u%Hh$g(3(2I}Ps}Lo=T5G@Z@yC0OdoxMlK!I18T7`@l=PKXV#T}>cUKoEX zLgh=q^cLa*dwaPk#7fxmr6$8X`{)XaO)S(8>k#T7`r>u_am!*X@^G7I&RA6$lCFe|Y_trnIR>v*t_`%x)NxdfB2?G- zH=&ERBoY;y-gDq{L0(U{0O#N!o;!0igI3Bz!Zv=W{*51Mue~RZ)A9Dky%`JEmOR3J zvzO0kUMJ;?=w=y)xbx{>7rNX&-j7^;t}kUnaAQMvLrtStV{sC7tLnUUgP-6S`b`61 zv(H`A=U_|DKK=_k(0jBzS9^0Td6$3z)WRKM-%ARu6}8c9inJFHl}M~83c@|Bf5_M;$TTeC!t{lcmz$AnLi zuObjb6b*n#8q?9qsKAc*IbJ7Y>y0oRfk2Sfpw({yei!`XVWt-OZ;rX@)W66j_$ZbL z@`2q+j*`2`aL35#Dcs{$G(C{qmE%3 zbwn%AWa~ZOso{D;3KDxTPki$y=gTtq=U9Q<%kF97>JK7=WhgrW(eIMa`HV_gFH>!| zEYl-m;glGN@NLptcRCuT`_~za>%v05PQj$ps_F(x__9QQi8#~Sw`02Tzd82z8$aQY z#CmW-$^5geW$AD?dcwEubTXMzU;vy1Hts_z8l>+NOIkfc2uXs8cnpF4ndN0!XI)&~ zST0`q-^9E>N+z}WBstKP9jVt#MB=ks3#P!Roxk@TP?i3kh6UmbL*wR(8w==_83W-y}elyw^m;e$csC_*g8BP=fSvwy% zVV|AHh+?DC1W_%Ia3*<;^NZKh`WIKU6=Vs2nf}C%?}n#p{$_uS&tiQ|kLHBWu`bW@ zW3m9ZR|j|TD=sezC$CQ`|Fn4a<&9Aa$@k-l3M7a?vj1!@=XKwYZ(ek0o6(S@h|$Gw zhEQlW+8XLAl+FCiQk8HUcfT1?EVl)Q0gWQ@ByS&cV`z|Vl@?lyk}?kPkirv*XvF-7 zt_+ARS4x3m%9?L|t)g_wHx#s)(70eL*!`NXF&%x&AC5MyKq<%?EmmLp~@Z00U9)AKF2wyZjylg#9=TS{m zv1mIR$H}5v5hB{)J>?Z46NEb4nfeNoVo~#r{fpSuE)>=e+$sYMX$eX3^DlX^*2SFd3sLWWw^tH0 zkcDkL^Jm}vkwv+SgD8x(uCy<&G#-?zV$}*F4ip)am8JbW>&R;>rJbK2Ca{mClQWZ^ zhWJv|mo*oQpvuHpFsuBD=_@bhP~d#<3ZE6>fN0eB1G;`O+*wls17fX%D?MXUQmE$5QM2EM1Ad1%Aq=Jp5| zdt+JzWzR#^%fa#mWSNhEgeHoFwhBX34q~Gh(J)lT^@H?A3er%p7{zYBJkN(nB4oZ` z=H?W=-|g9DY_m%WzvC%bT=V5=#aJskYf2u5ANPuN^jFsnYEKbOlq;L{h3a4PxfMy7 zd+l{)X}Gd@r4|KPKE%nq1=16=Vd+uD=B-dF#M1NjNvP`P1J3qk}1i< z=_zMMWsp5CRjeR9uY76gEuqFC`YRg+)Jj{Kx^6l9?tNS9x#ZyDYhWpmEkD(cbg&wr zO^CDHa`AX%@_Ko`nYX8|KG*~-y${romM<>PIeFN!9kMNmkDdR$bRF7;zgu&`j7 zoNuF(E2)>`O!W(9_WD4!_xc-j=fx*D?!7LxU}<`1lFJ;%%~-U3|b!%igJ(`zT&DY`+T@#4~0=W@wJpg^f=AA4VQ6gC4z!_JJxi!&|Hf);Va6zkKrR2@{If! zw}Q~9WF7UlUWDeZmIHoH3Fn`x5pof1yg*>!$ONYgRnLB~%d_~bv=ZR?F?zF@4xgnS zLmW>P#Ux2$7@p3=`0+JOzw63?0ZF`o8^#*UbQH6}<8F_O`#s=$99Cs*-Ly+e-T39H z4fpICs9W&)Vn=qVq6fFjGk_(g4cT844`;P~(aPHT6GBj(R=C&QuTms`46Kc zwzlj#zG4qE*nUFqUgAYA@1^a}VxR5I*wWzVvEU=I&ntG`rbt&w3Q6b#$`;3G);rv` zC-LDKpq53}j?_dE?V5+;VS6*&l^2m`(!$0>DGOqRNXZ0FxoS?1A6fBCv}Uwu!I_`+ zc-*Z*pZl(k3)w-l-|1FW5OeJ*dJZwNG5x@iCD`zS&?4DDBa2zpp z>D<~yze>N?TVM$~>)VDCZpRxZloQu2G*5@(=-Lk$BumJ0GDEGa{lV=sd76;VNp@n= zCFfC>CsT_yf+F9@`x+-jQ#qfixHG>cG-)nwBt1WR;P>2pJ$Vo#(_eX_PD%B3))GL@ zFeO4UVj28*H9t9;q=Vk1knSLzA zvqQLjQFX{hd~zHkO{V0+$4`YMskvLHLc?rQ;Ey5o<69sdwFKsO0=b^An51P6W*K6b zqIfcL2!C^
    %-(a@!i`89VK;?-qg=ZiR0A&pVk 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

    wrV@M0ad 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 literal 0 HcmV?d00001 diff --git a/mobile/assets/splash-icon.png b/mobile/assets/splash-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..03d6f6b6c6727954aec1d8206222769afd178d8d GIT binary patch literal 17547 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 { + const fromShared = context.originModulePath.startsWith(webSrc); + const bare = !moduleName.startsWith(".") && !moduleName.startsWith("/") && !moduleName.startsWith("@web"); + const ctx = fromShared && bare ? { ...context, originModulePath: path.join(root, "index.ts") } : context; + return (defaultResolve ?? ctx.resolveRequest)(ctx, moduleName, platform); +}; +module.exports = config; diff --git a/mobile/package-lock.json b/mobile/package-lock.json new file mode 100644 index 0000000..0561669 --- /dev/null +++ b/mobile/package-lock.json @@ -0,0 +1,6620 @@ +{ + "name": "mobile", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mobile", + "version": "1.0.0", + "dependencies": { + "@expo-google-fonts/dm-mono": "^0.4.2", + "@expo-google-fonts/dm-sans": "^0.4.2", + "@expo-google-fonts/space-grotesk": "^0.4.1", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.19.1", + "@react-navigation/native": "^7.4.1", + "@react-navigation/native-stack": "^7.19.1", + "@tanstack/react-query": "^5.102.8", + "expo": "~57.0.23", + "expo-clipboard": "~57.0.2", + "expo-font": "~57.0.4", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", + "expo-secure-store": "~57.0.4", + "expo-status-bar": "~57.0.1", + "react": "19.2.3", + "react-native": "0.86.3", + "react-native-get-random-values": "~1.11.0", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0", + "viem": "^2.56.5" + }, + "devDependencies": { + "@types/react": "~19.2.2", + "typescript": "~6.0.3" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", + "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-decorators": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.29.7.tgz", + "integrity": "sha512-p+G5BNXDcy3bOXplhY4HybQ1GxH3i2Tppmdm/3epyRu2VgJJZuUlZ61MqRTg582Q7ZLBdP7fePYvsumSEkMxcQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", + "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.29.7.tgz", + "integrity": "sha512-foag0BB37ROhdeIX9O8G0jX7hw0UekJc04cHMrYLOnrErsnBKqJGHJ8eDRpoCFZBvEPPygmmtw4qyU97qa4oOw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.29.7.tgz", + "integrity": "sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.29.7.tgz", + "integrity": "sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-flow": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", + "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", + "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", + "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", + "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", + "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@expo-google-fonts/dm-mono": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/dm-mono/-/dm-mono-0.4.2.tgz", + "integrity": "sha512-loMaZOkQRs1r7yt4rN39zcr9e0J+smwnSx929yuODkuiPfsY4PaW18C9SEZ0BvXfcBKoRhatGoIBl8V2MOYVPQ==", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo-google-fonts/dm-sans": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/dm-sans/-/dm-sans-0.4.2.tgz", + "integrity": "sha512-e/fLH5aCJzkEenz7axvEn8N7IJAKhUwNjIxS75h9j+Ip1M9S7d22M19gJN3A7QW4egVkBJRyQh1hQFhngQn9yA==", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo-google-fonts/space-grotesk": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/space-grotesk/-/space-grotesk-0.4.1.tgz", + "integrity": "sha512-ZVQYw4Ok/pgcSJiufP8oRZE3AVxS9xtmKEUfsurbHkHNdMc/GA1gDXP9G4Cr7KL4KqSc0haexR2TuMigotCn4Q==", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo/code-signing-certificates": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz", + "integrity": "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.3" + } + }, + "node_modules/@expo/config": { + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.9.tgz", + "integrity": "sha512-dmzlKraIFxa7wLwV6K7WzI8jp6QZpW6Mc5mGjLimJUFjzh4uQdYaT3m3plEutM5yxBoBEwqzks7l+I/ljCbxAQ==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.9", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.5", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/@expo/config-plugins": { + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.9.tgz", + "integrity": "sha512-hHgfL1avkCdEvDSw7IwlKwRYYNgcxzbNNMIk6W6lTkJpY0MajinAfeJUS0J+wPCsjUfGbVqOJM+XhPaO5ulUxg==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.5", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, + "node_modules/@expo/devcert": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", + "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==", + "license": "MIT", + "dependencies": { + "@expo/sudo-prompt": "^9.3.1", + "debug": "^3.1.0" + } + }, + "node_modules/@expo/devcert/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@expo/devtools": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-57.0.1.tgz", + "integrity": "sha512-GyUf+wFNkbttaX0jR7MZa9bm77U0IrLg6d2AjpxdyoXw/w4abHoXG0oFufwLMgP9zLTd5+Ct4X/ffNUTnlzZgg==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@expo/env": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.4.3.tgz", + "integrity": "sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" + } + }, + "node_modules/@expo/expo-modules-macros-plugin": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@expo/expo-modules-macros-plugin/-/expo-modules-macros-plugin-0.6.1.tgz", + "integrity": "sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==", + "license": "MIT" + }, + "node_modules/@expo/fingerprint": { + "version": "0.20.13", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.13.tgz", + "integrity": "sha512-h1x+w+JpNRu88a/5SMZRzJs9YDGR/f7R8ApCr7OdenhqmJ00hFxQMzvxajDLL+1P2Y2g/ND0xksusqvBqWSW5Q==", + "license": "MIT", + "dependencies": { + "@expo/env": "^2.4.3", + "@expo/spawn-async": "^1.8.0", + "arg": "^5.0.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "ignore": "^5.3.1", + "minimatch": "^10.2.2", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "bin": { + "fingerprint": "bin/cli.js" + } + }, + "node_modules/@expo/image-utils": { + "version": "0.11.5", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.11.5.tgz", + "integrity": "sha512-KPQBTpmpAfy/Vu9y4wPW808/qtZxjYmyJg8cm2QCPAupp+qEWA3b5zmk0ulOwQ9OgeHxuCPgUqWgkwHFo7UsrQ==", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/inline-modules": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@expo/inline-modules/-/inline-modules-0.1.7.tgz", + "integrity": "sha512-Bz/khd1gIJqDkje7t5ejD5e9jFbm4xEJzWSwRKadRo6gruepbw1xJ3Eb+e58OS8fY1ZNQYjzZbspnuph67sN0g==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.9" + } + }, + "node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/local-build-cache-provider": { + "version": "57.0.8", + "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-57.0.8.tgz", + "integrity": "sha512-SEdE0pAQrr90bRh3MNR0ZuwoIBw390cYdFgbn7Vk0Mtm9EHaBfP7kYj+2hXnXZJgOEm3/JMtfoD3rV7rWA9FGg==", + "license": "MIT", + "dependencies": { + "@expo/config": "~57.0.9", + "chalk": "^4.1.2" + } + }, + "node_modules/@expo/metro": { + "version": "56.0.2", + "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-56.0.2.tgz", + "integrity": "sha512-Ld5AeYMCCDa8bLeWhfuLbZFFjlV3f6ORqyPz2glGh6RltIngMuLf9BTC2yvHFjkKuGxL5SynijmA8xmNNWn5iA==", + "license": "MIT", + "dependencies": { + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5" + } + }, + "node_modules/@expo/metro-file-map": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-57.0.3.tgz", + "integrity": "sha512-1OXy+uPYY5uc7Tm4VBsd2NRn+3wHhqeqNuEO/Xo4kmYgv8FjYgUAc+bUXON9FpC2ikcLn4EVlGM9ce2exx9Mlg==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "fb-watchman": "^2.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "node_modules/@expo/osascript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.7.1.tgz", + "integrity": "sha512-Zn03EX6In7ts2lPUW2ESUSkEhEWQN1qqsiXjadtZMJOuZRkMiAg1ZQHuvz9DjByDWNJ2pBwAGyrts9lj9k389g==", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/package-manager": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.13.1.tgz", + "integrity": "sha512-y/K+CaYYpZpNGZhSX4HyLT/vyIunFjNfyoxNysPBCefeLKI/VCx6f9LNPzrxayr3rCYO5bl9O8H+HRQK265Nkg==", + "license": "MIT", + "dependencies": { + "@expo/json-file": "^11.0.1", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" + } + }, + "node_modules/@expo/plist": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/prebuild-config": { + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-57.0.16.tgz", + "integrity": "sha512-QA8oMZ7y70kjOzw+abhRl9uYC8Nu/abeUTHr0YVxb3pgIC14gc7w543bYtI+5gEDI3q55jKUViIauC76QvZN1w==", + "license": "MIT", + "dependencies": { + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/config-types": "^57.0.2", + "@expo/image-utils": "^0.11.5", + "@expo/json-file": "^11.0.1", + "@react-native/normalize-colors": "0.86.3", + "debug": "^4.3.1", + "expo-modules-autolinking": "~57.0.13", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/require-utils": { + "version": "57.0.5", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-57.0.5.tgz", + "integrity": "sha512-kTAXj9lDFEIPMsbAOGCGbjBbMF0oi7CqkYM79KOX0DDD9wSwXmlKL1z2h8OwsrBf7mbOo2DjlRvZu4BEjrIxGw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@expo/schema-utils": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-57.0.2.tgz", + "integrity": "sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw==", + "license": "MIT" + }, + "node_modules/@expo/sdk-runtime-versions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz", + "integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==", + "license": "MIT" + }, + "node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/sudo-prompt": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/@expo/sudo-prompt/-/sudo-prompt-9.3.2.tgz", + "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==", + "license": "MIT" + }, + "node_modules/@expo/xcpretty": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.5.tgz", + "integrity": "sha512-J3eL4n4h5QTwfD0SIz8OIk6/+sOL/hFZAMacgCM07UNlxBQfJipEpIC2AQxvGkbYeStByJ0TVhQAJo+DeNgaSQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "chalk": "^4.1.0", + "js-yaml": "^4.1.0" + }, + "bin": { + "excpretty": "build/cli.js" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", + "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", + "license": "MIT", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.86.3.tgz", + "integrity": "sha512-TDhgCZA4wjJg84d5A9swiOQYPIWSKEEVdg9IwMFZDupQzW/F3QoLUrfAJOcalgqTDA9/buTB8awhE3Whwg6u9Q==", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.86.3.tgz", + "integrity": "sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.86.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", + "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/hermes-estree": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", + "license": "MIT" + }, + "node_modules/@react-native/codegen/node_modules/hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.86.3.tgz", + "integrity": "sha512-qSDL9LQc5mZSZPNczT95WU9YQuPzxBklgON9vLhhqfI0yWIwKInqFx88dQ/uiEXBtf0yossthaQIqA4Ml6bF6g==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.86.3", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.84.3", + "metro-config": "^0.84.3", + "metro-core": "^0.84.3", + "semver": "^7.1.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.86.3" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.86.3.tgz", + "integrity": "sha512-TQmeofQ0PcuylhhlleOeuzHYZfbrgm3gayXzowqUEzgRisTm1D40/J3ggqs7XkQi5HP5ZA3n8dHmKL9vIzPcsw==", + "license": "BSD-3-Clause", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/debugger-shell": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.86.3.tgz", + "integrity": "sha512-O4ds+J7xZfxkbih9T+cAGegBdvKSPKYJm/lDgC9CpEjFMkmzWTpVLU3Qsv9sqZuo58z+sGhIcJfPsCFFWHpqbQ==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.86.3.tgz", + "integrity": "sha512-LiEPTqTg/63bYUnrPyHLfjTDCNhA/+CUqI1+DsA9tYyewtSbULd5awsva6SgE10I+2iMhgKXS3ymkhU/kSCrGA==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.86.3", + "@react-native/debugger-shell": "0.86.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.3.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.86.3.tgz", + "integrity": "sha512-lxmx0GqLEWRIpZfpYFXlYVIs3ENQwaW6Vmp6oi29l2GoQJ1wZfFZRdMimDWlGEk8LKfHar3QH3iaPMkTcK9lEQ==", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.86.3.tgz", + "integrity": "sha512-eYIJ0es967+tePBFQDnl/gidVFxLns3fnbiK6rxscQrGodvuUO6hwxpQnfNynJ8MjbbndImXihXjcnJdc7SzJg==", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.3.tgz", + "integrity": "sha512-Cv3CDkprb67GrzuaS9BGbBJC/6G4lIw3nyKOHRKTqTTum4bn37y5+R0Z04L8mcbQN85eEohNrRwb7IOM4j6uvg==", + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.86.3.tgz", + "integrity": "sha512-1j44NEyNn05Ut40vHAmoSWbsIcybFkMAOBTwQt1PrESyfSS+qBoyU1LGIogNva0VIa0rQyEC5PzbA7R4/7Nhyw==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "0.86.3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.19.1.tgz", + "integrity": "sha512-LE4CFDkwVQ1H+0CMTdanFJkXlgy4xaYoZMFrwS65iyMPDGfNBnGrqrNcn7nCiYWbodG2bYSbFmXlEyRE+Qh2xw==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/core": { + "version": "7.22.1", + "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.22.1.tgz", + "integrity": "sha512-6JAaYM4u6RPtVMUjN5ovX5DNBdBZtDqebk7kEwlncUP6fP4P94+qEYv1bRmtxSFs7UxiZwQQs+jzTsBaW2WeyA==", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.6.4", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "license": "MIT" + }, + "node_modules/@react-navigation/elements": { + "version": "2.9.42", + "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.42.tgz", + "integrity": "sha512-3U1ZmXXoSrJEex+f8I4sRAzVL0OwLpgTEzORgjQGExWLjGrvn7QofK8cjNgBQHjRiTTQXAl8QMZvrdejg7yJAA==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.4.1.tgz", + "integrity": "sha512-pEnu5XzAXV6RWr6A6pmZ7qLB+O6TJWMhBO25AjckMdr596UWulMPHQCtBcnOUfg6K+2h9ZUctHF2E5Xu4vcOrQ==", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.22.1", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "standard-navigation": "^0.0.8", + "use-latest-callback": "^0.2.4" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/native-stack": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.19.1.tgz", + "integrity": "sha512-YB3DLKXe1CLZAtJWgH/F3M5fWRALm1VbgVm91FppGYqPYfVZrD7mJaINaif2RIC4sZW7BziCE57IZ68vlINdkg==", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0", + "warn-once": "^0.1.1" + }, + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.6.4.tgz", + "integrity": "sha512-GI7eJm8/KsZUQaYcXvEExikKurRZRgEsSzyZ7faENfi65yqJBCXjDMwyN1pF6pNW1MoLH1ErDwDivFxY6BzD3w==", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11" + } + }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "license": "MIT" + }, + "node_modules/@tanstack/query-core": { + "version": "5.102.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.8.tgz", + "integrity": "sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.102.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.8.tgz", + "integrity": "sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.102.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "22.20.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.3.tgz", + "integrity": "sha512-DZmzkmwHzXrLPAXPyKNDzlIwMMUZCVacoD25ywdy5YTKGbOx/2ld+Q38Im2zJ0vBuZP5Prd3VZutKZyXwkOS8A==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", + "license": "ISC" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abitype": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", + "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-cli-detector": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.7.tgz", + "integrity": "sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==", + "license": "MIT", + "bin": { + "agent-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", + "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/babel-plugin-react-native-web": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.2.tgz", + "integrity": "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.0.tgz", + "integrity": "sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", + "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.24", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.24.tgz", + "integrity": "sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", + "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", + "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", + "license": "MIT", + "dependencies": { + "stream-buffers": "2.2.x" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", + "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", + "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz", + "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "destroy": "1.2.0", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", + "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dnssd-advertise": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/dnssd-advertise/-/dnssd-advertise-1.1.6.tgz", + "integrity": "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.429", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.429.tgz", + "integrity": "sha512-/1ENIE3cx4HTIx4IfPZFaOunJmsrSVTnj6coXoRVbiJUbkeTyFkJvBeWGkdgh08OhFbxYLMT1kbkwFVSarq6Ow==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/expo": { + "version": "57.0.23", + "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.23.tgz", + "integrity": "sha512-/aBLZFTD7+BNHWV/q5XbNRFqMhW/CrHsYeq8CcS/iGz6lJHYwEMm4XFcdoaeliuMdo6ZjNrsTHkBIdGB8VMHTg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "^57.0.25", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devtools": "~57.0.1", + "@expo/dom-webview": "~57.0.1", + "@expo/fingerprint": "^0.20.13", + "@expo/local-build-cache-provider": "^57.0.8", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~57.0.12", + "expo-asset": "~57.0.17", + "expo-constants": "~57.0.18", + "expo-file-system": "~57.0.7", + "expo-font": "~57.0.4", + "expo-keep-awake": "~57.0.2", + "expo-modules-autolinking": "~57.0.13", + "expo-modules-core": "~57.0.18", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-minimum": "^0.1.2" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-web": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-native-webview": { + "optional": true + } + } + }, + "node_modules/expo-clipboard": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.2.tgz", + "integrity": "sha512-VB4Au8X/RbvJKUtJk+87vdtveWSNEa5RzY3ooeO6VNF7Rd49RbQXZOu3/TfEW9p7mU8TCfyTvjyCiAUwSoSJ4w==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-font": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.4.tgz", + "integrity": "sha512-7WOMC2oA6xCfOm8bbofqWn2bIqyWFm7YLEnpc/gA1MJH0Ll0TfT/3+CqRkoW2eNRWMS8sxrz5WukUmSvmNquHA==", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-linking": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.10.tgz", + "integrity": "sha512-RzRi4l4pIYzjgoCJKnqkO+lUI+M2YX6qgcMIQkIbLAXdcWrykBoKYwHGlmAkdFHQm89GaYcq329yfxG+c1hv8w==", + "license": "MIT", + "dependencies": { + "expo-constants": "~57.0.18", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-linking/node_modules/expo-constants": { + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", + "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", + "license": "MIT", + "dependencies": { + "@expo/env": "~2.4.3" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-local-authentication": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-57.0.3.tgz", + "integrity": "sha512-1oQCBKz8JOpai+Zp+Z2RkBFIi2CHHWLSJk/pjvT9VEyf8nPFslo4kt1ZlQvtJ4rupbKNCmxqKfYr8Mlo8nJEug==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-autolinking": { + "version": "57.0.13", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.13.tgz", + "integrity": "sha512-Hj5NjZRlfccazhKab+wK19leRVUr1Y/PUERaRvegIbUSkq4GVxKq6lU9QHlKQyC16MdD/VS4iwsiLivB4o7lvQ==", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.1.0", + "commander": "^7.2.0" + }, + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + } + }, + "node_modules/expo-modules-core": { + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.18.tgz", + "integrity": "sha512-ovB7C+GVQTlKAOIsOIHJVVXN9Mn0ljf2SYBS+afrRaGqq+HZEn1D3o+HReIVeH1NjCn/xDBb7I4HjldHs6luZA==", + "license": "MIT", + "dependencies": { + "@expo/expo-modules-macros-plugin": "0.6.1", + "expo-modules-jsi": "~57.1.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" + }, + "peerDependenciesMeta": { + "react-native-worklets": { + "optional": true + } + } + }, + "node_modules/expo-modules-jsi": { + "version": "57.1.0", + "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.1.0.tgz", + "integrity": "sha512-a5ckeHfnbYfonhcHGkM0EU/a0Keh+/OufXy/HyFS+spr5Ib0N4Oh1ZsSYFQhp5xdOUFkVofKRhfH+VmcccIIpA==", + "license": "MIT", + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/expo-secure-store": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-57.0.4.tgz", + "integrity": "sha512-7zBA1RThURTXdP4w65kBzZNbcSsfArqVd+p+ETAnPRWXO8J296Qd0YaCVyRpJ0HSwlCnGdvOnqO+NgSreHsOhA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-server": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-57.0.3.tgz", + "integrity": "sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==", + "license": "MIT", + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/expo-status-bar": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-57.0.1.tgz", + "integrity": "sha512-Xwaq1gAoVRWx5dPG5VhT5RSbnI9OilhZnO5qoPBnUaBAa5VzRzfdS8q0/bsPt0jR2DKLtGuP0bQ6efMJ4RIMDg==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/cli": { + "version": "57.0.25", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.25.tgz", + "integrity": "sha512-G2FJfwClIPNPhH2sJlIFAkhQLYaKNGzSarIQUl6sVA8oGdrmBnhRvbtTzxDzjS6WzO2aDX8DY7y1aNbCFILodg==", + "license": "MIT", + "dependencies": { + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.4.3", + "@expo/image-utils": "^0.11.5", + "@expo/inline-modules": "^0.1.7", + "@expo/json-file": "^11.0.1", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@expo/metro-file-map": "^57.0.3", + "@expo/osascript": "^2.7.1", + "@expo/package-manager": "^1.13.1", + "@expo/plist": "^0.8.1", + "@expo/prebuild-config": "^57.0.16", + "@expo/require-utils": "^57.0.5", + "@expo/router-server": "^57.0.10", + "@expo/schema-utils": "^57.0.2", + "@expo/spawn-async": "^1.8.0", + "@expo/ws-tunnel": "^2.0.0", + "@expo/xcpretty": "^4.4.4", + "@react-native/dev-middleware": "0.86.3", + "accepts": "^1.3.8", + "agent-cli-detector": "0.1.7", + "arg": "^5.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "dnssd-advertise": "^1.1.4", + "expo-server": "^57.0.3", + "fetch-nodeshim": "^0.4.10", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.2.1", + "multitars": "^1.0.2", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^4.0.4", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "resolve-from": "^5.0.0", + "sandbox-cli-detector": "^0.2.0", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "terminal-link": "^2.1.1", + "toqr": "^0.1.1", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1", + "zod": "^3.25.76" + }, + "bin": { + "expo-internal": "main.js" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-57.0.10.tgz", + "integrity": "sha512-8rGh6N5di7jzu7UC1SuIA1TWmVd+vBwOHwC7/1ww+FA6CcxcWyQlcPl39h2+Jpnul78CVzWpIjOcdKsZsp2zXw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "@expo/metro-runtime": "^57.0.15", + "expo": "*", + "expo-constants": "^57.0.18", + "expo-font": "^57.0.4", + "expo-router": "*", + "expo-server": "^57.0.3", + "react": "*", + "react-dom": "*", + "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" + }, + "peerDependenciesMeta": { + "@expo/metro-runtime": { + "optional": true + }, + "expo-router": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/dom-webview": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-57.0.1.tgz", + "integrity": "sha512-lAKsME4SAq+8sf56oN0DX5TBYyruupoRxbWbD2xf9RnKY8y6x8eb9LCE5pxSN0qyWdqnp+0wmyWzDkKboThKAw==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/log-box": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-57.0.4.tgz", + "integrity": "sha512-IxwS9s1L2muj8mj8AQSuiy7u8OFJdc02NRFo2me/Tj6DiaeG5SREqmpBE4rQpR2cadqSg5jl8Qab8Cjie616dg==", + "license": "MIT", + "dependencies": { + "@expo/dom-webview": "^57.0.1", + "anser": "^1.4.9", + "stacktrace-parser": "^0.1.10" + }, + "peerDependencies": { + "@expo/dom-webview": "^57.0.1", + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/metro-config": { + "version": "57.0.12", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-57.0.12.tgz", + "integrity": "sha512-S62Lrq35HZqBFD55423pmWb8PjaiR/W02zQC1uECBmw1vTN8WZaFz4TJ0i21EeJzwfebMb9MLxL8JZ102Z6VbA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~57.0.9", + "@expo/env": "~2.4.3", + "@expo/json-file": "~11.0.1", + "@expo/metro": "~56.0.2", + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.36.0", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/ws-tunnel": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-2.0.0.tgz", + "integrity": "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw==", + "license": "MIT", + "peerDependencies": { + "ws": "^8.0.0" + } + }, + "node_modules/expo/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/babel-preset-expo": { + "version": "57.0.12", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.12.tgz", + "integrity": "sha512-rrZqJPYbVevy7rqibJZQFd3AsleGslJ63vmB3Qs8b5poOO5AHaehUGbZHjb0HoOZO59d86BEifYbq0/ncoM2UQ==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^57.0.19", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expo/node_modules/expo-asset": { + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.17.tgz", + "integrity": "sha512-qSdWZBSfEg06o3GJMwcj36tw0vXkB6eYjqkQistWmyJkHxhUOKnsKJnev6OraXxLdoI+KOd1+qgp/ENx8gcqYA==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-constants": { + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", + "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", + "license": "MIT", + "dependencies": { + "@expo/env": "~2.4.3" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-file-system": { + "version": "57.0.7", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.7.tgz", + "integrity": "sha512-1vkZRadOsIputFDBcclqBa1pO3iXOO6iIsdqJipQWw4V5TSnWgmRTuOF7ro8IzrVue+PHbum++KCG3Tawem4cg==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-keep-awake": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.2.tgz", + "integrity": "sha512-GqgH746wtJImmsbyHmCQoi7cOslKuWQBbJHXr53S35Bpf5UvxCAztvnitUEd7D0QvFN2rvkOhylbZpgZZfBLlQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "node_modules/expo/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "license": "MIT" + }, + "node_modules/expo/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "node_modules/expo/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/expo/node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0" + }, + "node_modules/fast-base64-decode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", + "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", + "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fetch-nodeshim": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/fetch-nodeshim/-/fetch-nodeshim-0.4.10.tgz", + "integrity": "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", + "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", + "license": "BSD-2-Clause" + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-compiler": { + "version": "250829098.0.17", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.17.tgz", + "integrity": "sha512-qG1PXzTEtriF6oQLZF3vyHhSMxOdW5h2TqqLri0rdpstPustd2fSvRZQMVAPdlhgFwBfYnj3OUZtiO6LjYsEFw==", + "license": "MIT" + }, + "node_modules/hermes-estree": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jimp-compact": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", + "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lan-network": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.1.tgz", + "integrity": "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==", + "license": "MIT", + "bin": { + "lan-network": "dist/lan-network-cli.js" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/metro": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.5.tgz", + "integrity": "sha512-r1liLkyFZMVSEMNjU1CJU5pRzs3NdkxHqXS60O25c0rCIqAR+cGk7rPydw/g0WAIKVXojIBIF45yYBPagJGcgw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.35.0", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.5.tgz", + "integrity": "sha512-2WbHILKMiJUzfdjmGOQOqU1bWi9//gqiclc/tkk/AIsrrVw3efhZ1uhkOwMTxUEPOzqoo091H0olLmVZH5FHGQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-cache": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.5.tgz", + "integrity": "sha512-WHS0n2OxQqtwEjSeQFPePNrMvEFhmQcUQM9cRJMHByWoi/GMWFBEWOf7hVkAM/0KRutAXNbDlSu/cZB6CyxgQQ==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.84.5" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-cache-key": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.5.tgz", + "integrity": "sha512-3dPB2TnvGjjf0/9O7AXVQURKXuQNauTZE7WpTGTlR017Gh/B5y0m/2wcqxfveUguHSpu89KhVxCAlr2k/H7uhQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.5.tgz", + "integrity": "sha512-zie+uN6oohscowi2S7ByU+wUw6CrT4ZxW9uAbONOObSxx86RGmnIAmjXHLkfmcdYoY7jzOPEbqcI6oeVmqyBQA==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.5", + "metro-cache": "0.84.5", + "metro-core": "0.84.5", + "metro-runtime": "0.84.5", + "yaml": "^2.6.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-core": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.5.tgz", + "integrity": "sha512-xwm605hCi5Y6eJTTb8ZWo6pkUcoBEIyiQOfkZh5GwtDwUrP9SNhTQZhzJHrBCwwxlf3Ptl/pxWJgQ1rsNYMnrA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.84.5" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-file-map": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.5.tgz", + "integrity": "sha512-mlm/JL8toSbSc2akpKIGmzvrVRSCgZ5vkbycI34oMLoOnLGuLyC8WTyVJ6P0hZG/usDaGwZSl/s9BCRriqjGJA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.5.tgz", + "integrity": "sha512-BJoFwCEDsYnagPqarayInv2+diCDNDdLlaof/p6s9w4gh+gc9HXYM+pDvsKGKKUumpZswNF3Z/ftTMqKl/5IBg==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-resolver": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.5.tgz", + "integrity": "sha512-VSSnepg1k6LyCwtb6eirWdAWlpKwBG8Rdtsr1mU38rMelFyWgh3/QuMSiZIZAIjwg/fsa8GhW5/FO54CAUPCEA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-runtime": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.5.tgz", + "integrity": "sha512-U1m2+d1Pr+JO2/iVXBB2OfXXityz7tqwIorxfrT15IEgaHvpJBq/OHiqnOWPKJbUl3JcxjcdviZZOKk85oK4Qg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-source-map": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.5.tgz", + "integrity": "sha512-2BtV5L9uPc49F13Gn5wiP6bX/EncqzqTIk2VL/0F/96Vo0YEOjluT/qktQjFODfqGFsucwnh5mPEAl/2jVEfeg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.84.5", + "nullthrows": "^1.1.1", + "ob1": "0.84.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.5.tgz", + "integrity": "sha512-rQ40zYDAkaWBN9yvjUuAD0ZpzBMZSoKyGYXnb5JrfbKjun7fTvfoLHL3KXFYenBTYZkQtlp4cKSCv/1utxFyOw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.84.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.5.tgz", + "integrity": "sha512-+InaSVGaOyt0DyRo4Y/zIdPI6CZwnbNho5LAL23tgmuGwv7fyfkF7kKfPjZcfxXBcoYdTLLFnCfCH/dHSiCqNg==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.5.tgz", + "integrity": "sha512-ui1Z8x4s5RL36gMmKLaMMO7O9NNDHNdthEZSCDQHAau3JcAsTaFOK6I+2q4I/kW5u8hSEjJk9L45TXSVJw6g1A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-source-map": "0.84.5", + "metro-transform-plugins": "0.84.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multitars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/multitars/-/multitars-1.0.2.tgz", + "integrity": "sha512-6GwVw5eLi9sThdtlS4PKwC7yRLaf45pYhIEzKBHdKxi+YOXGKFX8acIniH+Uh/+k9mS2lQOupTccjoe5r0/1IQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.55", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", + "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.5.tgz", + "integrity": "sha512-aH9RkoZc7w/90HBamFxTw8ZLFr05wXS+iOnvmrgo53Ep8Pyrm5FieQSaPIVROkfFVQISeD/zo92fes26TOwe+A==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/ora/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ora/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ox": { + "version": "0.14.44", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.44.tgz", + "integrity": "sha512-O54qXXHEk4ySamMSyBpI0AeBegS5frxU6+LA6Jb9Sf6kMOxcTNaxYmwZfpOu22DIQsdKfgQxHq8EsAGaoBQScA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.2.3", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/parse-png": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz", + "integrity": "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==", + "license": "MIT", + "dependencies": { + "pngjs": "^3.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", + "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.9.10", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/plist/node_modules/@xmldom/xmldom": { + "version": "0.9.12", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz", + "integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==", + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-freeze": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", + "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.86.3.tgz", + "integrity": "sha512-JR5s3bM9ezud+Mw24GlNXNfthqPIKwrQgPPJcam+L97t2sKjjEavhCzBn+fyqZZRcM5+XlhYxpTxVkK7e1n38Q==", + "license": "MIT", + "dependencies": { + "@react-native/assets-registry": "0.86.3", + "@react-native/codegen": "0.86.3", + "@react-native/community-cli-plugin": "0.86.3", + "@react-native/gradle-plugin": "0.86.3", + "@react-native/js-polyfills": "0.86.3", + "@react-native/normalize-colors": "0.86.3", + "@react-native/virtualized-lists": "0.86.3", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-plugin-syntax-hermes-parser": "0.36.0", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "hermes-compiler": "250829098.0.17", + "invariant": "^2.2.4", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.84.3", + "metro-source-map": "^0.84.3", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.27.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", + "whatwg-fetch": "^3.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native/jest-preset": "0.86.3", + "@types/react": "^19.1.1", + "react": "^19.2.3" + }, + "peerDependenciesMeta": { + "@react-native/jest-preset": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-get-random-values": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz", + "integrity": "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==", + "license": "MIT", + "dependencies": { + "fast-base64-decode": "^1.0.0" + }, + "peerDependencies": { + "react-native": ">=0.56" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz", + "integrity": "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.26.2.tgz", + "integrity": "sha512-2XnWsZToKj76trGtEZzx5ELD/qOICFEprEeUntImmitQFVUkea27fiWdUSITArI356Y1qynpXZINW+Unbhky/A==", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", + "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-workspace-root": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.1.tgz", + "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sandbox-cli-detector": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sandbox-cli-detector/-/sandbox-cli-detector-0.2.0.tgz", + "integrity": "sha512-4lyHX0ZU0AZKwjgZ1InxZAa3PNpyEb8rOQ+Zss1ReYmhNzW0Q+h1zE5nvniXN0HaAWZaZE1zgVNEirb0R7LmNg==", + "license": "MIT", + "bin": { + "sandbox-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sf-symbols-typescript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz", + "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-plist": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", + "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", + "license": "MIT", + "dependencies": { + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slugify": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", + "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-navigation": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.8.tgz", + "integrity": "sha512-TyVbo7INUDWtsUWDFn8RR7kwR87U0S4xHfLfbbnyeC581TmmyqQ+eM+nPw8rQTSD8QitRVcYfPaSHr/QJiUy1g==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", + "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/structured-headers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", + "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toqr": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/toqr/-/toqr-0.1.1.tgz", + "integrity": "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==", + "license": "MIT" + }, + "node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-latest-callback": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", + "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", + "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/viem": { + "version": "2.56.5", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.56.5.tgz", + "integrity": "sha512-GuEf/oee0PHgy4D6JIA8u0rY1g+sM5nF+p7HyMHO3vjlHC5G/ljfrgnUOnrES9m5Ny/P3RwWCHjDuN2T6HUWzQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.2.3", + "isows": "1.0.7", + "ox": "0.14.44", + "ws": "8.21.0" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/whatwg-url-minimum": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.1.2.tgz", + "integrity": "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xcode": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", + "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", + "license": "Apache-2.0", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", + "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", + "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/mobile/package.json b/mobile/package.json new file mode 100644 index 0000000..46f9a51 --- /dev/null +++ b/mobile/package.json @@ -0,0 +1,39 @@ +{ + "name": "mobile", + "version": "1.0.0", + "main": "index.ts", + "dependencies": { + "@expo-google-fonts/dm-mono": "^0.4.2", + "@expo-google-fonts/dm-sans": "^0.4.2", + "@expo-google-fonts/space-grotesk": "^0.4.1", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.19.1", + "@react-navigation/native": "^7.4.1", + "@react-navigation/native-stack": "^7.19.1", + "@tanstack/react-query": "^5.102.8", + "expo": "~57.0.23", + "expo-clipboard": "~57.0.2", + "expo-font": "~57.0.4", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", + "expo-secure-store": "~57.0.4", + "expo-status-bar": "~57.0.1", + "react": "19.2.3", + "react-native": "0.86.3", + "react-native-get-random-values": "~1.11.0", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0", + "viem": "^2.56.5" + }, + "devDependencies": { + "@types/react": "~19.2.2", + "typescript": "~6.0.3" + }, + "scripts": { + "start": "expo start", + "android": "expo run:android", + "ios": "expo run:ios", + "web": "expo start --web" + }, + "private": true +} diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx new file mode 100644 index 0000000..1e0b866 --- /dev/null +++ b/mobile/src/components/ui.tsx @@ -0,0 +1,163 @@ +import * as Clipboard from "expo-clipboard"; +import { useState, type ReactNode } from "react"; +import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { short } from "@web/lib/format"; +import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; +import type { TxState } from "../hooks/useTx"; +import { C, F, R } from "../theme"; + +export function Screen({ children, title, sub, right, refreshControl, scroll = true }: { children: ReactNode; title?: string; sub?: string; right?: ReactNode; refreshControl?: ReactNode; scroll?: boolean }) { + const insets = useSafeAreaInsets(); + const head = title ? ( + + + {title} + {sub ? {sub} : null} + + {right} + + ) : null; + if (!scroll) return {head}{children}; + return ( + + {head} + {children} + + ); +} + +export function Card({ children, title, action, style }: { children: ReactNode; title?: string; action?: ReactNode; style?: StyleProp }) { + return ( + + {(title || action) && ( + + {title ? {title} : } + {action} + + )} + {children} + + ); +} + +export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNode; mono?: boolean; last?: boolean }) { + return ( + + {k} + {typeof v === "string" || typeof v === "number" ? {v} : v} + + ); +} + +type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent"; +const TONES: Record = { + ok: { bg: C.successBg, fg: C.success }, + warn: { bg: C.warningBg, fg: C.warning }, + bad: { bg: C.errorBg, fg: C.error }, + info: { bg: C.infoBg, fg: C.info }, + neutral: { bg: C.panel2, fg: C.text2 }, + accent: { bg: C.accent, fg: C.onAccent }, +}; +export function Badge({ tone = "neutral", children }: { tone?: Tone; children: ReactNode }) { + const t = TONES[tone]; + return {children}; +} +export const TierBadge = ({ tier }: { tier: Tier }) => {TIER_LABEL[tier]}; +export const ModeBadge = ({ mode }: { mode: Mode }) => {MODE_LABEL[mode]}; +export const StatusBadge = ({ status }: { status: Status }) => {STATUS_LABEL[status]}; +export const TrustBadge = ({ trust }: { trust: Trust }) => {TRUST_LABEL[trust]}; + +export function Button({ children, onPress, kind = "primary", disabled, loading, style }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; style?: StyleProp }) { + const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.panel2 : "transparent"; + const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; + return ( + [s.btn, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, kind === "secondary" && { borderWidth: 1, borderColor: C.border }, style]}> + {loading ? : {children}} + + ); +} + +export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { + return ( + + {label} + {children} + {hint ? {hint} : null} + + ); +} +export function Input(props: TextInputProps & { mono?: boolean }) { + return ; +} + +export function Segmented({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { + return ( + + {options.map(([v, label]) => ( + onChange(v)} style={[s.segItem, value === v && s.segOn]}>{label} + ))} + + ); +} + +export function Address({ value, full = false }: { value: string; full?: boolean }) { + const [copied, setCopied] = useState(false); + return ( + { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8}> + {full ? value : short(value)}{copied ? " ✓ copied" : ""} + + ); +} + +export function Notice({ tone = "info", children }: { tone?: Tone; children: ReactNode }) { + const t = TONES[tone]; + return {children}; +} + +export function TxStatus({ state }: { state: TxState }) { + if (state.phase === "idle") return null; + if (state.phase === "error") return {state.message}; + if (state.phase === "done") return Confirmed onchain · {short(state.hash, 6)}; + const msg = state.phase === "auth" ? "Waiting for authentication…" : state.phase === "simulating" ? "Checking the transaction against the vault's policy…" : "Waiting for the block…"; + return {msg}; +} + +export function Empty({ children }: { children: ReactNode }) { + return {children}; +} + +export function Tape({ running = false }: { running?: boolean }) { + // Caution-tape band: the brand's signature, drawn as alternating blocks. Static on native; `running` is reserved for Lockdown. + return ( + + {Array.from({ length: 30 }).map((_, i) => )} + + ); +} + +export const s = StyleSheet.create({ + screen: { flex: 1, backgroundColor: C.canvas }, + head: { paddingHorizontal: 16, paddingBottom: 10, flexDirection: "row", alignItems: "flex-end", gap: 12 }, + h1: { fontFamily: F.display, fontSize: 28, color: C.text, letterSpacing: -0.5 }, + sub: { fontFamily: F.body, fontSize: 14, color: C.text2, marginTop: 2 }, + card: { backgroundColor: C.panel, borderRadius: R.lg, padding: 16, marginBottom: 14 }, + cardHead: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }, + cardTitle: { fontFamily: F.displayMedium, fontSize: 17, color: C.text }, + kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 10, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + kvK: { fontFamily: F.body, fontSize: 14, color: C.text2 }, + kvV: { fontFamily: F.bodyMedium, fontSize: 14, color: C.text, textAlign: "right", flexShrink: 1 }, + badge: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: R.sm, alignSelf: "flex-start" }, + badgeText: { fontFamily: F.bodyBold, fontSize: 12 }, + btn: { height: 46, borderRadius: R.md, alignItems: "center", justifyContent: "center", paddingHorizontal: 18 }, + btnText: { fontFamily: F.bodyBold, fontSize: 15 }, + label: { fontFamily: F.bodyMedium, fontSize: 13, color: C.text2, marginBottom: 6 }, + hint: { fontFamily: F.body, fontSize: 12, color: C.text3, marginTop: 6, lineHeight: 16 }, + input: { backgroundColor: C.panel2, borderRadius: R.md, paddingHorizontal: 12, height: 46, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, + seg: { flexDirection: "row", backgroundColor: C.panel2, borderRadius: R.md, padding: 3, marginBottom: 14 }, + segItem: { flex: 1, height: 36, alignItems: "center", justifyContent: "center", borderRadius: R.sm }, + segOn: { backgroundColor: C.accent }, + segText: { fontFamily: F.bodyBold, fontSize: 13, color: C.text2 }, + addr: { fontFamily: F.mono, fontSize: 13, color: C.text }, + notice: { padding: 12, borderRadius: R.md, marginTop: 10 }, +}); diff --git a/mobile/src/hooks/useTx.ts b/mobile/src/hooks/useTx.ts new file mode 100644 index 0000000..3031b17 --- /dev/null +++ b/mobile/src/hooks/useTx.ts @@ -0,0 +1,63 @@ +import * as LocalAuthentication from "expo-local-authentication"; +import { useCallback, useState } from "react"; +import { createWalletClient, http, type Abi } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { arkDevnet, ARK_DEVNET_RPC } from "@web/config/chain"; +import { describeError } from "@web/lib/errors"; +import { publicClient } from "../lib/client"; +import { useStore } from "../state/store"; + +export type TxState = + | { phase: "idle" } + | { phase: "auth" } + | { phase: "simulating" } + | { phase: "mining"; hash: `0x${string}` } + | { phase: "done"; hash: `0x${string}` } + | { phase: "error"; message: string }; + +/** + * Sign with the device key. Order: biometric gate, simulation (so a policy refusal reads as plain language before + * anything is signed), sign and broadcast, wait for the receipt. + */ +export function useTx(onDone?: () => void) { + const { signer, biometrics } = useStore(); + const [state, setState] = useState({ phase: "idle" }); + + const send = useCallback( + async (args: { address: `0x${string}`; abi: Abi; functionName: string; args?: readonly unknown[]; value?: bigint }) => { + if (!signer) { + setState({ phase: "error", message: "Add a signer key under Settings to sign from this device." }); + return; + } + try { + if (biometrics) { + setState({ phase: "auth" }); + const hw = await LocalAuthentication.hasHardwareAsync(); + const enrolled = hw && (await LocalAuthentication.isEnrolledAsync()); + if (enrolled) { + const r = await LocalAuthentication.authenticateAsync({ promptMessage: "Approve with Skur", cancelLabel: "Cancel" }); + if (!r.success) { + setState({ phase: "error", message: "Authentication cancelled. Nothing was signed." }); + return; + } + } + } + setState({ phase: "simulating" }); + const account = privateKeyToAccount(signer.key); + const wallet = createWalletClient({ account, chain: arkDevnet, transport: http(ARK_DEVNET_RPC) }); + const { request } = await publicClient.simulateContract({ ...args, account, chain: arkDevnet } as Parameters[0]); + const hash = await wallet.writeContract(request); + setState({ phase: "mining", hash }); + await publicClient.waitForTransactionReceipt({ hash }); + setState({ phase: "done", hash }); + onDone?.(); + } catch (e) { + setState({ phase: "error", message: describeError(e) }); + } + }, + [signer, biometrics, onDone], + ); + + const reset = useCallback(() => setState({ phase: "idle" }), []); + return { state, send, reset, busy: state.phase === "auth" || state.phase === "simulating" || state.phase === "mining" }; +} diff --git a/mobile/src/hooks/useVault.ts b/mobile/src/hooks/useVault.ts new file mode 100644 index 0000000..c6eb3bd --- /dev/null +++ b/mobile/src/hooks/useVault.ts @@ -0,0 +1,40 @@ +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { publicClient } from "../lib/client"; +import { fetchActivity, fetchCore, type VaultActivity, type VaultData } from "@web/lib/vaultReads"; +import { useStore } from "../state/store"; +import { ROLE_GUARDIAN } from "@web/lib/types"; + +const EMPTY: VaultActivity = { proposals: [], recipients: [], logsFailed: false, policyHistory: [], modeHistory: [] }; +const key = (a: `0x${string}` | null) => ["vault", a] as const; + +/** Same two-query shape as the web app: core paints first, activity fills in. */ +export function useVault(address: `0x${string}` | null) { + const core = useQuery({ queryKey: [...key(address), "core"], queryFn: () => fetchCore(publicClient, address!), enabled: Boolean(address), refetchInterval: 20_000, staleTime: 10_000 }); + const activity = useQuery({ + queryKey: [...key(address), "activity", core.data?.proposalCount ?? -1], + queryFn: () => fetchActivity(publicClient, address!, core.data?.proposalCount ?? 0, core.data?.blockNumber ?? 0n), + enabled: Boolean(address && core.data), + refetchInterval: 30_000, + staleTime: 15_000, + placeholderData: (prev) => prev, + }); + const data: VaultData | undefined = core.data ? { ...core.data, ...(activity.data ?? EMPTY), activityLoading: !activity.data, fetchedAt: core.dataUpdatedAt } : undefined; + return { data, error: core.error ?? activity.error, isLoading: core.isLoading, refetch: () => { void core.refetch(); void activity.refetch(); }, refreshing: core.isFetching }; +} + +export function useInvalidateVault(address: `0x${string}` | null) { + const qc = useQueryClient(); + return () => { + void qc.invalidateQueries({ queryKey: key(address) }); + for (const ms of [6_000, 15_000, 30_000]) setTimeout(() => void qc.invalidateQueries({ queryKey: key(address) }), ms); + }; +} + +/** Roles the device signer holds in the open vault. */ +export function useMyRoles(vault: VaultData | undefined): number { + const { signer } = useStore(); + if (!vault || !signer) return 0; + return vault.members.find((m) => m.address.toLowerCase() === signer.address.toLowerCase())?.roles ?? 0; +} + +export const isGuardianRole = (roles: number) => Boolean(roles & ROLE_GUARDIAN); diff --git a/mobile/src/lib/client.ts b/mobile/src/lib/client.ts new file mode 100644 index 0000000..d89592b --- /dev/null +++ b/mobile/src/lib/client.ts @@ -0,0 +1,5 @@ +import { createPublicClient, http } from "viem"; +import { arkDevnet, ARK_DEVNET_RPC } from "@web/config/chain"; + +/** One public client for the app. No JSON-RPC batching: the devnet serves batches serially (docs/DECISIONS.md D18). */ +export const publicClient = createPublicClient({ chain: arkDevnet, transport: http(ARK_DEVNET_RPC, { retryCount: 2 }) }); diff --git a/mobile/src/lib/describe.ts b/mobile/src/lib/describe.ts new file mode 100644 index 0000000..de5e7c1 --- /dev/null +++ b/mobile/src/lib/describe.ts @@ -0,0 +1,42 @@ +import { hexToString } from "viem"; +import { fmtAmount, short } from "@web/lib/format"; +import { Kind, MODE_LABEL, roleNames, Status, TRUST_LABEL, type Mode, type Trust } from "@web/lib/types"; +import type { ProposalView, VaultData } from "@web/lib/vaultReads"; + +/** Title and one-line detail for a proposal row, in the same words the web interface uses. */ +export function describeProposal(p: ProposalView, vault: VaultData): { title: string; detail: string; icon: string } { + const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); + switch (p.kind) { + case Kind.TRANSFER: + return { title: "Send", detail: `${asset ? fmtAmount(p.amount, asset.decimals, asset.symbol) : String(p.amount)} to ${short(p.target)}`, icon: "↗" }; + case Kind.POLICY_UPDATE: + return { title: "Policy update", detail: p.securityReducing ? "loosens at least one control" : "tightens or keeps every control", icon: "≡" }; + case Kind.ASSET_LIMITS: + return { title: "Asset limits", detail: `${asset?.symbol ?? short(p.target)}${p.securityReducing ? " · loosens a cap" : ""}`, icon: "≡" }; + case Kind.MEMBER_SET: { + const roles = Number(p.amount); + return { title: roles === 0 ? "Remove member" : "Set roles", detail: `${short(p.target)}${roles ? ` → ${roleNames(roles).join(" + ")}` : ""}`, icon: "◎" }; + } + case Kind.RECIPIENT_TRUST: + return { title: "Recipient trust", detail: `${short(p.target)} → ${TRUST_LABEL[Number(p.amount) as Trust]}`, icon: "◎" }; + case Kind.MODE_RELAX: + return { title: "Lower security mode", detail: `to ${MODE_LABEL[Number(p.amount) as Mode]} · guardians must confirm`, icon: "⛨" }; + case Kind.RECOVERY: + return { title: "Signer recovery", detail: `${short(p.target)} replaced`, icon: "⛨" }; + default: + return { title: "Proposal", detail: "", icon: "•" }; + } +} + +export function statusText(p: ProposalView): string { + if (p.status === Status.PENDING) return `${p.liveApprovals} of ${p.requiredApprovals}${p.requiredGuardians ? ` + ${p.liveGuardians} of ${p.requiredGuardians} guardian` : ""}`; + return ["", "Pending", "Executed", "Cancelled", "Vetoed"][p.status] ?? ""; +} + +export function memoText(p: ProposalView): string { + if (p.memo) return p.memo; + if (p.kind === Kind.TRANSFER && p.data && p.data !== "0x") { + try { return hexToString(p.data); } catch { return ""; } + } + return ""; +} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx new file mode 100644 index 0000000..89fa105 --- /dev/null +++ b/mobile/src/screens/Home.tsx @@ -0,0 +1,73 @@ +import { useNavigation } from "@react-navigation/native"; +import { Pressable, RefreshControl, Text, View } from "react-native"; +import { NATIVE_ASSET } from "@web/config/chain"; +import { fmtAmount, fmtDuration, short } from "@web/lib/format"; +import { Mode, ROLE_APPROVER, ROLE_OWNER, Status } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { describeProposal, statusText } from "../lib/describe"; +import { useMyRoles } from "../hooks/useVault"; +import { useStore } from "../state/store"; +import { Address, Badge, Button, Card, Empty, KV, ModeBadge, Screen, Tape, s } from "../components/ui"; +import { C, F } from "../theme"; + +export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); + const { labels, signer } = useStore(); + const roles = useMyRoles(vault); + const label = labels[vault.address.toLowerCase()] ?? "Treasury vault"; + const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; + const native = vault.assets.find((a) => a.address === NATIVE_ASSET); + const pending = vault.proposals.filter((p) => p.status === Status.PENDING); + const canPropose = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)) && vault.mode !== Mode.LOCKDOWN; + + return ( + } refreshControl={}> + {vault.mode !== Mode.NORMAL && } + + Total balance + {stable ? fmtAmount(stable.balance, stable.decimals, stable.symbol) : "—"} + {native ? `+ ${fmtAmount(native.balance, native.decimals, native.symbol)}` : ""} · policy v{vault.policyVersion} · {vault.members.length} members + + + + + {!signer && Read-only: add a signer key under Settings to confirm or propose.} + {signer && roles === 0 && Read-only: {short(signer.address)} is not a member of this vault.} + + + {vault.mode !== Mode.NORMAL && ( + + {vault.mode === Mode.LOCKDOWN ? "LOCKDOWN" : "ELEVATED"} + {vault.mode === Mode.LOCKDOWN ? "Outgoing payments are frozen" : "Every payment is scored one tier higher"} + {vault.mode === Mode.LOCKDOWN ? "Deposits, tightening changes, recovery and guardian actions still work." : "Per-transaction and daily caps are halved until owners and guardians lower the mode."} + + )} + + 0 ? nav.navigate("Transactions")}>View all › : undefined}> + {vault.activityLoading ? Reading the queue from the chain… : pending.length === 0 ? Nothing waiting for a signature : pending.slice(0, 4).map((p) => { + const d = describeProposal(p, vault); + return ( + nav.navigate("TxDetail", { id: String(p.id) })} style={s.kv}> + {d.title} · {d.detail} + {statusText(p)} + + ); + })} + + + + {vault.assets.map((a, i) => ( + + ))} + + + nav.navigate("Security")}>Security ›}> + + + + + + Vault

    + + ); +} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx new file mode 100644 index 0000000..3f02587 --- /dev/null +++ b/mobile/src/screens/Onboard.tsx @@ -0,0 +1,60 @@ +import { useState } from "react"; +import { Text, View } from "react-native"; +import { isAddress } from "viem"; +import { SkurFactoryAbi } from "@web/abi/SkurFactory"; +import { DEPLOYMENTS } from "@web/config/chain"; +import { short } from "@web/lib/format"; +import { publicClient } from "../lib/client"; +import { useStore } from "../state/store"; +import { Button, Card, Field, Input, Notice, Screen, Tape, s } from "../components/ui"; +import { C, F } from "../theme"; + +/** First screen: open a vault by address, the demo vault, or one the device signer belongs to. */ +export function Onboard() { + const { setVaultAddress, signer, createSigner } = useStore(); + const [addr, setAddr] = useState(""); + const [mine, setMine] = useState<`0x${string}`[] | null>(null); + const [busy, setBusy] = useState(false); + const [err, setErr] = useState(null); + + const findMine = async () => { + if (!signer) return; + setBusy(true); setErr(null); + try { const v = await publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }); setMine([...v]); } + catch (e) { setErr((e as Error).message); } + finally { setBusy(false); } + }; + + return ( + + + S + Skur + Treasury security that assumes compromise. Open a vault to see its balances, queue and policy, and sign from this phone. + + + + + setAddr(t.trim())} placeholder="0x…" mono /> + + + + + + {signer ? ( + <> + Signer on this phone: {short(signer.address)} + {mine === null ? : mine.length === 0 ? This signer is not a member of any vault yet. You can still open any vault by address. : mine.map((v) => )} + {err ? {err} : null} + + ) : ( + <> + No signer key on this phone yet. Create one to be added as a member, or import an existing key under Settings later. + + + )} + + You interact directly with verified contracts on the Ark Constellation devnet. Skur never holds keys or funds. + + ); +} diff --git a/mobile/src/screens/Receive.tsx b/mobile/src/screens/Receive.tsx new file mode 100644 index 0000000..7c40c4d --- /dev/null +++ b/mobile/src/screens/Receive.tsx @@ -0,0 +1,17 @@ +import { useNavigation } from "@react-navigation/native"; +import { Text } from "react-native"; +import type { VaultData } from "@web/lib/vaultReads"; +import { Address, Button, Card, Screen, s } from "../components/ui"; + +export function Receive({ vault }: { vault: VaultData }) { + const nav = useNavigation<{ goBack: () => void }>(); + return ( + + +
    + Tap the address to copy it. Send KASH or any approved token to this address on the Ark Constellation devnet, chain 9000. + + + + ); +} diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx new file mode 100644 index 0000000..eda5bbc --- /dev/null +++ b/mobile/src/screens/Security.tsx @@ -0,0 +1,76 @@ +import { useState } from "react"; +import { RefreshControl, Text, View } from "react-native"; +import { stringToHex } from "viem"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { NATIVE_ASSET } from "@web/config/chain"; +import { fmtAmount, fmtDuration, short } from "@web/lib/format"; +import { computeMaxLoss } from "@web/lib/maxLoss"; +import { postureItems } from "@web/lib/posture"; +import { Mode, MODE_LABEL, ROLE_GUARDIAN, ROLE_OWNER } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { Badge, Button, Card, Field, Input, KV, ModeBadge, Notice, Screen, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +export function Security({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const roles = useMyRoles(vault); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(invalidate); + const [reason, setReason] = useState(""); + const r32 = stringToHex(reason.slice(0, 31), { size: 32 }); + const call = (fn: string, args: readonly unknown[]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); + const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); + const posture = postureItems(vault); + const okCount = posture.filter((i) => i.ok === "ok").length; + const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; + const loss = stable ? computeMaxLoss(vault.policy, stable.limits, stable.balance, vault.mode) : null; + const canRaise = Boolean(roles & (ROLE_OWNER | ROLE_GUARDIAN)); + + return ( + } refreshControl={}> + {okCount} of {posture.length} confirmed}> + {posture.map((i) => ( + + {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} + {i.text} + + ))} + + + + Any owner or guardian can raise the mode at once. Lowering it needs owners and guardians together, and leaving Lockdown also waits out the policy-change delay. + + + {vault.mode < Mode.ELEVATED && } + {vault.mode < Mode.LOCKDOWN && } + {vault.mode > Mode.NORMAL && } + + {!canRaise && Only an owner or guardian signer can change the mode.} + + + + + {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => Guardian} />)} + + + + + + {loss && stable && ( + + + + + A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. + + )} + + + {vault.modeHistory.length === 0 ? The mode has never changed. : [...vault.modeHistory].reverse().slice(0, 8).map((h, i) => ( + + ))} + + + ); +} diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx new file mode 100644 index 0000000..56f750f --- /dev/null +++ b/mobile/src/screens/Send.tsx @@ -0,0 +1,99 @@ +import { useNavigation } from "@react-navigation/native"; +import { useEffect, useState } from "react"; +import { Pressable, Text, View } from "react-native"; +import { isAddress, stringToHex } from "viem"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { fmtAmount, fmtBps, fmtDuration, parseAmount, short } from "@web/lib/format"; +import { describeError } from "@web/lib/errors"; +import { explainReasons, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { publicClient } from "../lib/client"; +import { useInvalidateVault } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { Button, Card, Field, Input, KV, Notice, Screen, TierBadge, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust; activatesAt: bigint }; + +/** Send flow: the vault itself classifies the payment before anything is signed. */ +export function Send({ vault }: { vault: VaultData }) { + const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(() => { invalidate(); }); + const [to, setTo] = useState(""); + const [assetAddr, setAssetAddr] = useState(vault.assets[0]?.address); + const [amountText, setAmountText] = useState(""); + const [memo, setMemo] = useState(""); + const [preview, setPreview] = useState(null); + const [previewError, setPreviewError] = useState(null); + const [loading, setLoading] = useState(false); + const asset = vault.assets.find((a) => a.address === assetAddr) ?? vault.assets[0]; + const amount = asset ? parseAmount(amountText, asset.decimals) : null; + const ok = isAddress(to) && amount !== null && amount > 0n && Boolean(asset); + + useEffect(() => { + if (!ok || !asset || amount === null) { setPreview(null); setPreviewError(null); return; } + let live = true; + setLoading(true); + (async () => { + try { + const [r, rec] = await Promise.all([ + publicClient.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "previewTransfer", args: [asset.address, to as `0x${string}`, amount] }), + publicClient.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "getRecipient", args: [to as `0x${string}`] }), + ]); + if (!live) return; + setPreview({ tier: Number(r.tier) as Tier, reasons: Number(r.reasons), exposureBps: Number(r.exposureBps), requiredApprovals: Number(r.requiredApprovals), requiredGuardians: Number(r.requiredGuardians), delay: Number(r.delay), trust: Number(rec.trust) as Trust, activatesAt: rec.activatesAt }); + setPreviewError(null); + } catch (e) { if (live) { setPreview(null); setPreviewError(describeError(e)); } } + finally { if (live) setLoading(false); } + })(); + return () => { live = false; }; + }, [ok, to, assetAddr, amountText, vault.address, asset, amount]); + + const submit = () => { if (!asset || amount === null) return; void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [asset.address, to as `0x${string}`, amount, memo ? stringToHex(memo) : "0x"] }); }; + const remaining = asset && amount !== null ? asset.balance - amount : 0n; + + return ( + + + + setTo(t.trim())} placeholder="0x…" mono /> + + + + {vault.assets.map((a) => ( + setAssetAddr(a.address)} style={[s.segItem, { flex: 0, paddingHorizontal: 14, backgroundColor: a.address === assetAddr ? C.accent : C.panel2 }]}>{a.symbol} + ))} + + + + + + + + + + {loading && Asking the vault how it scores this payment…} + {previewError && {previewError}} + {preview && asset && amount !== null && ( + + + + + } /> + + {explainReasons(preview.reasons).length > 0 && ( + + Why this tier + {explainReasons(preview.reasons).map((t) => ▪ {t})} + + )} + + )} + + + {tx.state.phase === "done" && } + + + ); +} diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx new file mode 100644 index 0000000..59a601c --- /dev/null +++ b/mobile/src/screens/Settings.tsx @@ -0,0 +1,76 @@ +import * as LocalAuthentication from "expo-local-authentication"; +import { useEffect, useState } from "react"; +import { Alert, Linking, Switch, Text, View } from "react-native"; +import { ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC, DEPLOYMENTS } from "@web/config/chain"; +import { short } from "@web/lib/format"; +import { roleNames } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useMyRoles } from "../hooks/useVault"; +import { useStore } from "../state/store"; +import { Address, Badge, Button, Card, Field, Input, KV, Notice, Screen, s } from "../components/ui"; +import { C } from "../theme"; + +export function Settings({ vault }: { vault: VaultData | undefined }) { + const { vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics } = useStore(); + const roles = useMyRoles(vault); + const [name, setName] = useState(vaultAddress ? labels[vaultAddress.toLowerCase()] ?? "" : ""); + const [importKey, setImportKey] = useState(""); + const [importErr, setImportErr] = useState(null); + const [bioAvailable, setBioAvailable] = useState(false); + useEffect(() => { void (async () => setBioAvailable((await LocalAuthentication.hasHardwareAsync()) && (await LocalAuthentication.isEnrolledAsync())))(); }, []); + + return ( + + + {vaultAddress ? ( + <> + + { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} /> + + } /> + + + + + + + + ) : } + + + + {signer ? ( + <> + } /> + + + Require Face ID / biometrics to sign{!bioAvailable && No biometrics enrolled on this device; signing proceeds without a prompt.} + void setBiometrics(v)} trackColor={{ true: C.accent }} /> + + The private key is stored in the device keychain and never leaves the phone. Only signed transactions do. Give this address a role in a vault to sign for it. + + + ) : ( + <> + No signer yet. Create a fresh key on this phone, then add its address as a member of your vault, or import a key you already use. + + + + + + {importErr && {importErr}} + + )} + + + + + + } /> + } /> + } last /> + If this app ever disappears, the vault stays reachable through these endpoints and the verified contracts on the explorer. Skur V1 · {short(DEPLOYMENTS.demoVault)} + + + ); +} diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx new file mode 100644 index 0000000..f35dfad --- /dev/null +++ b/mobile/src/screens/Transactions.tsx @@ -0,0 +1,42 @@ +import { useNavigation } from "@react-navigation/native"; +import { useState } from "react"; +import { Pressable, RefreshControl, Text, View } from "react-native"; +import { fmtDate } from "@web/lib/format"; +import { Status } from "@web/lib/types"; +import type { ProposalView, VaultData } from "@web/lib/vaultReads"; +import { describeProposal, statusText } from "../lib/describe"; +import { Badge, Card, Empty, Notice, Screen, Segmented, StatusBadge, s } from "../components/ui"; +import { C, F } from "../theme"; + +export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); + const [tab, setTab] = useState<"queue" | "history">("queue"); + const items = vault.proposals.filter((p) => (tab === "queue" ? p.status === Status.PENDING : p.status !== Status.PENDING)); + return ( + }> + p.status === Status.PENDING).length ? ` · ${vault.proposals.filter((p) => p.status === Status.PENDING).length}` : ""}`], ["history", "History"]]} onChange={setTab} /> + {vault.logsFailed && The chain's event log could not be read, so purposes and history details are missing. Proposals below come straight from contract state.} + {vault.activityLoading ? Reading proposals and history from the chain… : items.length === 0 ? {tab === "queue" ? "Proposals waiting for confirmation or execution will appear here" : "Executed, cancelled and vetoed proposals will appear here"} : ( + + {items.map((p, i) => nav.navigate("TxDetail", { id: String(p.id) })} />)} + + )} + Governance proposals need owner confirmations. Security-reducing ones also wait out their timelock, and any guardian can veto them. + + ); +} + +function Row({ p, vault, last, onPress }: { p: ProposalView; vault: VaultData; last: boolean; onPress: () => void }) { + const d = describeProposal(p, vault); + return ( + + {d.icon} + + {d.title} #{String(p.id)} + {d.detail} + {fmtDate(p.createdAt)} + + {p.status === Status.PENDING ? {statusText(p)} : } + + ); +} diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx new file mode 100644 index 0000000..05b25c0 --- /dev/null +++ b/mobile/src/screens/TxDetail.tsx @@ -0,0 +1,87 @@ +import { useNavigation, useRoute } from "@react-navigation/native"; +import { Linking, Text, View } from "react-native"; +import { stringToHex } from "viem"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { ARK_DEVNET_EXPLORER } from "@web/config/chain"; +import { fmtDate, fmtDuration, nowSec, short } from "@web/lib/format"; +import { explainReasons, Kind, Mode, ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, Status } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { describeProposal, memoText, statusText } from "../lib/describe"; +import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { useStore } from "../state/store"; +import { Address, Badge, Button, Card, KV, Notice, Screen, StatusBadge, TierBadge, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +export function TxDetail({ vault }: { vault: VaultData }) { + const route = useRoute<{ key: string; name: string; params: { id: string } }>(); + const nav = useNavigation<{ goBack: () => void }>(); + const { signer } = useStore(); + const roles = useMyRoles(vault); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(invalidate); + const p = vault.proposals.find((x) => String(x.id) === route.params.id); + if (!p) return This proposal is not in the loaded range.; + const d = describeProposal(p, vault); + const now = nowSec(); + const pending = p.status === Status.PENDING; + const expired = pending && Number(p.expiresAt) <= now; + const timelocked = pending && Number(p.executableAfter) > now; + const approvalsMet = p.liveApprovals >= p.requiredApprovals && p.liveGuardians >= p.requiredGuardians; + const me = signer?.address.toLowerCase(); + const alreadyApproved = Boolean(me && (p.approvers.some((a) => a.toLowerCase() === me) || p.guardianConfirmers.some((a) => a.toLowerCase() === me))); + const canApprove = pending && !expired && !alreadyApproved && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER | ROLE_GUARDIAN : ROLE_OWNER | ROLE_GUARDIAN)) && (roles & ROLE_GUARDIAN ? p.requiredGuardians > 0 : true); + const lockedOut = vault.mode === Mode.LOCKDOWN && (p.kind === Kind.TRANSFER || p.securityReducing); + const canExecute = pending && !expired && approvalsMet && !timelocked && !lockedOut && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_EXECUTOR | ROLE_OWNER : ROLE_OWNER)); + const canVeto = pending && p.vetoable && Boolean(roles & ROLE_GUARDIAN); + const canCancel = pending && Boolean(me && (p.proposer.toLowerCase() === me || roles & ROLE_OWNER)); + const call = (fn: string, args: readonly unknown[] = [p.id]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); + const memo = memoText(p); + + return ( + {statusText(p)} : }> + + + {memo ? : null} + } /> + + {p.kind === Kind.TRANSFER && } />} + + Number(p.createdAt) ? fmtDuration(Number(p.executableAfter - p.createdAt)) : "none"} /> + + + + {p.kind === Kind.TRANSFER && explainReasons(p.riskReasons).length > 0 && ( + + {explainReasons(p.riskReasons).map((t) => ▪ {t})} + + )} + + Signers ({p.liveApprovals} of {p.requiredApprovals}) + {p.approvers.length === 0 ? None yet : p.approvers.map((a) => ✓ {short(a, 6)})} + {p.requiredGuardians > 0 && ( + <> + Guardians ({p.liveGuardians} of {p.requiredGuardians}) + {p.guardianConfirmers.length === 0 ? Independent sign-off required : p.guardianConfirmers.map((a) => ✓ {short(a, 6)})} + + )} + + {pending && ( + + {!signer && Add a signer key under Settings to act on this proposal.} + {signer && roles === 0 && {short(signer.address)} is not a member of this vault.} + + {canApprove && } + {Boolean(roles & (ROLE_EXECUTOR | ROLE_OWNER)) && !(roles & ROLE_GUARDIAN) && } + {canVeto && } + {canCancel && !expired && } + {expired && } + + + + )} + + + + ); +} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx new file mode 100644 index 0000000..5943e0f --- /dev/null +++ b/mobile/src/state/store.tsx @@ -0,0 +1,62 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import * as SecureStore from "expo-secure-store"; +import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; +import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; + +export type Signer = { key: `0x${string}`; address: `0x${string}` }; +type Store = { + ready: boolean; + vaultAddress: `0x${string}` | null; + setVaultAddress: (a: `0x${string}` | null) => Promise; + labels: Record; + setLabel: (vault: `0x${string}`, name: string) => Promise; + signer: Signer | null; + createSigner: () => Promise; + importSigner: (key: string) => Promise; + removeSigner: () => Promise; + biometrics: boolean; + setBiometrics: (on: boolean) => Promise; +}; + +const Ctx = createContext(null); +const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer" }; + +/** App state. The signer's private key lives only in the device keychain (expo-secure-store); nothing leaves the phone but signed transactions. */ +export function StoreProvider({ children }: { children: ReactNode }) { + const [ready, setReady] = useState(false); + const [vaultAddress, setVault] = useState<`0x${string}` | null>(null); + const [labels, setLabels] = useState>({}); + const [signer, setSigner] = useState(null); + const [biometrics, setBio] = useState(true); + + useEffect(() => { + (async () => { + try { + const [v, l, b, key] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer)]); + if (v) setVault(v as `0x${string}`); + if (l) setLabels(JSON.parse(l)); + if (b !== null) setBio(b === "1"); + if (key) setSigner({ key: key as `0x${string}`, address: privateKeyToAccount(key as `0x${string}`).address }); + } finally { + setReady(true); + } + })(); + }, []); + + const setVaultAddress = useCallback(async (a: `0x${string}` | null) => { setVault(a); if (a) await AsyncStorage.setItem(K.vault, a); else await AsyncStorage.removeItem(K.vault); }, []); + const setLabel = useCallback(async (vault: `0x${string}`, name: string) => { setLabels((l) => { const n = { ...l, [vault.toLowerCase()]: name }; void AsyncStorage.setItem(K.labels, JSON.stringify(n)); return n; }); }, []); + const persistSigner = useCallback(async (key: `0x${string}`) => { const s = { key, address: privateKeyToAccount(key).address }; await SecureStore.setItemAsync(K.signer, key, { keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY }); setSigner(s); return s; }, []); + const createSigner = useCallback(() => persistSigner(generatePrivateKey()), [persistSigner]); + const importSigner = useCallback((raw: string) => { const k = (raw.trim().startsWith("0x") ? raw.trim() : `0x${raw.trim()}`) as `0x${string}`; if (!/^0x[0-9a-fA-F]{64}$/.test(k)) throw new Error("A private key is 64 hex characters."); return persistSigner(k); }, [persistSigner]); + const removeSigner = useCallback(async () => { await SecureStore.deleteItemAsync(K.signer); setSigner(null); }, []); + const setBiometrics = useCallback(async (on: boolean) => { setBio(on); await AsyncStorage.setItem(K.bio, on ? "1" : "0"); }, []); + + const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics }), [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics]); + return {children}; +} + +export function useStore(): Store { + const s = useContext(Ctx); + if (!s) throw new Error("StoreProvider missing"); + return s; +} diff --git a/mobile/src/theme.ts b/mobile/src/theme.ts new file mode 100644 index 0000000..8186d99 --- /dev/null +++ b/mobile/src/theme.ts @@ -0,0 +1,33 @@ +/** Skur mobile: charcoal ground, #FFD000 used the way hazard tape is used. Mirrors web/src/styles.css dark tokens. */ +export const C = { + canvas: "#212529", + panel: "#2b3035", + panel2: "#343a40", + border: "#495057", + text: "#f8f9fa", + text2: "#adb5bd", + text3: "#6c757d", + accent: "#ffd000", + accentBg: "#3d3400", + onAccent: "#212529", + success: "#75b798", + successBg: "#1b4332", + warning: "#ffa94d", + warningBg: "#4d2e05", + error: "#ea868f", + errorBg: "#4a1c22", + info: "#6ea8fe", + infoBg: "#1b3a5c", +} as const; + +export const F = { + display: "SpaceGrotesk_700Bold", + displayMedium: "SpaceGrotesk_600SemiBold", + body: "DMSans_400Regular", + bodyMedium: "DMSans_500Medium", + bodyBold: "DMSans_700Bold", + mono: "DMMono_400Regular", + monoMedium: "DMMono_500Medium", +} as const; + +export const R = { sm: 6, md: 10, lg: 14 } as const; diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json new file mode 100644 index 0000000..8cdbf88 --- /dev/null +++ b/mobile/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "resolveJsonModule": true, + "paths": { "@web/*": ["../web/src/*"] } + }, + "include": ["**/*.ts", "**/*.tsx", "../web/src/lib/**/*.ts", "../web/src/abi/*.ts", "../web/src/config/*.ts"], + "exclude": ["node_modules", "../web/src/lib/*.test.ts", "../web/src/lib/motion.ts"] +} diff --git a/package.json b/package.json index 893c621..50c2b19 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "web:dev": "cd web && npm run dev", "web:build": "cd web && npm run build", "web:test": "cd web && npm test", - "test": "npm run contracts:test && npm run web:test" + "mobile:start": "cd mobile && npx expo start", + "mobile:typecheck": "cd mobile && npx tsc --noEmit", + "test": "npm run contracts:test && npm run web:test && npm run mobile:typecheck" } } diff --git a/web/src/hooks/useTx.ts b/web/src/hooks/useTx.ts index 4a486cf..242da39 100644 --- a/web/src/hooks/useTx.ts +++ b/web/src/hooks/useTx.ts @@ -2,7 +2,8 @@ import { useCallback, useState } from "react"; import { useAccount, usePublicClient, useSwitchChain, useWalletClient } from "wagmi"; import { getWalletClient } from "wagmi/actions"; import { wagmiConfig } from "../wagmi"; -import { BaseError, ContractFunctionRevertedError, type Abi } from "viem"; +import type { Abi } from "viem"; +import { describeError } from "../lib/errors"; import { arkDevnet } from "../config/chain"; export type TxState = @@ -66,54 +67,4 @@ export function useTx(onDone?: () => void) { return { state, send, reset, busy: state.phase === "simulating" || state.phase === "signing" || state.phase === "mining" }; } -const ERROR_TEXT: Record string> = { - NotAuthorized: (a) => `Your wallet does not hold the required role (${roleText(Number(a[0]))}).`, - VaultLocked: () => "The vault is in Lockdown. Outgoing payments and security-reducing changes are blocked until it is lowered.", - Timelocked: (a) => `This cannot execute before ${new Date(Number(a[0]) * 1000).toLocaleString()}.`, - InsufficientApprovals: (a) => `${a[0]} of the required ${a[1]} approvals are in place.`, - InsufficientGuardians: (a) => `${a[0]} of the required ${a[1]} guardian confirmations are in place.`, - PerTxLimitExceeded: () => "This amount is above the per-transaction cap for the asset.", - VelocityExceeded: () => "This would push today's outflow past the 24-hour cap for the asset.", - ExposureHardBlocked: (a) => `This would move ${Number(a[0]) / 100}% of holdings; the policy refuses anything above ${Number(a[1]) / 100}%.`, - RecipientBlocked: () => "This recipient is blocked by policy.", - AssetNotApproved: () => "This asset is not on the vault's approved list.", - AlreadyApproved: () => "You have already confirmed this proposal.", - NotPending: () => "This proposal is no longer open.", - ProposalExpired: () => "This proposal has expired.", - NotVetoable: () => "Guardians cannot veto this proposal: it is neither critical, probationary nor security-reducing.", - ModeNotStricter: () => "The mode can only be raised directly. Lowering it goes through governance.", - ModeNotRelaxation: () => "That mode is not lower than the current one.", - InvalidPolicy: (a) => `Invalid policy: ${String(a[0])}.`, - ThresholdUnsatisfiable: (a) => `Thresholds would be unsatisfiable: ${String(a[0])}.`, - InvalidProposal: (a) => `Invalid proposal: ${String(a[0])}.`, - InvalidRoles: () => "Guardians cannot hold treasury roles, and roles must be valid.", - MemberExists: () => "That address is already a member.", - NotMember: () => "That address is not a member.", - InsufficientBalance: () => "The vault does not hold enough of this asset right now.", - AmountZero: () => "Amount must be greater than zero.", - ZeroAddress: () => "Address cannot be empty.", - NotCancellable: () => "Only the proposer or an owner can cancel this.", -}; - -function roleText(bits: number): string { - const n: string[] = []; - if (bits & 1) n.push("Owner"); - if (bits & 2) n.push("Approver"); - if (bits & 4) n.push("Executor"); - if (bits & 8) n.push("Guardian"); - return n.join(" or ") || "unknown"; -} - -export function describeError(e: unknown): string { - if (e instanceof BaseError) { - const revert = e.walk((err) => err instanceof ContractFunctionRevertedError) as ContractFunctionRevertedError | null; - if (revert?.data) { - const name = revert.data.errorName; - const f = ERROR_TEXT[name]; - if (f) return f(revert.data.args ?? []); - return `${name}(${(revert.data.args ?? []).map(String).join(", ")})`; - } - return e.shortMessage; - } - return e instanceof Error ? e.message : String(e); -} +export { describeError } from "../lib/errors"; diff --git a/web/src/hooks/useVault.ts b/web/src/hooks/useVault.ts index 2a24a54..bc92ddc 100644 --- a/web/src/hooks/useVault.ts +++ b/web/src/hooks/useVault.ts @@ -1,275 +1,9 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { usePublicClient } from "wagmi"; -import { erc20Abi, parseAbiItem, type PublicClient, type AbiEvent, type ReadContractReturnType } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { DEPLOYMENTS, NATIVE_ASSET } from "../config/chain"; -import { policyFromContract } from "../lib/policy"; -import { - Kind, - Mode, - Status, - Trust, - type AssetLimits, - type AssetMeta, - type Policy, - type Proposal, - type Recipient, -} from "../lib/types"; +import type { PublicClient } from "viem"; +import { fetchActivity, fetchCore, type VaultActivity, type VaultData } from "../lib/vaultReads"; -export type Member = { address: `0x${string}`; roles: number }; - -export type ProposalView = Proposal & { - id: bigint; - liveApprovals: number; - liveGuardians: number; - vetoable: boolean; - approvers: `0x${string}`[]; - guardianConfirmers: `0x${string}`[]; - memo: string; -}; - -export type VelocityView = { - daySpent: bigint; - dailyMax: bigint; - envelopeSpent: bigint; - envelope: bigint; - envelopeResetsAt: bigint; -}; - -export type RecipientView = Recipient & { address: `0x${string}` }; - -/** Fast path: everything needed to render balances, policy, members and limits, read concurrently. */ -export type VaultCore = { - address: `0x${string}`; - mode: Mode; - policyVersion: number; - policy: Policy; - members: Member[]; - counts: { owners: number; approvers: number; executors: number; guardians: number }; - assets: AssetMeta[]; - velocity: Record; - proposalCount: number; - /** Head block at the time of the core read; the activity scan uses it so it needs no extra round trip. */ - blockNumber: bigint; - pendingCount: number; - executedCount: number; -}; - -/** Slow path: proposals, recipients and event history. Depends on the log queries, which the devnet serves slowly. */ -export type VaultActivity = { - proposals: ProposalView[]; - recipients: RecipientView[]; - /** True when the event scan failed; proposals still come from contract state but memos and histories are missing. */ - logsFailed: boolean; - policyHistory: Array<{ version: number; activatedAt: bigint; txHash: `0x${string}` }>; - modeHistory: Array<{ previous: Mode; mode: Mode; by: `0x${string}`; reason: string; txHash: `0x${string}`; block: bigint }>; -}; - -export type VaultData = VaultCore & VaultActivity & { activityLoading: boolean; fetchedAt: number }; - -const MAX_PROPOSALS = 60; - -/** Proposals in a terminal status never change again, so their reads are kept for the session. */ -type ContractProposal = ReadContractReturnType; -type ProposalRaw = { id: bigint; p: ContractProposal; live: readonly [number, number] | readonly [bigint, bigint]; vetoable: boolean; approvers: readonly `0x${string}`[]; guardianConfirmers: readonly `0x${string}`[] }; -const terminalCache = new Map(); - -const proposalCreatedEvent = parseAbiItem( - "event ProposalCreated(uint256 indexed id, uint8 indexed kind, address indexed proposer, address asset, address target, uint256 amount, uint8 tier, uint16 riskReasons, uint8 requiredApprovals, uint8 requiredGuardians, uint64 executableAfter, uint64 expiresAt, bool securityReducing, string memo)", -); -const recipientRegisteredEvent = parseAbiItem("event RecipientRegistered(address indexed recipient, uint64 activatesAt)"); -const recipientTrustEvent = parseAbiItem("event RecipientTrustSet(address indexed recipient, uint8 previous, uint8 trust)"); -const policyActivatedEvent = parseAbiItem( - "event PolicyActivated(uint32 indexed version, uint64 activatedAt, (uint8 approvalsLow, uint8 approvalsHigh, uint8 approvalsCritical, uint8 governanceThreshold, uint8 guardianThreshold, bool guardianRequiredCritical, uint32 delayHigh, uint32 delayCritical, uint32 recipientActivationDelay, uint32 policyChangeDelay, uint32 recoveryDelay, uint32 proposalTtl, uint16 highExposureBps, uint16 criticalExposureBps, uint16 hardBlockExposureBps, uint16 envelopeBps, uint32 envelopeWindow) policy)", -); -const modeChangedEvent = parseAbiItem("event ModeChanged(uint8 indexed previous, uint8 indexed mode, address indexed by, bytes32 reason)"); - -function bytes32ToString(hex: `0x${string}`): string { - const bytes = hex.slice(2).match(/.{2}/g) ?? []; - let out = ""; - for (const b of bytes) { - const c = parseInt(b, 16); - if (c === 0) break; - out += String.fromCharCode(c); - } - return out; -} - -async function fetchCore(client: PublicClient, address: `0x${string}`): Promise { - const vault = { address, abi: SkurVaultAbi } as const; - const [modeRaw, policyVersion, policyRaw, membersRaw, assetsRaw, proposalCountRaw, pendingCountRaw, executedCountRaw, nativeBalance, blockNumber] = - await Promise.all([ - client.readContract({ ...vault, functionName: "mode" }), - client.readContract({ ...vault, functionName: "policyVersion" }), - client.readContract({ ...vault, functionName: "getPolicy" }), - client.readContract({ ...vault, functionName: "getMembers" }), - client.readContract({ ...vault, functionName: "getAssets" }), - client.readContract({ ...vault, functionName: "proposalCount" }), - client.readContract({ ...vault, functionName: "pendingCount" }), - client.readContract({ ...vault, functionName: "executedCount" }), - client.getBalance({ address }), - client.getBlockNumber(), - ]); - - const members: Member[] = membersRaw[0].map((a, i) => ({ address: a, roles: Number(membersRaw[1][i]) })); - const counts = members.reduce( - (acc, m) => ({ - owners: acc.owners + (m.roles & 1 ? 1 : 0), - approvers: acc.approvers + (m.roles & 2 ? 1 : 0), - executors: acc.executors + (m.roles & 4 ? 1 : 0), - guardians: acc.guardians + (m.roles & 8 ? 1 : 0), - }), - { owners: 0, approvers: 0, executors: 0, guardians: 0 }, - ); - - // Second wave of concurrent reads: per-asset limits, velocity and ERC-20 metadata. - const perAsset = await Promise.all( - assetsRaw.map(async (asset) => { - const [limitsRaw, v, symbol, decimals, balance] = await Promise.all([ - client.readContract({ ...vault, functionName: "getAssetLimits", args: [asset] }), - client.readContract({ ...vault, functionName: "velocityOf", args: [asset] }), - asset === NATIVE_ASSET ? Promise.resolve("KASH") : client.readContract({ address: asset, abi: erc20Abi, functionName: "symbol" }).catch(() => "TOKEN"), - asset === NATIVE_ASSET ? Promise.resolve(18) : client.readContract({ address: asset, abi: erc20Abi, functionName: "decimals" }).catch(() => 18), - asset === NATIVE_ASSET ? Promise.resolve(nativeBalance) : client.readContract({ address: asset, abi: erc20Abi, functionName: "balanceOf", args: [address] }).catch(() => 0n), - ]); - const limits: AssetLimits = { approved: limitsRaw.approved, lowMax: limitsRaw.lowMax, highMax: limitsRaw.highMax, perTxMax: limitsRaw.perTxMax, dailyMax: limitsRaw.dailyMax }; - const meta: AssetMeta = { address: asset, symbol, decimals: Number(decimals), limits, balance }; - const velocity: VelocityView = { daySpent: v[0], dailyMax: v[1], envelopeSpent: v[2], envelope: v[3], envelopeResetsAt: v[4] }; - return { meta, velocity }; - }), - ); - const velocity: Record = {}; - for (const { meta, velocity: v } of perAsset) velocity[meta.address.toLowerCase()] = v; - - return { - address, - mode: Number(modeRaw) as Mode, - policyVersion: Number(policyVersion), - policy: policyFromContract(policyRaw as unknown as Record), - members, - counts, - assets: perAsset.map((x) => x.meta), - velocity, - proposalCount: Number(proposalCountRaw), - blockNumber, - pendingCount: Number(pendingCountRaw), - executedCount: Number(executedCountRaw), - }; -} - -/** The devnet RPC caps eth_getLogs at 10,000 blocks per call, so the scan runs in parallel windows. */ -const LOG_WINDOW = 9_000n; -type RawLog = { eventName?: string; args?: unknown; transactionHash: `0x${string}`; blockNumber: bigint }; -async function getLogsChunked(client: PublicClient, address: `0x${string}`, events: readonly AbiEvent[], fromBlock: bigint, head: bigint): Promise<{ logs: RawLog[]; failed: boolean }> { - try { - // `head` comes from the core read and may be a few blocks stale, so the last window runs to "latest" - // rather than to `head`; that keeps an event mined between the two reads from being missed. - const windows: Array<[bigint, bigint | "latest"]> = []; - for (let a = fromBlock; a <= head; a += LOG_WINDOW + 1n) windows.push([a, a + LOG_WINDOW > head ? head : a + LOG_WINDOW]); - if (windows.length === 0) windows.push([fromBlock, "latest"]); - else windows[windows.length - 1][1] = "latest"; - const chunks = await Promise.all(windows.map(([from, to]) => client.getLogs({ address, events, fromBlock: from, toBlock: to }) as unknown as Promise)); - return { logs: chunks.flat(), failed: false }; - } catch { - return { logs: [], failed: true }; - } -} - -async function fetchActivity(client: PublicClient, address: `0x${string}`, proposalCount: number, head: bigint): Promise { - const vault = { address, abi: SkurVaultAbi } as const; - const fromBlock = BigInt(DEPLOYMENTS.deployedAtBlock || 0); - - const firstId = Math.max(1, proposalCount - MAX_PROPOSALS + 1); - const ids: bigint[] = []; - for (let i = proposalCount; i >= firstId; i--) ids.push(BigInt(i)); - - // One log query for every event we index; the devnet serves each getLogs call slowly, so five - // separate queries were the long pole of the page load. - const [{ logs: allLogs, failed: logsFailed }, proposalsRaw] = await Promise.all([ - getLogsChunked(client, address, [proposalCreatedEvent, recipientRegisteredEvent, recipientTrustEvent, policyActivatedEvent, modeChangedEvent], fromBlock, head), - Promise.all( - ids.map(async (id): Promise => { - const cached = terminalCache.get(`${address}:${id}`); - if (cached) return cached; - const p = await client.readContract({ ...vault, functionName: "getProposal", args: [id] }); - const pending = Number(p.status) === Status.PENDING; - const [live, vetoable, approvers, guardianConfirmers] = await Promise.all([ - pending ? client.readContract({ ...vault, functionName: "liveApprovals", args: [id] }) : ([0, 0] as const), - pending ? client.readContract({ ...vault, functionName: "isVetoable", args: [id] }) : false, - client.readContract({ ...vault, functionName: "getApprovers", args: [id] }), - client.readContract({ ...vault, functionName: "getGuardianConfirmers", args: [id] }), - ]); - const raw: ProposalRaw = { id, p, live, vetoable, approvers, guardianConfirmers }; - if (!pending) terminalCache.set(`${address}:${id}`, raw); - return raw; - }), - ), - ]); - // viem types the args of a multi-event query as a union; narrow per event name explicitly. - type LogWith = { args: A; transactionHash: `0x${string}`; blockNumber: bigint }; - const byName = (name: string): LogWith[] => allLogs.filter((l) => l.eventName === name) as unknown as LogWith[]; - const createdLogs = byName<{ id?: bigint; memo?: string }>("ProposalCreated"); - const registeredLogs = byName<{ recipient?: `0x${string}` }>("RecipientRegistered"); - const trustLogs = byName<{ recipient?: `0x${string}` }>("RecipientTrustSet"); - const policyLogs = byName<{ version?: number; activatedAt?: bigint }>("PolicyActivated"); - const modeLogs = byName<{ previous?: number; mode?: number; by?: `0x${string}`; reason?: `0x${string}` }>("ModeChanged"); - - const memos = new Map(); - for (const l of createdLogs) memos.set(String(l.args.id), l.args.memo ?? ""); - - const proposals: ProposalView[] = proposalsRaw.map(({ id, p, live, vetoable, approvers, guardianConfirmers }) => ({ - id, - kind: Number(p.kind) as Kind, - status: Number(p.status) as Status, - tier: Number(p.tier), - requiredApprovals: Number(p.requiredApprovals), - requiredGuardians: Number(p.requiredGuardians), - securityReducing: p.securityReducing, - riskReasons: Number(p.riskReasons), - policyVersion: Number(p.policyVersion), - proposer: p.proposer, - asset: p.asset, - target: p.target, - amount: p.amount, - createdAt: p.createdAt, - executableAfter: p.executableAfter, - expiresAt: p.expiresAt, - data: p.data, - liveApprovals: Number(live[0]), - liveGuardians: Number(live[1]), - vetoable, - approvers: [...approvers], - guardianConfirmers: [...guardianConfirmers], - memo: memos.get(String(id)) ?? "", - })); - - const recipientSet = new Set(); - for (const l of registeredLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); - for (const l of trustLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); - for (const p of proposals) if (p.kind === Kind.TRANSFER) recipientSet.add(p.target); - const recipients: RecipientView[] = await Promise.all( - [...recipientSet].map(async (r) => { - const rec = await client.readContract({ ...vault, functionName: "getRecipient", args: [r as `0x${string}`] }); - return { address: r as `0x${string}`, trust: Number(rec.trust) as Trust, registeredAt: rec.registeredAt, activatesAt: rec.activatesAt, paymentCount: rec.paymentCount, totalPaid: rec.totalPaid }; - }), - ); - recipients.sort((a, b) => Number(b.registeredAt - a.registeredAt)); - - return { - proposals, - recipients, - logsFailed, - policyHistory: policyLogs.map((l) => ({ version: Number(l.args.version), activatedAt: l.args.activatedAt ?? 0n, txHash: l.transactionHash })), - modeHistory: modeLogs.map((l) => ({ - previous: Number(l.args.previous) as Mode, - mode: Number(l.args.mode) as Mode, - by: l.args.by as `0x${string}`, - reason: bytes32ToString(l.args.reason as `0x${string}`), - txHash: l.transactionHash, - block: l.blockNumber, - })), - }; -} +export type { Member, ProposalView, VelocityView, RecipientView, VaultCore, VaultActivity, VaultData } from "../lib/vaultReads"; export function vaultQueryKey(address: `0x${string}` | null) { return ["vault", address] as const; diff --git a/web/src/lib/errors.ts b/web/src/lib/errors.ts new file mode 100644 index 0000000..7db037a --- /dev/null +++ b/web/src/lib/errors.ts @@ -0,0 +1,54 @@ +import { BaseError, ContractFunctionRevertedError } from "viem"; + +/** Maps the vault's custom errors to plain language. Shared by web and mobile. */ +const ERROR_TEXT: Record string> = { + NotAuthorized: (a) => `Your wallet does not hold the required role (${roleText(Number(a[0]))}).`, + VaultLocked: () => "The vault is in Lockdown. Outgoing payments and security-reducing changes are blocked until it is lowered.", + Timelocked: (a) => `This cannot execute before ${new Date(Number(a[0]) * 1000).toLocaleString()}.`, + InsufficientApprovals: (a) => `${a[0]} of the required ${a[1]} approvals are in place.`, + InsufficientGuardians: (a) => `${a[0]} of the required ${a[1]} guardian confirmations are in place.`, + PerTxLimitExceeded: () => "This amount is above the per-transaction cap for the asset.", + VelocityExceeded: () => "This would push today's outflow past the 24-hour cap for the asset.", + ExposureHardBlocked: (a) => `This would move ${Number(a[0]) / 100}% of holdings; the policy refuses anything above ${Number(a[1]) / 100}%.`, + RecipientBlocked: () => "This recipient is blocked by policy.", + AssetNotApproved: () => "This asset is not on the vault's approved list.", + AlreadyApproved: () => "You have already confirmed this proposal.", + NotPending: () => "This proposal is no longer open.", + ProposalExpired: () => "This proposal has expired.", + NotVetoable: () => "Guardians cannot veto this proposal: it is neither critical, probationary nor security-reducing.", + ModeNotStricter: () => "The mode can only be raised directly. Lowering it goes through governance.", + ModeNotRelaxation: () => "That mode is not lower than the current one.", + InvalidPolicy: (a) => `Invalid policy: ${String(a[0])}.`, + ThresholdUnsatisfiable: (a) => `Thresholds would be unsatisfiable: ${String(a[0])}.`, + InvalidProposal: (a) => `Invalid proposal: ${String(a[0])}.`, + InvalidRoles: () => "Guardians cannot hold treasury roles, and roles must be valid.", + MemberExists: () => "That address is already a member.", + NotMember: () => "That address is not a member.", + InsufficientBalance: () => "The vault does not hold enough of this asset right now.", + AmountZero: () => "Amount must be greater than zero.", + ZeroAddress: () => "Address cannot be empty.", + NotCancellable: () => "Only the proposer or an owner can cancel this.", +}; + +function roleText(bits: number): string { + const n: string[] = []; + if (bits & 1) n.push("Owner"); + if (bits & 2) n.push("Approver"); + if (bits & 4) n.push("Executor"); + if (bits & 8) n.push("Guardian"); + return n.join(" or ") || "unknown"; +} + +export function describeError(e: unknown): string { + if (e instanceof BaseError) { + const revert = e.walk((err) => err instanceof ContractFunctionRevertedError) as ContractFunctionRevertedError | null; + if (revert?.data) { + const name = revert.data.errorName; + const f = ERROR_TEXT[name]; + if (f) return f(revert.data.args ?? []); + return `${name}(${(revert.data.args ?? []).map(String).join(", ")})`; + } + return e.shortMessage; + } + return e instanceof Error ? e.message : String(e); +} diff --git a/web/src/lib/posture.ts b/web/src/lib/posture.ts new file mode 100644 index 0000000..a8d21be --- /dev/null +++ b/web/src/lib/posture.ts @@ -0,0 +1,22 @@ +import { fmtDuration } from "./format"; +import type { VaultData } from "./vaultReads"; + +/** Plain-language posture checks shared by the web and mobile interfaces. */ +export type PostureItem = { ok: "ok" | "warn" | "bad"; text: string }; + +export function postureItems(vault: VaultData): PostureItem[] { + const p = vault.policy; + const g = vault.counts.guardians; + return [ + { ok: g > 0 ? "ok" : "bad", text: g > 0 ? `${g} independent guardian${g === 1 ? "" : "s"} configured` : "No guardian: nobody independent can veto or freeze" }, + { ok: p.guardianRequiredCritical ? "ok" : "warn", text: p.guardianRequiredCritical ? "Critical transfers need guardian confirmation" : "Critical transfers do not need a guardian" }, + { ok: p.delayCritical >= 24 * 3600 ? "ok" : "warn", text: `Critical delay ${fmtDuration(p.delayCritical)}` }, + { ok: p.recipientActivationDelay > 0 ? "ok" : "bad", text: p.recipientActivationDelay > 0 ? `New recipients wait ${fmtDuration(p.recipientActivationDelay)}` : "New recipients can be paid immediately" }, + { ok: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "ok" : "warn", text: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "24h outflow cap on every asset" : "Some assets have no 24h cap" }, + { ok: p.envelopeBps > 0 ? "ok" : "warn", text: p.envelopeBps > 0 ? `Circuit breaker at ${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}` : "No loss envelope configured" }, + { ok: p.policyChangeDelay > 0 ? "ok" : "bad", text: p.policyChangeDelay > 0 ? `Security-reducing changes wait ${fmtDuration(p.policyChangeDelay)}` : "Policy can be weakened instantly" }, + { ok: p.recoveryDelay > 0 && g > 0 ? "ok" : "warn", text: `Recovery configured (${fmtDuration(p.recoveryDelay)} delay)` }, + { ok: p.approvalsLow >= 2 ? "ok" : "warn", text: p.approvalsLow >= 2 ? "Routine payments need two approvals" : "Routine payments need a single approval" }, + ]; +} + diff --git a/web/src/lib/vaultReads.ts b/web/src/lib/vaultReads.ts new file mode 100644 index 0000000..4687d7d --- /dev/null +++ b/web/src/lib/vaultReads.ts @@ -0,0 +1,273 @@ +/** Pure contract reads shared by the web and mobile interfaces. No React, no wagmi: a viem PublicClient in, plain data out. */ +import { erc20Abi, parseAbiItem, type PublicClient, type AbiEvent, type ReadContractReturnType } from "viem"; +import { SkurVaultAbi } from "../abi/SkurVault"; +import { DEPLOYMENTS, NATIVE_ASSET } from "../config/chain"; +import { policyFromContract } from "./policy"; +import { + Kind, + Mode, + Status, + Trust, + type AssetLimits, + type AssetMeta, + type Policy, + type Proposal, + type Recipient, +} from "./types"; + +export type Member = { address: `0x${string}`; roles: number }; + +export type ProposalView = Proposal & { + id: bigint; + liveApprovals: number; + liveGuardians: number; + vetoable: boolean; + approvers: `0x${string}`[]; + guardianConfirmers: `0x${string}`[]; + memo: string; +}; + +export type VelocityView = { + daySpent: bigint; + dailyMax: bigint; + envelopeSpent: bigint; + envelope: bigint; + envelopeResetsAt: bigint; +}; + +export type RecipientView = Recipient & { address: `0x${string}` }; + +/** Fast path: everything needed to render balances, policy, members and limits, read concurrently. */ +export type VaultCore = { + address: `0x${string}`; + mode: Mode; + policyVersion: number; + policy: Policy; + members: Member[]; + counts: { owners: number; approvers: number; executors: number; guardians: number }; + assets: AssetMeta[]; + velocity: Record; + proposalCount: number; + /** Head block at the time of the core read; the activity scan uses it so it needs no extra round trip. */ + blockNumber: bigint; + pendingCount: number; + executedCount: number; +}; + +/** Slow path: proposals, recipients and event history. Depends on the log queries, which the devnet serves slowly. */ +export type VaultActivity = { + proposals: ProposalView[]; + recipients: RecipientView[]; + /** True when the event scan failed; proposals still come from contract state but memos and histories are missing. */ + logsFailed: boolean; + policyHistory: Array<{ version: number; activatedAt: bigint; txHash: `0x${string}` }>; + modeHistory: Array<{ previous: Mode; mode: Mode; by: `0x${string}`; reason: string; txHash: `0x${string}`; block: bigint }>; +}; + +export type VaultData = VaultCore & VaultActivity & { activityLoading: boolean; fetchedAt: number }; + +export const MAX_PROPOSALS = 60; + +/** Proposals in a terminal status never change again, so their reads are kept for the session. */ +type ContractProposal = ReadContractReturnType; +type ProposalRaw = { id: bigint; p: ContractProposal; live: readonly [number, number] | readonly [bigint, bigint]; vetoable: boolean; approvers: readonly `0x${string}`[]; guardianConfirmers: readonly `0x${string}`[] }; +const terminalCache = new Map(); + +const proposalCreatedEvent = parseAbiItem( + "event ProposalCreated(uint256 indexed id, uint8 indexed kind, address indexed proposer, address asset, address target, uint256 amount, uint8 tier, uint16 riskReasons, uint8 requiredApprovals, uint8 requiredGuardians, uint64 executableAfter, uint64 expiresAt, bool securityReducing, string memo)", +); +const recipientRegisteredEvent = parseAbiItem("event RecipientRegistered(address indexed recipient, uint64 activatesAt)"); +const recipientTrustEvent = parseAbiItem("event RecipientTrustSet(address indexed recipient, uint8 previous, uint8 trust)"); +const policyActivatedEvent = parseAbiItem( + "event PolicyActivated(uint32 indexed version, uint64 activatedAt, (uint8 approvalsLow, uint8 approvalsHigh, uint8 approvalsCritical, uint8 governanceThreshold, uint8 guardianThreshold, bool guardianRequiredCritical, uint32 delayHigh, uint32 delayCritical, uint32 recipientActivationDelay, uint32 policyChangeDelay, uint32 recoveryDelay, uint32 proposalTtl, uint16 highExposureBps, uint16 criticalExposureBps, uint16 hardBlockExposureBps, uint16 envelopeBps, uint32 envelopeWindow) policy)", +); +const modeChangedEvent = parseAbiItem("event ModeChanged(uint8 indexed previous, uint8 indexed mode, address indexed by, bytes32 reason)"); + +function bytes32ToString(hex: `0x${string}`): string { + const bytes = hex.slice(2).match(/.{2}/g) ?? []; + let out = ""; + for (const b of bytes) { + const c = parseInt(b, 16); + if (c === 0) break; + out += String.fromCharCode(c); + } + return out; +} + +export async function fetchCore(client: PublicClient, address: `0x${string}`): Promise { + const vault = { address, abi: SkurVaultAbi } as const; + const [modeRaw, policyVersion, policyRaw, membersRaw, assetsRaw, proposalCountRaw, pendingCountRaw, executedCountRaw, nativeBalance, blockNumber] = + await Promise.all([ + client.readContract({ ...vault, functionName: "mode" }), + client.readContract({ ...vault, functionName: "policyVersion" }), + client.readContract({ ...vault, functionName: "getPolicy" }), + client.readContract({ ...vault, functionName: "getMembers" }), + client.readContract({ ...vault, functionName: "getAssets" }), + client.readContract({ ...vault, functionName: "proposalCount" }), + client.readContract({ ...vault, functionName: "pendingCount" }), + client.readContract({ ...vault, functionName: "executedCount" }), + client.getBalance({ address }), + client.getBlockNumber(), + ]); + + const members: Member[] = membersRaw[0].map((a, i) => ({ address: a, roles: Number(membersRaw[1][i]) })); + const counts = members.reduce( + (acc, m) => ({ + owners: acc.owners + (m.roles & 1 ? 1 : 0), + approvers: acc.approvers + (m.roles & 2 ? 1 : 0), + executors: acc.executors + (m.roles & 4 ? 1 : 0), + guardians: acc.guardians + (m.roles & 8 ? 1 : 0), + }), + { owners: 0, approvers: 0, executors: 0, guardians: 0 }, + ); + + // Second wave of concurrent reads: per-asset limits, velocity and ERC-20 metadata. + const perAsset = await Promise.all( + assetsRaw.map(async (asset) => { + const [limitsRaw, v, symbol, decimals, balance] = await Promise.all([ + client.readContract({ ...vault, functionName: "getAssetLimits", args: [asset] }), + client.readContract({ ...vault, functionName: "velocityOf", args: [asset] }), + asset === NATIVE_ASSET ? Promise.resolve("KASH") : client.readContract({ address: asset, abi: erc20Abi, functionName: "symbol" }).catch(() => "TOKEN"), + asset === NATIVE_ASSET ? Promise.resolve(18) : client.readContract({ address: asset, abi: erc20Abi, functionName: "decimals" }).catch(() => 18), + asset === NATIVE_ASSET ? Promise.resolve(nativeBalance) : client.readContract({ address: asset, abi: erc20Abi, functionName: "balanceOf", args: [address] }).catch(() => 0n), + ]); + const limits: AssetLimits = { approved: limitsRaw.approved, lowMax: limitsRaw.lowMax, highMax: limitsRaw.highMax, perTxMax: limitsRaw.perTxMax, dailyMax: limitsRaw.dailyMax }; + const meta: AssetMeta = { address: asset, symbol, decimals: Number(decimals), limits, balance }; + const velocity: VelocityView = { daySpent: v[0], dailyMax: v[1], envelopeSpent: v[2], envelope: v[3], envelopeResetsAt: v[4] }; + return { meta, velocity }; + }), + ); + const velocity: Record = {}; + for (const { meta, velocity: v } of perAsset) velocity[meta.address.toLowerCase()] = v; + + return { + address, + mode: Number(modeRaw) as Mode, + policyVersion: Number(policyVersion), + policy: policyFromContract(policyRaw as unknown as Record), + members, + counts, + assets: perAsset.map((x) => x.meta), + velocity, + proposalCount: Number(proposalCountRaw), + blockNumber, + pendingCount: Number(pendingCountRaw), + executedCount: Number(executedCountRaw), + }; +} + +/** The devnet RPC caps eth_getLogs at 10,000 blocks per call, so the scan runs in parallel windows. */ +const LOG_WINDOW = 9_000n; +type RawLog = { eventName?: string; args?: unknown; transactionHash: `0x${string}`; blockNumber: bigint }; +async function getLogsChunked(client: PublicClient, address: `0x${string}`, events: readonly AbiEvent[], fromBlock: bigint, head: bigint): Promise<{ logs: RawLog[]; failed: boolean }> { + try { + // `head` comes from the core read and may be a few blocks stale, so the last window runs to "latest" + // rather than to `head`; that keeps an event mined between the two reads from being missed. + const windows: Array<[bigint, bigint | "latest"]> = []; + for (let a = fromBlock; a <= head; a += LOG_WINDOW + 1n) windows.push([a, a + LOG_WINDOW > head ? head : a + LOG_WINDOW]); + if (windows.length === 0) windows.push([fromBlock, "latest"]); + else windows[windows.length - 1][1] = "latest"; + const chunks = await Promise.all(windows.map(([from, to]) => client.getLogs({ address, events, fromBlock: from, toBlock: to }) as unknown as Promise)); + return { logs: chunks.flat(), failed: false }; + } catch { + return { logs: [], failed: true }; + } +} + +export async function fetchActivity(client: PublicClient, address: `0x${string}`, proposalCount: number, head: bigint): Promise { + const vault = { address, abi: SkurVaultAbi } as const; + const fromBlock = BigInt(DEPLOYMENTS.deployedAtBlock || 0); + + const firstId = Math.max(1, proposalCount - MAX_PROPOSALS + 1); + const ids: bigint[] = []; + for (let i = proposalCount; i >= firstId; i--) ids.push(BigInt(i)); + + // One log query for every event we index; the devnet serves each getLogs call slowly, so five + // separate queries were the long pole of the page load. + const [{ logs: allLogs, failed: logsFailed }, proposalsRaw] = await Promise.all([ + getLogsChunked(client, address, [proposalCreatedEvent, recipientRegisteredEvent, recipientTrustEvent, policyActivatedEvent, modeChangedEvent], fromBlock, head), + Promise.all( + ids.map(async (id): Promise => { + const cached = terminalCache.get(`${address}:${id}`); + if (cached) return cached; + const p = await client.readContract({ ...vault, functionName: "getProposal", args: [id] }); + const pending = Number(p.status) === Status.PENDING; + const [live, vetoable, approvers, guardianConfirmers] = await Promise.all([ + pending ? client.readContract({ ...vault, functionName: "liveApprovals", args: [id] }) : ([0, 0] as const), + pending ? client.readContract({ ...vault, functionName: "isVetoable", args: [id] }) : false, + client.readContract({ ...vault, functionName: "getApprovers", args: [id] }), + client.readContract({ ...vault, functionName: "getGuardianConfirmers", args: [id] }), + ]); + // Terminal proposals keep the confirmations they had; the live recount only matters while pending. + const raw: ProposalRaw = { id, p, live: pending ? live : ([approvers.length, guardianConfirmers.length] as const), vetoable, approvers, guardianConfirmers }; + if (!pending) terminalCache.set(`${address}:${id}`, raw); + return raw; + }), + ), + ]); + // viem types the args of a multi-event query as a union; narrow per event name explicitly. + type LogWith = { args: A; transactionHash: `0x${string}`; blockNumber: bigint }; + const byName = (name: string): LogWith[] => allLogs.filter((l) => l.eventName === name) as unknown as LogWith[]; + const createdLogs = byName<{ id?: bigint; memo?: string }>("ProposalCreated"); + const registeredLogs = byName<{ recipient?: `0x${string}` }>("RecipientRegistered"); + const trustLogs = byName<{ recipient?: `0x${string}` }>("RecipientTrustSet"); + const policyLogs = byName<{ version?: number; activatedAt?: bigint }>("PolicyActivated"); + const modeLogs = byName<{ previous?: number; mode?: number; by?: `0x${string}`; reason?: `0x${string}` }>("ModeChanged"); + + const memos = new Map(); + for (const l of createdLogs) memos.set(String(l.args.id), l.args.memo ?? ""); + + const proposals: ProposalView[] = proposalsRaw.map(({ id, p, live, vetoable, approvers, guardianConfirmers }) => ({ + id, + kind: Number(p.kind) as Kind, + status: Number(p.status) as Status, + tier: Number(p.tier), + requiredApprovals: Number(p.requiredApprovals), + requiredGuardians: Number(p.requiredGuardians), + securityReducing: p.securityReducing, + riskReasons: Number(p.riskReasons), + policyVersion: Number(p.policyVersion), + proposer: p.proposer, + asset: p.asset, + target: p.target, + amount: p.amount, + createdAt: p.createdAt, + executableAfter: p.executableAfter, + expiresAt: p.expiresAt, + data: p.data, + liveApprovals: Number(live[0]), + liveGuardians: Number(live[1]), + vetoable, + approvers: [...approvers], + guardianConfirmers: [...guardianConfirmers], + memo: memos.get(String(id)) ?? "", + })); + + const recipientSet = new Set(); + for (const l of registeredLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); + for (const l of trustLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); + for (const p of proposals) if (p.kind === Kind.TRANSFER) recipientSet.add(p.target); + const recipients: RecipientView[] = await Promise.all( + [...recipientSet].map(async (r) => { + const rec = await client.readContract({ ...vault, functionName: "getRecipient", args: [r as `0x${string}`] }); + return { address: r as `0x${string}`, trust: Number(rec.trust) as Trust, registeredAt: rec.registeredAt, activatesAt: rec.activatesAt, paymentCount: rec.paymentCount, totalPaid: rec.totalPaid }; + }), + ); + recipients.sort((a, b) => Number(b.registeredAt - a.registeredAt)); + + return { + proposals, + recipients, + logsFailed, + policyHistory: policyLogs.map((l) => ({ version: Number(l.args.version), activatedAt: l.args.activatedAt ?? 0n, txHash: l.transactionHash })), + modeHistory: modeLogs.map((l) => ({ + previous: Number(l.args.previous) as Mode, + mode: Number(l.args.mode) as Mode, + by: l.args.by as `0x${string}`, + reason: bytes32ToString(l.args.reason as `0x${string}`), + txHash: l.transactionHash, + block: l.blockNumber, + })), + }; +} + diff --git a/web/src/pages/Security.tsx b/web/src/pages/Security.tsx index 1877cd0..dea85db 100644 --- a/web/src/pages/Security.tsx +++ b/web/src/pages/Security.tsx @@ -9,6 +9,8 @@ import { useTx } from "../hooks/useTx"; import type { VaultData } from "../hooks/useVault"; import { fmtAmount, fmtDuration } from "../lib/format"; import { computeMaxLoss } from "../lib/maxLoss"; +import { postureItems, type PostureItem } from "../lib/posture"; +export { postureItems, type PostureItem }; import { Mode, MODE_LABEL, ROLE_GUARDIAN, ROLE_OWNER } from "../lib/types"; export function Security({ vault, onChanged }: { vault: VaultData; onChanged: () => void }) { @@ -138,24 +140,6 @@ export function Security({ vault, onChanged }: { vault: VaultData; onChanged: () ); } -export type PostureItem = { ok: "ok" | "warn" | "bad"; text: string }; - -export function postureItems(vault: VaultData): PostureItem[] { - const p = vault.policy; - const g = vault.counts.guardians; - return [ - { ok: g > 0 ? "ok" : "bad", text: g > 0 ? `${g} independent guardian${g === 1 ? "" : "s"} configured` : "No guardian: nobody independent can veto or freeze" }, - { ok: p.guardianRequiredCritical ? "ok" : "warn", text: p.guardianRequiredCritical ? "Critical transfers need guardian confirmation" : "Critical transfers do not need a guardian" }, - { ok: p.delayCritical >= 24 * 3600 ? "ok" : "warn", text: `Critical delay ${fmtDuration(p.delayCritical)}` }, - { ok: p.recipientActivationDelay > 0 ? "ok" : "bad", text: p.recipientActivationDelay > 0 ? `New recipients wait ${fmtDuration(p.recipientActivationDelay)}` : "New recipients can be paid immediately" }, - { ok: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "ok" : "warn", text: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "24h outflow cap on every asset" : "Some assets have no 24h cap" }, - { ok: p.envelopeBps > 0 ? "ok" : "warn", text: p.envelopeBps > 0 ? `Circuit breaker at ${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}` : "No loss envelope configured" }, - { ok: p.policyChangeDelay > 0 ? "ok" : "bad", text: p.policyChangeDelay > 0 ? `Security-reducing changes wait ${fmtDuration(p.policyChangeDelay)}` : "Policy can be weakened instantly" }, - { ok: p.recoveryDelay > 0 && g > 0 ? "ok" : "warn", text: `Recovery configured (${fmtDuration(p.recoveryDelay)} delay)` }, - { ok: p.approvalsLow >= 2 ? "ok" : "warn", text: p.approvalsLow >= 2 ? "Routine payments need two approvals" : "Routine payments need a single approval" }, - ]; -} - export function Posture({ vault, compact = false }: { vault: VaultData; compact?: boolean }) { const client = usePublicClient(); const signers = vault.members.filter((m) => !(m.roles & ROLE_GUARDIAN)); From b435a24f98ed722f0ab437f642dddb9232a3eac0 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 03:14:06 +0100 Subject: [PATCH 02/44] fix(mobile): queue navigation, memo encoding, historical confirmation counts Found by driving the app on an iPhone 17 Pro simulator through idb: proposing a payment, opening it from the queue, confirming, cancelling. - Open the queue navigated to a tab name from the root stack, which React Navigation rejected; it now targets the Main tabs' Transactions screen. - The purpose was hex-encoded before proposing while the contract takes a plain string, so it displayed as hex; it is passed as text now. - Finished proposals keep their historical confirmation counts in the shared read instead of showing zero once live approvals stop being re-read. --- mobile/src/lib/describe.ts | 7 +------ mobile/src/screens/Send.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/mobile/src/lib/describe.ts b/mobile/src/lib/describe.ts index de5e7c1..408ff53 100644 --- a/mobile/src/lib/describe.ts +++ b/mobile/src/lib/describe.ts @@ -1,4 +1,3 @@ -import { hexToString } from "viem"; import { fmtAmount, short } from "@web/lib/format"; import { Kind, MODE_LABEL, roleNames, Status, TRUST_LABEL, type Mode, type Trust } from "@web/lib/types"; import type { ProposalView, VaultData } from "@web/lib/vaultReads"; @@ -34,9 +33,5 @@ export function statusText(p: ProposalView): string { } export function memoText(p: ProposalView): string { - if (p.memo) return p.memo; - if (p.kind === Kind.TRANSFER && p.data && p.data !== "0x") { - try { return hexToString(p.data); } catch { return ""; } - } - return ""; + return p.memo; } diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index 56f750f..5d142b7 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -1,7 +1,7 @@ import { useNavigation } from "@react-navigation/native"; import { useEffect, useState } from "react"; import { Pressable, Text, View } from "react-native"; -import { isAddress, stringToHex } from "viem"; +import { isAddress } from "viem"; import { SkurVaultAbi } from "@web/abi/SkurVault"; import { fmtAmount, fmtBps, fmtDuration, parseAmount, short } from "@web/lib/format"; import { describeError } from "@web/lib/errors"; @@ -17,7 +17,7 @@ type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredAppro /** Send flow: the vault itself classifies the payment before anything is signed. */ export function Send({ vault }: { vault: VaultData }) { - const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); + const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); const invalidate = useInvalidateVault(vault.address); const tx = useTx(() => { invalidate(); }); const [to, setTo] = useState(""); @@ -50,7 +50,7 @@ export function Send({ vault }: { vault: VaultData }) { return () => { live = false; }; }, [ok, to, assetAddr, amountText, vault.address, asset, amount]); - const submit = () => { if (!asset || amount === null) return; void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [asset.address, to as `0x${string}`, amount, memo ? stringToHex(memo) : "0x"] }); }; + const submit = () => { if (!asset || amount === null) return; void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [asset.address, to as `0x${string}`, amount, memo] }); }; const remaining = asset && amount !== null ? asset.balance - amount : 0n; return ( @@ -92,7 +92,7 @@ export function Send({ vault }: { vault: VaultData }) { )} - {tx.state.phase === "done" && } + {tx.state.phase === "done" && } ); From 4766462be7a10a91a08909d5d7e75b080102c551 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 05:02:40 +0100 Subject: [PATCH 03/44] feat(mobile): Safe{Mobile} structure in Skur's pattern, onboarding and app icon Rebuilt every screen on Safe{Mobile}'s skeleton: splash with the logo, three-page onboarding carousel with dots and one button, Home with the vault switcher (identicon and approval-threshold badge, bottom sheet), chain row, big balance, quick actions and Tokens, Policy and Members tabs, Transactions grouped by date with a plus button, a Confirm transaction screen with hero amount, To card, advanced details, Risk review and Confirmations rows and a sticky Sign-with bar, Send with a big amount field and the vault's Transaction checks card, Security and Settings as grouped rows, three icon-only bottom tabs. Skur's own pattern throughout: charcoal ground, #FFD000 as caution tape and highlighter, Space Grotesk display type, the web logo as splash and app icon (rendered from the same mark), identicons identical to the web's. Compound controls carry explicit accessibility labels. Verified on an iPhone 17 Pro simulator with idb: onboarding, vault switcher, proposing a payment through the sign bar, confirming it, expanding confirmations, cancelling it. --- mobile/App.tsx | 32 ++-- mobile/README.md | 2 +- mobile/assets/android-icon-background.png | Bin 17549 -> 5236 bytes mobile/assets/android-icon-foreground.png | Bin 78796 -> 19781 bytes mobile/assets/android-icon-monochrome.png | Bin 4140 -> 19781 bytes mobile/assets/favicon.png | Bin 1129 -> 28809 bytes mobile/assets/icon.png | Bin 393493 -> 28809 bytes mobile/assets/splash-icon.png | Bin 17547 -> 19781 bytes mobile/package-lock.json | 12 ++ mobile/package.json | 1 + mobile/src/components/Identicon.tsx | 34 ++++ mobile/src/components/VaultSheet.tsx | 47 +++++ mobile/src/components/ui.tsx | 221 +++++++++++++++------- mobile/src/screens/Home.tsx | 141 +++++++++----- mobile/src/screens/Onboard.tsx | 47 ++--- mobile/src/screens/Receive.tsx | 19 +- mobile/src/screens/Security.tsx | 96 ++++++---- mobile/src/screens/Send.tsx | 83 ++++---- mobile/src/screens/Settings.tsx | 102 +++++----- mobile/src/screens/Transactions.tsx | 58 +++--- mobile/src/screens/TxDetail.tsx | 121 ++++++++---- mobile/src/screens/Welcome.tsx | 89 +++++++++ mobile/src/state/store.tsx | 11 +- mobile/src/theme.ts | 8 +- 24 files changed, 757 insertions(+), 367 deletions(-) create mode 100644 mobile/src/components/Identicon.tsx create mode 100644 mobile/src/components/VaultSheet.tsx create mode 100644 mobile/src/screens/Welcome.tsx diff --git a/mobile/App.tsx b/mobile/App.tsx index a026442..0f88879 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -11,12 +11,15 @@ import { useEffect } from "react"; import { isAddress } from "viem"; import { StatusBar } from "expo-status-bar"; import { ActivityIndicator, Text, View } from "react-native"; +import { Feather } from "@expo/vector-icons"; import { SafeAreaProvider } from "react-native-safe-area-context"; import { Status } from "@web/lib/types"; import { Notice, Screen } from "./src/components/ui"; import { useVault } from "./src/hooks/useVault"; import { Home } from "./src/screens/Home"; import { Onboard } from "./src/screens/Onboard"; +import { Welcome } from "./src/screens/Welcome"; +import { Logo } from "./src/components/ui"; import { Receive } from "./src/screens/Receive"; import { Security } from "./src/screens/Security"; import { Send } from "./src/screens/Send"; @@ -29,25 +32,22 @@ import { C, F } from "./src/theme"; const queryClient = new QueryClient(); const Tabs = createBottomTabNavigator(); const Stack = createNativeStackNavigator(); -const navTheme = { ...DarkTheme, colors: { ...DarkTheme.colors, background: C.canvas, card: C.panel, border: C.border, primary: C.accent, text: C.text } }; +const navTheme = { ...DarkTheme, colors: { ...DarkTheme.colors, background: C.canvas, card: C.card, border: C.border, primary: C.accent, text: C.text } }; + -function TabIcon({ glyph, color }: { glyph: string; color: string }) { - return {glyph}; -} function VaultApp() { const { vaultAddress } = useStore(); const { data: vault, error, isLoading, refetch, refreshing } = useVault(vaultAddress); if (!vaultAddress) return ; - if (error && !vault) return Could not read the vault: {(error as Error).message}; + if (error && !vault) return Could not read the vault: {(error as Error).message}; if (isLoading || !vault) return Reading the vault from the chain…; const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; const TabsScreen = () => ( - - }}>{() => } - , tabBarBadge: pending || undefined, tabBarBadgeStyle: { backgroundColor: C.accent, color: C.onAccent, fontFamily: F.bodyBold } }}>{() => } - }}>{() => } - }}>{() => } + + }}>{() => } + , tabBarBadge: pending || undefined, tabBarBadgeStyle: { backgroundColor: C.accent, color: C.onAccent, fontFamily: F.bodyBold, fontSize: 11 } }}>{() => } + }}>{() => } ); return ( @@ -56,6 +56,7 @@ function VaultApp() { {() => } {() => } {() => } + {() => } ); } @@ -78,17 +79,18 @@ function useDeepLinks() { } function Gate() { - const { ready } = useStore(); + const { ready, onboarded, setOnboarded, vaultAddress } = useStore(); useDeepLinks(); - if (!ready) return ; + if (!ready) return ; + if (!onboarded && !vaultAddress) return void setOnboarded()} />; return ; } -type TabParams = { Home: undefined; Transactions: undefined; Security: undefined; Settings: undefined }; -type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined }; +type TabParams = { Home: undefined; Transactions: undefined; Settings: undefined }; +type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined; Security: undefined }; const linking: LinkingOptions = { prefixes: [Linking.createURL("/"), "skur://"], - config: { screens: { Main: { screens: { Home: "home", Transactions: "transactions", Security: "security", Settings: "settings" } }, TxDetail: "tx/:id", Send: "send", Receive: "receive" } }, + config: { screens: { Main: { screens: { Home: "home", Transactions: "transactions", Settings: "settings" } }, TxDetail: "tx/:id", Send: "send", Receive: "receive", Security: "security" } }, }; export default function App() { diff --git a/mobile/README.md b/mobile/README.md index 7a08ec8..8c802d9 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -1,6 +1,6 @@ # Skur mobile -The phone companion to the Skur web interface: open a vault, read its balances, queue, policy and security posture, and confirm, execute, veto or propose from the phone. Built with Expo and React Native for iOS and Android. +The phone companion to the Skur web interface, built after Safe{Mobile}'s structure in Skur's own pattern: a splash with the logo, a three-page onboarding carousel, a Home with the vault switcher, chain row, big balance and Tokens, Policy and Members tabs, Transactions grouped by date, a Confirm-transaction screen with a sticky sign bar, Send with the vault's own review, Security, and Settings as grouped rows. Charcoal ground, #FFD000 as hazard tape and highlighter, Space Grotesk for display, the same identicons as the web. Built with Expo and React Native for iOS and Android. ## What it shares with the web app diff --git a/mobile/assets/android-icon-background.png b/mobile/assets/android-icon-background.png index 5ffefc5bb57a3d7b39ec6ff4e96979226522cc49..f1d3b7dc929c0dbb72bcdc6b0c9048e0dec8af45 100644 GIT binary patch literal 5236 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7&w@K)Q9>#R~Q%s7(87ZLn`LHxo*hIpdi4o zk^dkEGxI-Qr6*D1cc1TLWMGiG22?Bw(xEs?jE2EzIvC9cqea1JNjO>(j+TU@CE;jE zI9d{pmV~1v;b=)XS`rT7lCYK|Di$~}APX7`7>&pw9Fe1uHyU{~YLCb>F#P|2QLC&0 fSlhFK3JPY103VK`BHOM4pa_GftDnm{r-UW|vsSAn literal 17549 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 abpAhC#ukaM?vUO90000G8SMI1R+4M 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

    f!0B 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 diff --git a/mobile/assets/android-icon-monochrome.png b/mobile/assets/android-icon-monochrome.png index 77484ebdbca253297baea4a7d416233aa47a45c0..52502da10fb26ece6096647d7d7ccf54a8783fbd 100644 GIT binary patch literal 19781 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 diff --git a/mobile/assets/favicon.png b/mobile/assets/favicon.png index 408bd746615785760b09e6f23fa8378d3e614331..14e4967fca6fc76747beeb9dc4111da1d1fb90c3 100644 GIT binary patch literal 28809 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 literal 1129 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 literal 393493 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
      H|zz{j8vX-lqku;-NW2E3;BMf3f>Jhxt3 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
      %-(a@!i`89VK;?-qg=ZiR0A&pVk z*QwtA8I#3~E1D=exysS-y56KT%{E?RRZ(Jq;%g)@k&s}@ z180^o?#h`nyPa6g#d4UFm;dhMST`Rlz?pmKJt=a&>=A-|_uk&bjMCaUp%!4s@vcU(XnAK?zAvAO^?EhSV=vWop!7#} zsI7Kb_k{_biZG%ioR-#K?mKMC7h33?Jm7#aQ(mUkFMg)UqXG%^lxH`u<+jCG*XUp1 z7}$wyJn8Dp=%U5amvo`3IfR(uI609dIGH+)70}TDr(<8`*@sztA$sHr~>7N zk$`_P8J#_eT)BAcMs2puzcQCpRs_lDUmxc~S_QBCKHUUMil6_E@tX2{DRgh5rkXc+ z;%O%Z$FrcIVT}l=3<=NAHj}g0U$(*b5*ku^@dBpl!rq2YYxrgJh-U(k5-_RUOc>6t zSoET%T;1sIx2+#SS?kak&gKy{g02-kD_~FV6u5d3`n)ehB4TjBzoW1ew}|_@9p9t2 zVUNh;(w`nUcPEHX&Lt0^vDux&F`b+*isA>UFn-bEoI}%zl#zzM#Qeo{B4;HJ{N##& z#t|xtwdpQ3tSf1*D9RQCHs3EPMMLB}w8M8K2x6)<#?Ms9i7OEIAleu<+VKTHOU@9& zc*?Wuupi$m_0j3MIwn=zSW=LR0phSIao~ZqKQ~{P)h{w;upc26E}qwx{6RQ0Un3%oJdpD(BQ7NP54Z+x2sV4_Z*wBs zLjiwzHzJnb8}veW=f2 z`mH0i#Lz@7$+}Hn4>9HYEiKXBOaaA0C+srSel-pdJy{@*Y6S|h|k!UN$N*kP)=0g^B@Ql<;P zX-$wC*d-KImCL1b{6Un8B+341!L;%3UxoPOrn&|}CNYPw``hCvF07<#Keh>&fdSu>Mq+3`3n?0Db) zcUfgkH7frFsjw5d+T$B3Zq78$zrvfkgky-J0s~oyVt#4OM@JEn`LudJ?LWgNS>kB! zKF%KPZMeNWjv^mh&q<)>A@i6B?X(Ch%@*IiJo43wa8I1Cy~;{0>$Vf}$Hm>-PTj*6 z(n^-zy!FkYCt8FyXX6(nOw|V&2qR$pzAQoY+Z_vQXd)?SDQ|DGCg{Z1B%1<$>RL1B zD!+-|!KVCc??Nc-W4$-;I1DY#S_8DK6l(YR=w}{I$7X?-adMrNgcGp~RJRGOI{)p5 zq@dH^tG)p?6EhSn`U?W3 zXk00=2E)h`$NIx&k(Y%vleQT&7)P}JpZfTK3B48gpj8;33P%vM(U}C_U*Wg@&$K|WD`D-hki4i1vZ zR*8F!a&XFWOD%C>#Yn{RGU34`*=){?=LOwCCx=#b0a1iCeLp>1oiby4`Wl)-mxYVPYGlsD!@&_VqgH3? zypIy&C(l#NQqD)=Sw_8XC#-NUY<;&x*{k8G=XFCDk&$FNbe3&+Gh+RJ1v+fP(!BfI z#@jRp7T+G%bdPP1!x!OqR;~(bkffJS{nOJhw^Ut+Ry#Z-17Z7UtDQNUkG%&AvX+J$ z1M5e9lQ}97_D9@1*Tyh+=!fZGSH)joyc!W&;}GQxCY1GBN6MZ5C(msmQa_va{h(kM zSVPik8J*~q_vv}Sz3BZLy@;oeFJ+#C8w4|D#iIL_C)wH>^h9Yy zC<{GyEL__Fy1|90ko5KbP;d<54oj8dS670=%;ehY!~|byg3zJ3h zMjr@mBVv@{h1McjghUu%zoK_ampx6Xh(YDhF7Y&}Sd#Xa!%q77I&ud|>cd6tFvqDy z;8yX+cONar;S!$rzdL8cZB@vBV_L0yhC=PAj1VbJU|voe(351$GDTsQlJ>K*(Z{!E zZ%b`jzCfn5X|WA>0-ty0=ymJ)WU=tfKx|ng&`UK6n}isBRip=R{Ebshgf|n~iD%)T ziHhT}!-;VA`%(R2;eUU+^+)hxIHvGRxZK|?R*IS!@EuclW4}54!rF-q|6L_`SPQ^+ z^mG#d3Ah60B<#f$C%((nWKU&T>%>CXU}{{WP^;3mVBUBhCgz)`i zUOt(cGLWRddTpKX@C;O^Ur(LsLQZxmUnVjf0U8~GEe5;Rt)KI(ST%n9d)Vp{m!~!* zkKnp+$mx3G`eT+sik@(a@e>w&7=?H*>6cOdJR;3ZI$0%}p}?-h#?GsD%t}JxE>%cQ z0j~q_3W&N2+dn+H{#oWV*Va`11>KQq>IUA^W*@YCM)~x^geXAx#9p~?Zr6$4g3`+P~}E)lPBF zp{9r=2W7Yft00eOmUwyB#oByH-$$_&3 z{UM68Km5}@>X(7Z3m1;tm<1;?b3?A5{^zpSk87g8d;hGhdBnWk=bOd0>0G%hN*I%R zqGW$e|Han4Zki?i9Y4Nw=*Gj3yIxtZGbam6IRG9KIMpu2&|+MJ$S0{N;XlgdvW-q7 z{KV8)2YxgPbvE%kjw0?%$0+jMPQTab$JyDT>Ly#%+IP%539I~GRwxKikNiw21>MCT zY6jTn3$wS_x_e~Lw-<8!cVKa{PQp+Gl&@I2PHVD+SVR)SUc2rf4g`5^9(q!yhcNO$ zO5{I0MMAHyri;M=qcz;v)wQI|OmY7d&$~kD=fxrSpPOB7*$H&f$^JTfX(OU|sq%ZB zI%E>D4ux$FjmAZF17&zi)KjTRulo7reP1iEwfw;{o;b2b`ba>(Fb5>^c6%0MUnAvO>AC#T13}B3;q8E7Qb&&nB*^2WT1p?!}VG3 ztGSZDOMl?=>?Xa_cVQzlh$#17$fkoKSmr_tm}Y%`2^e z(6Kz->!$Dijutl@(Xicm=}li88toLDks%Y6f+3Y$tUN|8{*VmIVBMxrd)IUjr2 zzae6w@E9ulam&$~P zR&xKqqv0h{Z0}$-X(~|H%o=s&5!vH^Y(d*w4z%N*2{%@X$gn<6IMG(#hwa0kf+@-j zhcoDszRz73UM2>lAgT>zP3_5L>!$vZUs3O9lkb}j#aUnb#sv>n)HBvHt2hT`#Y%wM zI~x)PpO>qs0vu->9TY0py{3DM_c|vBT0Z*~pkxDx%h>$L=Iq~m38RcZ97;xEm#Y&UEg)rrz ze|mj1WcuT&&ck7TLjP9He0}*ET7d9rt!h)7oF%Oq1TyLyxrCCv@~6==sN0;!MY(TF z+xzipirHEMD^fg`GqUjmk8~~we2f!b!@AYcWY2~*LT~X9V@~dtQ#HHetzfVe^c*Yw z$L@Rw;qmI>nNty4i{$yHnIIl9#Zlc57#EtSE~$`33!nY;ZUpUMx3L zhVki0Yx73AfTI`T%=IL2Q|sDSf?$CeLH*(FK~n~wK@^*6cwDr;IP$p-Vx6xRJdqm( zZHYzSqn&q^naqj}-tdf|n7T{!)0Ea1J@Us>o*v2fA%C8|4h{H}ldym1fl5?VCaHKa zbp2hH#2SU(lk;#6P;mSh?8RkvYN=`gs{s~yz_m{4q;eB!uNk9H`^bNtFqUM!XPrI?;$FxlPJ!xJ07dL#N_Uo_X|XBvyGW&j zMA^~IU3a(QPZB)*sw^A5ZuEJAD4+fw{(Quh{fHI!3*;}7UzpQ2Fwt+p)qkH{{5Tjj z(-4Wz$>rlL)jzy<^~lbiZOppi@zGfEVm34GRy3e0GZ9Favp+N9_uh5iCQ@nk&WaX( zV41Z!LG&gw^B)-^aJ7{JguD%h8)>7y$JtVtbWmKq*_-H%l92*;Dr<#EIq>~axJ$-# znlt0)!WOT(__ni|nWmccK7`1f33-(YT&D%!Jk9va`rMh)>|jgi%@wACqS)!Zsw@sf z1jHj5L_q&FNq4q`jx2QQZ3w>x>z_IAlg_*D@i`in=2^wudo;0zs#1pKRCjCw4Z|NE zgU+I&zrOFWqMe*Cj;jLM0rKe#TBRI`Oi&8-uiRDIs6!_`32=6n<9lLC1v`_|eVc3; zk-jBZ!Sowa?sKb{P&6oR&#wbrP)Zql)U$j0h$(PNhOmTQeJi*RrV77xar*^bnR*%Cgjs>$nfe-Q1Rxat{U$agiRr|xSGHR z{+&Ch=|^(tlU9$#u`3a6`sLz>MvaV+^sYcFEJQSU=VaBM_fu7wehDtkNzCDYXbhp^ zgVqOd0{n@Z7-EGb1p*~S7#l}0vmuZyBxQo1O9|f5VKXgl{`ACI!>ypS^!IgF^?5R% zYUXYN ztEo#1^rm9+V)NTC)DZ#LwM)RIaU3Y$sw~V0zRLd0V*yEU{~4-AzIGmyo=AwV7j<_* z+;1YRo>He-%!_|o&PN{5=;`)G2uTy=!)L<~jIaXlky_v1;Sc`ppF9^{4Ey+U?c3r1 zWBHL0D9rZLgFyVf%{1m?oLELySrn9(9EX2Q5i2V1Uo$Y4iy3<LN(Ka6?3i^rL234$qUv=;kZ`_NTu_(PG?F|BtZtBeC<*px=4`yF2@0p?n z$0aU<;@Li`s}J%5BTp8h>;w2D+gYNtJEquE2$9I~j#ezl)oIV|1Qc9Sz$wx%%rOd4 z@dc5WMY;#L5!5=bjqHq@19~Fd2XDO@kjC4oIdzv!RB-JH7a;rrLf6&PRb75JNnG~2 z17PZfC~*EEyzFLoTsC|cLrAPNGpQd}%V*`p&V3)4sXFTbWLP%wdc_p4JLPIV6wYVW zqONa#luezoSRB7c5#%8GRq)wH8UA;@KZ)>abBYEAm)Ns|t_>SmiU;5eH-B8GBL)b2 zOu)iG4rEJtnFU7^L2YsxVK`E7(a~`7md6dAes021ruw}NT7xlrrR&hHKWBci6z_H7lX&z(2CL&B7Np&T^hP4<0llE9cWbq*kBXm)tAE? zr0yzEXxFn|RlN!S#V#5pjnwGa52p9AUUbrt&nl-|87R*NAXMa7b1Zt-I1yZ^jtRLM zh^YI-PiRX<9yC3~ktJ3zMKJ;1JXKR`iuMI_*CJZ03?chIJt-kZQ_KaTTAQ3 zMe1)!ZdA<%{trVZv(n|MZ!+_O)a~#uj=Ws|QxHIp5)wBv9Uy)v7vC&Z=XgOF${{l6 zlWF-&M_ZpJzh95-Mu~ghrcSeGqi|As!yAPVu1m%0*Z$*ti8q6OYZcV7{yu)m2(|#J z1MuK_qMACNkquOO27Fsy7Kg2S)SE6x5&oIgqN^okmc<=t;#r2@xK8(vi zGkf;;dQoS_L93t3hl#djMOGId(cy)!nY(>-nWxS=j9qVw%#1f z%Kx+h^VTPNMcH|L;La?;xh}H*@8@?sW(Q}*gzF;}WCAH5NZ1f!f&@LM^BTdP<>&R05_1ofP>_>G$^_j~v$5Z|(4C&PpX6P-M{+(_!pE|AS(DJdq)#?l zX${HFK@ncOt#IFcX;3Cwf-qnxm_&Gb{BrAIoo~i?AJ=~f;Pe8uylL37W>P~62v?-G zS6geJd`6CQLjBZ^W+WH=$l9`t*q65=oPSU+$&x>&Rnqq8ecS6w<2UNqN9SQD=@zQY z$1H$7(;Q@|`L9f7jzPJy4ob|FY;r_82@F z8vQm75><<`3bWgK>517m9Gg=q3A8Klf2>XJM_xE&wvTmhY^}&FW*57;XwmC2%U(l~ z9lC0t7PIQ1kA&+M=PcIZ7p*2@`))e+|5Vz0kj=GyR<%)}1Gjr3Q>YMb@%Lgxr8EEi82Lz9O1qolk{phMImq)>2RV z6pGcA)qQe0zIo+6S7bsS@LM;oL_PjDL2`ixf9C?;)AorQLJ2jF{Jd-H941?3Wx_g~ zj2exMODL*Vp?(mKD&50Uf3|Mlf)Ly-XOO77Ic+9;LI)*SJyHmz8j8%b+UySt99`t$ zPovVwd%pWwGYr=aDx=I%%9Jm(Xa|pcVtL%(!d|y+A3ifXw#o)Qk2fA#Hmun?G;p9W zBua67S^7kb=_zwbh!c<2LZQx2}W(o%VSryG7$+8{{V+e^Y|dFf<@O5g`GOipZEA z7wu+e(jmu)(*x!^jjgvgc$-3y&|fg%)5A`6T2YGJaxhsTHol*6GuhvDiP+4A%mqVE zLg%9F>lj~cubnIgD<=0b@7O7c`EJb&!u`_4JP=R$QAZFucaeehP5;yXS?E6=_qJ{@ z0XI3N8W#lx*PM<;!uE&bvG?8BsMv4y0(?vEHf~igpyB{cRLVrn2C?Rx>SoxDZ%=@* zJv@hX?DhW1xLD9B8Kcnx)0#-8BdWX#Cbl$*012pyDU#a*50!4lgQ<+E@pVV0VB5_^pbR#gG-E*^Db@ z@&BBfhKk0wr8G~H!lj@`r{I`#y2eJD1o*-_>uB|r!_3R-UOl>{Uf)!ytCx$esGj|Seb%SU^8PeSY%Gi)|egZr2J!x^mL z-+dO8fW9p&H7yQI_h4}x+D3j_FP$qUNPvIlKCIX~ArUBVG8{e0b(}1~=X6)B;1h=WDp(D^p-LY~ zPf1UC%58Y!0KI&c-KOBGf(cM?xlGL^{aA^U!iuBB=fvmMtOq36MI)VyyuPy*37dSx zO(JXcyFMD@yCJ2n-9;5& zU|4qDs(L2&N9J!`>>0d7IFTW>_QT_AoGIL0MURpUf}8o$6k{f!aqBJBNw!UrY(#Nh zj^J-3nVw3~=K2K&$r7e=FJs}FhcV{RRQU9qsvNao&`_RSob;O$)=D=p-ELFqYnxS1 zyog%pGM|2w?VK|_b+vqBSma5~ybFGV6M}GhYIVx(rcS%EQiHGjOUlK@vFme1)|WNa zLf8WAgTOp!CuETM58C!q>wSQ&No+GNx&f@ZL(LOix#ISv8t|_-ekrdhB6VDB>OEb zARqLRd~L^)#LDx#+U%rF9+7!$>D2CiY)Xlf_c26d?>2Y4V67N9afNaw>}94!t+Ji=%-y)8`~VU(G}^M5kYXebVrdwmBkm!c-*3R+YPHGjPdO~keh9C9UJRw%yn&1C1bxQ1-TQFrpi>PC zGy$CEY;v5c$hi6F0-MoTKbpch+iI4WxVQJCa<||Hced0=}#+MeK8qt!B4UcR{ZfkxwKUjxH#^rIC zsX8Vp<-URNnt6IKL;f2it&l}vO_{=t;_gJ$*+~mPB^{X_{s_0(5n=Z=u=D`xaT=p; ziyKXI;5fLfq+N^HRda8|H@rkChaHUy2B+_3vQbd@Wb=!Qt7Ev%ehSIS`!U5jOOygn z-@N+0RR>*GzK{J}BJifjg?w!=h4dG0pCfi08!1Od##xpaOMYCxWT*XJOxhR;acM>Y z&F9%e_SfaRHJVw8TuPy>1bW`r3bk*gKqXe>-Tq{&ZqRe%!yXaI4IWhNO!kks?OFak z9RmgjOo(qss0XnEs0T^Tu&shNXL!S={g&_vQGH9fTm2mmQqj6o0m`7porZC%>x)>* z$?jRPSD{fVb!WM4WlOj8OcF3kI_z6BZ{Df9s!k3l(%D6PsOAC#&J|U;#F=43Lh~Iz zHe|4uk07D})#gjJYhO2f7?!_oq1cvT=E}t$fJadMycfNYxt~+_MW_!Ff+L(_G4#p? zw{TK!IhQ1^`5bLhe}H(wZ6M4&K5?eM$cv1|YL(qCgLQ35m@8dBdX>qkR1sTyL zfS+@&>Q=-6A1OO#rNhWZ5IKQna&y4|G);Stp711{c z-_DPVX6+9hsnDk@UKm0sY8#!mP0eN zNh%JBuAo^~27rN(!=`}Uu_2G64Z=feLIrqef29TN<`mn2->7h7sOuF)2z*3vhC}?a zhq5~`O5L`&9Ms%MUYy5CxQ;!4y56_)+1BSp%liaffo)lAdbs}uZD@1v%qI#I0ti#M zy>G7gL4ifZ1P0>Tezd02>z!IAZjcPcXA)n|d^00;iT_K~g-m-&137t7L=CT?l+VM; z9v?o6f)lbY53(6}o{;Tba~t1iBlj(;63tp$5g`}`#x*EH2mUzk)CIU4b$%%Uhj%gA z25w!~?0vz;O>vmFt`iF0DS>_`Sf&kU5l{ympg{h~fbnqwDvS`i2OmP+!s)o5kA=}O zP$m=>=Kx|c*zuU$P#@0}^S2fkv-{q6!~Li^;$Q}GRZ1Ik6YArw3m4eukpS|px4R&y z@OO3Lr<3oeG~5*LmI26gJV|_tp?NueA|(=XU-WFKj6&4lTaSDXnryY@cXug3;c6Nk zz@|uQx*jA-l%yPNn%-T)TV59@QcT{X>(R-%8}Fhz~M zd2Z0x)((qLx729B|3nyuM;|;&JveK2v+6EINv^3KH!BG@dIfd)SdHq@MNlt8zGh5r0Rba6 zhCTFGW;a!#D*x;>&e(y*n69GcOTtddt9}D>)~5e?84NP0ZO+Cn-$Q&xu)zG{pT7_2 zMo75$A+$d|t@3UX9_o-+zN(W7_}Ez9Alj*gGHF3nX-ab2MXxTlK`(>GJksh3Ik*Wu zl|;WHDrgXB)7N*OcOOoKC=VBs`;CQb!L5uvtUMZE6uAY4rDB?}tfhO#RXq@A7({$4 z3f#~HwwRO=7gt_3>bKVA6>az28|&MjPpecCKBlq7GD21OZ1`$KU3W{dQUKs1^uIlP z73CVrF=%BJVq?DvSF}L~g#$Km!^L_L1V6Y_<>ma+AzTLIe^sc~(1>~%O=E9yzqz|L zZoK;&o~l_!C<7Fyfj-5p7e1mQ#-%bhNeYKt&%N6st9QRNUBwpII_+=#sK z-gr7l8~Z5(udHz^kwe55!Udz>@Ea+Ape? zHCbIYcE9HCA_Rm-Iu~%=USoP-G z{D^UN4hU4UN`oXy%o8=d>+?%HbIM4U>G~vndARWRRiyO=v2(z|7IhF&s*Cd9k@?_2 zmxZ!;g2;%Uy@F_MB#_i49VA+6;u0#>+FRRbd%mT1wx7>6eh|Mxv5ALZbD4-CF!vpE1Q6U7v6IZY;mAYjCBIp@z~GQ%3^j1|Eo4uYsdM zF9^gJ&24Qh=R!M1sGxdbI;F^Ok|8#5P$gBbF{jFEU7^oP6NqH%;=&z0bivB!f>fD$ zq%99qXlJj?wLSa#&lo})^r$4zskjnwvjR%tmz4t2M6lOV_(LU6SkXT z>UR&o8%QD=zh(5}^r@Puv^}D?AO>a0B3TiMhB3VfKt!~7t4himS zsPfPJ6N~mOcaYx30@@$RTH3z{Cl~$obA)AG0#}13Pm{fHoxVkp=`2U{G$7K>C4<65 z_hNY)2Kf&743uo+TCu>hWE11I=UIfe7K1tQ>!2A>6b5HfUY-J|l^Pp9B5DK&CU7f8 zinvOyuv`7I+%T+SBD)+zsPX!I1(vpCvJ$saEA;kwHvEz4R(}vq$eHeWAwX^%LdwO8 zR)vR`*M(qc)+J-hq@{PTrP#j{QJDqH%x<}#Q`AENy>MNTo=Lb_`QDTlPFM|-Ai$v zj^)faU@1^<5+vHR>hHM~93EY2N@RCQ5a{d(N{I$V3*};b2Dky#8m!*AE2u!WcQ*oc zZ(lVyPKbKPJALCe87soEJ{B@y4oEvNpG6KDm^i=83hba;s&7JIR4UL^&lQ1&|F^${2 zZF$%jk9_IzJEc3eM^*Iuh@6336O!n&Js)WP;6FVO1;Sblg3im>Pfz|x<$dYiRzL~E zS)9Xanp4MtNo?0_)Q@)&FF#BW_1B&(j4fApJZpwS_Z$tMpw+bp4#i_@Tx+LFSe z*UE7ooxaAZL*RRUZvCg$wnu@mZG_{0h>S^>^OQqHC5kKT!?V10P09c8v(5=sGx z5kDid8wnf9{b*Fno8!g*L-8qdQf_$Yclpor9HBS7L{F>ijSY?EUB?>R<#Plebw0}pI@o>Hzo4Og`$Q&RZdo)cV$n` zX$8?-e6HH?bSWWD88NAub+%=4u_c%#)@2ohsP;sktq3&)^bP7p$=h8YyaKNl+nv#q0_b*bK)yS7YunTU9p zL%-%w&(Qjc+b>|~W;&L42H!IbG}IhR70^86i!h)`9; z&VL;tpG^k7aC$QPH2y3$TnW9f7%$CfCVRDIUXE5nzBD22CHX8tFzc*U61(bpW_JZZQ(uNBT8*WdF7h8`9*iJ$fgy1O*IG3} zMEJ3V;OcxhR@NMf5A#(H>^Lcrl*PNK27& zQv!d^_5ZCIcXW8idlmdpMvt`C?9K%rj6|HqNhIWxEUosKJNObI98@U=5kr~ipZAC< zs!tBgYh0zP`EZsaiB)BBx4F6PWRc>OQW$WcLfr_D^h#q4wQaA+UB^Tym zhsLE$!wW=&`v*{Lw_bc^6_4>d7L)oSXF+ymXpwSp=Q(p?kJq}mEKxF*d~1Q% z$KhLgY$UtfcyFhqfw-N5&U_o>FRPhB5A^MACjBxIwa5ww=y`|?jI@#Vpqa!Ga}cT3 zciHXz#cP3x8bm_~0HgZP?nUuP>wGNWcoieTSz6%GjNnN0(@2}{ZPq*Mq(+NerXLy8 z+7#*b2$QX*L`)Vn0zJDXPZ#z<*Oe^~hw|luG;zu-VH6mjI_c{@MVqg4<|H=gX9Axd zV(8Pb;=(61Sk?E~b^QRh)EBoQf+L+TfP~=Ve-)Yp)p?)JXCDn9B7%yKtkl4$vBWmv zq?<7r$*Pr(oan)H3N_%9h&7=gJCKSRW7z7>OS3KI>-7B}`lAB~h&YkL4a|{Yd;}ix z1p3^s%6w$&Ou~#g-~2XvX2kLd-XoG4Rmv0txdbDaV}zEd29kU8*qC4~1t5c$+;ba@ z2s-JW5L+6X2X9ukc{^`){!#0ijzSd+e0<^%bdZ&!pd+V=MsYk@e_eBq2Hlhm>+)%o zs>JFMqT=Op+5vNk6reXm&+9Q$yD=w_l`h@XXt_;UO==oeZ-wA%)* z0rsr5XUf7G?6K)MeIE19la{i(M7 zZxOjL&SDhCX{!hfq+C0W}<0^atX8F^Oq{s`LCEO+wu9 zKdh1KbWUUVmp`Cr=Nk&NQ&MeEhKRHIvnkcxRk~4Yy?}yz2=HP{`|cp4C>{@lM9Vm4 zD`K|THa`ydr}cF@xWMaxn>Sp|*O=i!;l){fbln>3p<~m=mJsoA@wm^_{S+DriNw9v zp!k>+T&nMoL%L`&hjpk8|8Vyn1z-@MBp`PUsM{s#rpj9H|O@5k0o)^YgN#e~X zZ}WZWokrk}JNHa5UguK|FD3CBEHqZIKm7SiGfj z(CL1M;jH97j+VR|A9ffasCv6Jx8kTY5|tnugd@TlF*scIWDlECec4><#tq4h4dIX3 z*fGe+UM5ri;p)neoZaGoxM?>y0~RlwFAH^kN{&OsMMjtZSD>OG^%GQ^MN}`;4{f94 z25C5NLKviQVxcBMwE-Rh^u49>Df?Jf+Y`gkn}6jU3h~+= zd#R9wb_sylR*bx?5P%&;V>w{JoAV;_pDP)6g_0p!4#oljPnl@5c40ygT#Crji4leg ztYpP`Dee=*=zqQ8hzjs3hW{%kh+(sn9cuBT0Ww2Pfzi!2`p7FVT8EY?zbSW}Y)`Cv z8kvH|-dB71Y~0TXurY{j4SVV-hHt93jwngQT7 zFYwu0g&^^mk{hjh&HqTuYsK__Kv8PG^>M(6&7^xV0A#S9hgoC2ogdEQS0OW1LaffR zusc*$T<2-5KiB?}7Idx~`2Hurxw&@L-}mIyYKpL1jqa??^`gsF-Ii+w`w6E@J{|wgc z4PH(?>EgMc4>qF;yo`yzz;jB4H%Nz^)A3VI#;j9`_7Z2=BkFs}34HwE@BONeU2E7U zZfO5G^5$|gFve+{hR~b_TZ^_H4}7;@Hh2=JUj2KMn>)XTdA7MSlPQV`YCJB0HA=P; zQ2&$5^Var;>eUBacIn6a@>u1wCflWI`@v)J@SEjlq2S2(77`^#pDZJLiyhVa*elk4 zz8xwpmCbm~{;0%I`?512Vf4mn?k?zM>j*XzP=c@rL=kIbJw$&TZOpKL)fYmUC@L0>q_ zn6Sd~-mln2XZ}4-6Y37SJcCWP-`}#CEQlL@nzlyjrbgMUyBz90={Dff0fU@t&Vc6RZIUI%RHr!TN{)12)*6ZaA;5?d`)07^DKx}wAptBYzg;?hMQJooC`4*$GOfCaYd@Zd(Y6* z+o;5LY5en#;@2FCqxXfu7^>yq)U6_?Y!PGI9Pyst4Ze?^1oNZdWF(xBW*}xT>O`;6 z$gJxZb;fj_&V@#w+k*cPm_wSA{c-AKD=tR0t#$mE-2&iitBfRQE9^&uXTqzR?Hws3 zZ}xhy;4i(CQ8CFd+-Iy`4CZSS)BSu2!ULbP+7*|INJ9(wLzqicIQhe|J|>CJjD$28 zGzA0&6y@4*zKvs6J!=Vc+58iI=k+p~+5W65dT%F8LeOuAbZg2&gFZ6YSocLbj%xYV zZ={mrTTFPngZSyGtkA)2oIlIm?-=N#*$-YXv5TBlVwJ;-AFEN)X7P(8vw!2+Oe)i0 znXu#5pmR5^BE`?NV5A|{5yvDONw+&^+q5EJ2 z%9MTF$bZ-NxBNVe)ebim+)Q(jxVbU59JXn6bH=M&@dR8d^~2ZQuE6(kC%K`UGz!_B#BKtCy~Ocq=J6aa=N20 z{9!P;h_2^^2-dge0~5PX9>(1EW=e=N{7ppE^Y*(Pv=6$171TBwK*`Jx0+Qpr6_YbM@rqox%!VPSO-KjE?ITU)=2ZdwKo2;3_*ijxPBT$kF(P)2-+O6l=0 zfrz&}_6=$dBNX-($7zw9GzR$L(oHlx;;_`@ck>f7d>vOUi5AXke|c(e%|;UOn$N-AA&<|QE>N%+ z79fnhY4WEcKuVZ~KW}$DWGxvZy-6Y(yq*N6`;uy;MP*d(XpSCliBo6yygpr7m(;US zon|8H)!x^Ban=sI$h?S0w_~L!Kh()pV{ z3K_AdOi5BDozegXrC%qPt6L?=BsRwvZ~tuBKL06_dQB?mPmX9toQ=i$9(LHH$1*tE ze7AkLXr+N$Fw2Y>_|#W2ji7}=Yq-KQ92BFGGFAGn*l+2U{QbvJosyRS^swk4$h^xj zJb^D?Ib9?E`o|ZAPKtOMJ-4U7$;kH9a>XO*1vXB`!Z(ZeghWyR)G5YT@ju+~*G8$W zq7Qe1ppG`{p(_(K(q;@q{7g0u54dO<;1mFC^-jnQHAgL(gla zvuw7Lj!;t)cftZzo(ikP4vz&oF0nmS0yAmZM?vIbZTB}(c1URlwQ#PqW^(DTs%<75 za}u6>EHxw*ndBVp-irm-%hwt5IXv62%QabtlWi1%883K-?ergQ5f1z+A&d)fcNLF` z>wZlSa3+N3xK$)ORoZ7C4iG*tM@98&in4=ttw_&8friZqm=()QE^*oi*ZW!p{{&%C z@YwHAYL|mqAbWUrSc!0v`r$w50ssDo3oEKivuT$a3r(NYqG_DCizm%llH?0fGk9Lk zyA2pw;&9hVdakCvrPdp>AWLz8Y)&A-Xu=bS&S9@(r;An&%z2rP>a@*-MC6w5Yz+f* z;(K?#78IB>J`RY)#zG=GSTJHvz$4ZKbrKbQ`fQ;6rs18uU_<4_5FsqB{rQr8{`Z$$ zt#0{rIY4i?cquJ-+|-SL!#rrI3SiUpylPuO$z^&%Nd3@8J<@( z4GMsobwX1!O`E4QV@G_}VJ&FS{JQ<+=&a2Rf9Ga5+82T-$Tw*2;|pe|{aX;hAoMO>(p(bY5A8e7|^<%a|oz4^u<+(>CS@fjN# zlysoMo7HxIu>(^JZj@;8--_0{YrX|6pdU2)n|$_>5<=7KZSQImiU3kKUVG#8QUrIy zV;}G2_FdT7mbciX8MGOYhPUj`9YoP`^(>^-0pL_Y{UoYhZ+qmROV~@Z?wmi4j_qE2Ra&*CVMj>W*qT6U-@)N(+x1$@)~hOL2{`}s3UD;ig5oqRFEm3 zba>Z4&-*e5+q)HOe4}rinUnsNvLh7-oG2klwy@ts`1i_t^{epJ@ulnof^c5Qq%66K z80J8r@jGPPO4OO9n?BlrgX8Mp_t>?ctG;dLSDre}nL=?XrLZR{CdQ&L(^*w_rJ%l` z|AGtfUYv9*a+IH%ZC>h|nR|!`r0A2@|Bhw~8EmO{{r#(OJ{e<;c)StX+l+{J@gT?q&K)#7*j zvgW1hJw8u5ARY$cim8e&yF}S%`!!`?(>gCA2e8JV zvGO3y#!;j8TZBe9@hIRJguw0|Qc zhb(sr$g$06LDZ$9YY^n)tqWTa8}d%3G?TH3$q`9 z-qjNr8L5+@fETK_NJkWxt6(q2pZZb{OJ4K&fGEjZ#kmsFgO$f`phH!`jZF(rQ&r>p zM|P@e0Nz{|ZGy~W9sy-sy{YQ~KSwkx5pMgXw|q0%FPt_bzU(Wtd@*ACll#_#)ud%(v!z5k?gaL3!li4CUy*`UQZ_uCYytVXK-`!dr;>ZGnimu041FHUyddiCB zYIdiUdcC($-^VL8;~+DS0-(mbaw<4E(KR_@;pR&xA*S`$~hz{x+pnvw#Mer<;lp+oH#VgkU!;hx*3G(1bMvB_XuqcpL z#ExiGUkwI48o)N#PlLkL#|aajAke9F(a)~xuv5A5a+nh7DAO$7p~{s^D_FML3zvB z`#{I_(Fw5wB95?Z+)Xfl=0g&%ynHgF@w9PN6pz`lh%C+hZWwjnrvE;5p+CdYfc)6Y zg?yao=uE7Dz&B9j6WY|1w@W<=^bkzY^jk{5gHR%q->OmODFXHsqk39+;#`jM0p9a) zanXkt14$COBrLt7DU0f^?MtH%$PY3cO@b6DrfK$4c|djD@CiXS5ak1tGQ)`y2VyKI zyxbgEo7>b{qd(8wFdbYJ3(Q z>^pwxr&}qSb?HGUVL4pkIZ;5}lpg+5xPZx2U~@$`A={{Az1%2S$7H#|&;CuJb4O;n zP{gh-<-^OyKW6m!t+3Elwvab`Nqi|Jvr3@PTKANff#?(6{YB~ydArZ9o|K%L0+&Wg z7agsw)AvTKedusG;lyib6)rqkIuZ%~!~Zxs3%0hpB?<=!S{#bIJG4M?cc;bOo#NU8 z!QI{6ofe7}cQ5V^!QC}C-~9o3^5mS%p4n?=y>s!5!*>Q*=D}eRFR6m5<&wkwkbH=J zm~@3syFm2*ezEz82)bQv!^l)!I48pTz)nruAlkr5RDjBuUV)tHFKs-|mQksae((2q z{^R`c)$WBO?(K=UIJkr=jDCmZ;$boi$XF?(Kyfu;)gq0l0)XY#j^{Vqs*vs(Nw zA})bdtk|__TBkr<&w_vLI42EXU#KH`3gld%L_@yksYRWymK{|dDDgGard)86Nez*_ zWS92}^qOg*BNjWEZkN*si_NxkXq8mvr1`b}|M+1Zko*5j-u>K+>z{wj88}|e6k;A1 zuA+IMLLoApDg6>Qj5!4TJVx5OHLCyMury>_)FfSgpmN@!Oj2lrFphT{RKQ{A05?#I zF9yl=A2H)&k452?`&pqH$={xG!&4VDN655WToeN(KRCP~2=7Ikz98o8u_o6 z7`G54RgDxKQ)aYXR@Ll3U8c^X5Q=AE-)j?g3`9Y7r{ba45Bpma!q+jex4L}V#8wc( z&mAP^%_}oSyG?}gENw{zwnG1OPR-A@^*NXC2X@WPf|^ykSNGoN9v(YG^hq~XsBxj^OiEP$96}5qMyTef<#*bC)k9v@4C?RJvy1r5yn>Df6!L>$4n#WOP{ONLHbJbiP z@MssIQ{y-7znQhqIRz)b9*O|&`KmCRG8-u;- z5T^XB$%@z6(j){7dKI|H?xv^-(!_%&M(_3K#wv~-3HtC))7vs_=t~TfYo3zjteWtU z6`2qz8zPMXx@+Ps98`!xc)d`bs35yGe2B5hrHhCL@{nByjd`-Nv?9$Mo?`pGf{#9m zl{iT-#4i!DB>n>RC=a1qx)q(6q{h}gTxAzRH5<-_{Z2)zvVWU$?j9mlp`|wJQt;)B+{4FJ$x> zXEGca1=ynvD46orXb!)3b!Kr>0v%aGZGW!KnK;!kinK+6E)f^mH&vQy&OM<2R1y zd9h=;9hU@66(@z^T#f{P9X_~{Php&2c(1TE za!mk5T#A4BHoR1GfLRyvHjEk0mcZlMc<59a_zjnmWtn*7o7#}eTBy~>)6d!6j1`T@ z;EVJ}G)i5~mUJuJU)m)N++V;Onvq?JE&&g?n$n*O;HU?j(-l%$uX`aGm=x&2&eU|bDrB=T@!ehtqC0hc$mN79`s3S5>WJ`5aEcAS z#{uoD#sq;LV&nqf*bQ2oFoo6KrvUHR*dJ{>+R&@iuGd@JI_KEm0U#uO2I!W z0@TmU^3BNmaHZ}T0q+lu^%oWOXWyHq^wyI|H@k@Ah~nOQ%RbZot&@fcVacSmo;~(X zyAXqPuO%$G@_L2O+OMREGWON~8=bKIEnS&F_A>Q;I2-2>xXKf#VYec6KMHX;wiy}w`pj1Jn(Se@a`OGA5ILk`+wrdE5irAq#R}t1 z#w_FIbO`DWiOCAPp3NdY5q!^s9PK0iu^n*6kf8c9f=p0z#&D4-3ZBR%Ll+{y?rFD> zJ+-CEE0E4Wb`gYyQe+u>rr8x$@^r^N^qa$^@L}D{1x>kpFwm01wBZ58Dv+%hot(%* zqy|wEuB-mL>0_vtLoUp5>Q#&wvS1j-)RGnHVUWldRH4J%iX%8}LwxtQV3cwSvO(Mu z=jh{sE!G`61|Jzr-sx;BmxQ9!%d4KZ?&EaU`BPn1wy6iJIOoHpkoV0vfx(UW2?@uU z%4@Dq*SWm2Spl~47_Em0 z*;BC9)e^)I(RXV-@B3F2qvz27D?m*=u`psD15)Bqt zdPUZcMDycXhZpPxxGS_$j8DR)DHh?!rK+O zILTUv8*$kXM#|Cw8CVIzB1k~WL*w`+D#e`pSC7_G6|kNu|lK361OYd7T|TN`x#beN9&W^gA2iXrgw!{Jb{y}5$dw`zHO{;-zh;Zk5@Xd?82ZHp5lh^0vjTjHGHk&_V&42kDOLT z5Z6gdQeOjAaNmp@(1Qt}NotZsHhw*O&(I8`W%;VF<^q&Cu z8GFLLj|oys4DHXv7AtgfMG$DUdk6}BFQffTSz|Mb)YA7?^&=u0)u*onS5J4~m5v%| z6j=gbr<=#!-G_ZuQP=r+l7&&nJ5~>0ABky5_459fUxbZI<6FRZ&fAT_yAyp(E&v}s z1wny>iMTi-CQ593a%BgqsyNsW#nsl$n}p|6IoK5L?BE4gey5(|vJ#vizvy6{EP$+c z@cdHku+oBiRRn)-ca)D`fAZ@QL+=R-KK~%#nrjG|!U~J?)KJC~YLl*b1vDJo9`f$KoFn(@|sL>tSP z*(EfXc(<8`s>r+eLe2M%b~7zYbv)rSinb6L&?b~cM&-044pa)Zrl~ML^19jC8ZZl@ zb>>y9s>1jq+?6B^ETs7sl*lIDX7gTm+=%|KweqwQ?mrsk1&3lUOAoIUfd(P{Ez&y>Ri z6>Kp@dn#GRzp1Gp;fKsd;{~#@qIq~oH|V!{Sh>z>f}WPwBUrLD*e|&F)lUBie9RGhJs0#uoG4q>=d$w;v)XxheFxmKPyKo^BAbLkhZuk>reA>r zoo}H>QSFEa?!jOt4%kz+`tgpjQ)}>_;sv>0sc%q2l&KAC2;??Sc!`B81RGPf{6rm( zcD=^InoKen9ZbH$k0Y>OAy{_T|MU_v2n!`S`B157H$C|v1qW1bsDEP+ zZuK}hr=vsH`aWJ@3zovlDn(~Q*l79WsG+S;J& z{M+=!#aV1`Z|Cazg`Gq|NRomgQBsW#Ftf1mVz4&!yZcEK}!vtA6UZJ2~o{{RCchKG2x>Cf8mpZqTm zL5}NHVVsCp7Ak-Az*#RAd7b}m2coin*URv8LR=Gi@W>pt+-dY0eB;8fq9x`C(Rbi} z<5!+$cxa3A-5(-Nd1_!#b(S8ARGBxC zbhCsIjOS1x%>d}MS9@fP1eY@Z6^IG0+&>rzJ3GJ=NGyXtcDN3n{_T7IDM3C3^Cp5I zryXu~k5sl74dMx9+QUVw6kx?trHYrAlwbCWx4j#EyXugGHrZduv1CexS89cF+ zUKH>53Z~uf$*YxrbIf*W(Yj()XtR`7{N~xG3h(mAK7H58C57S5e*&8rNZ%OJ-Kdhq zCGzLkFgp)o;%Ok4Du17qi#GT*+TID}D(>XiNh&ADi_ch>d+c06r+mn32><*gDj;Z; zC85J`$CfS7ZRsP;tiW7>F$5@2`sULc>A1`d%zMJzT`B$pRec*~3C<#iRqwX#kJ}LZ zjZ5S;OF)>m0XcntMk<&I&9~m2!xX5JITtc{Ir{H%|EamOl=j@mQ@!jUSR2l(J9c}t zrUp>}{EbPw-tT6BlOBNqsbu0Ls+rpM?bVTdDu_(bMD1E)Pc7UY7J$fD&+;h8Yl1Et zoI02;NQ4+#2{!IOzK8lL@`O7Ze9t!i*y$|F2@+q1;Mv$jX}}l$24kI%Je!rOh)9*E z3%f?DYIy9IJ_NnLg@c6KF;3w}KV-n&BX0@%csS)lK|QO#bB;fWN>D7+f(`v64ChWG#foxA4rmiaeL}qOb-wW2+Qo`>0u)++;65&$s+#meW|IwT`=>eR$mw^pY&mR|pdpH1B% z@dBv!=Ks0-|G=cIXjk!u|UXa!W;}Uj>38amVQTp38s(-3 zFDDFi63H1G$7;S&hpq}+zVxqgNA@8r&ux9k`vpPGAZ2*AAN$Zen-WK23Q)pbUW>|1 zv{Of8EN$Y^d^38>xnSq$k`9)-fQ^bw4F8-eqFZ3g$?t8Gh|8R!`m-i60y< z33+qW@{NMaS`}9PrspPd@s9(0jFA3)9L*ycy2&tVz$0xBp(gRUCH(bp@)$rbK~K<> z#j1oX`eLq3%Z;CB5R6jJQO1+m-ifPT01W>}MgOVhtr;@VY(!R_$1)g+8^YYz12rwF zkm?cQ>6YV*U*WE_De2Yc(7EyVsI5x?@W?s``nKA6yG>#Ji`qXxG4csF2*BbF3Xh0^ zQ)!x-cE|1&Byxl0)<1nKJ`qWYyX1e}kLEthQ+V7c^J&cXCe=0}0hV|Qpr>Pd`^(K` zy1%pMOIZT?e6T}jhM>2tf1vT_n4WdX^6$Fpzj#L*I~Nw0 zpC4C{{QC|Z$bO1a9w2o${v4Fc3%ZTkVB7R!h*!SI1I(4jZsDfY8?3(F)x6kcWfhGu zP>Lbf&?@g-hq6QZHs9_#60}(uLUfRH^K)=YKL}yQZ;2rVvmkN>fnNd^sge-@kprrZ z%EWGl7%!qNe=rqAu18#dJ}$F*>4dN3UG6PQ5VRn@c{UaK#IjN$a013J(jZcz-0flMhDUwRF=~JgY;7(~$A}MFh~`J?RPc843;w)@?j_iE(E$GN2dWyc zYyW}U$YDZZ@FZ^&D#HNaQ#GeL6F0*#+g4H) zg=J|iuZZO1>R(Z1e!mP_JyA*zroC&l#rO|n9*34M31BJt6>ffyJeh9f;ra2_gV@(c z=`c@xYOsAcSiRlhJIX&4I`F#{tZF2Ev;?N8&{s(*xQI3zNgBNA32V)AreNt_oTUDL z=`@UX{S79rRjtksJvlL?@|f|3O~_KgBt`ld^up~;Z}eS{G)IYcI`k3y|43=vD-|i@ zUjqWxs&f)L&a({00Cp(1Qo*EKeQst{Hw4}RYZKHi4!k`0qk$k% zC!RHt^O3PbRtQ%-U0rR(n9Wq$zobi?*fmyiMI)5kR7?KrWj{{VvLOVDf5?F?mq^5k zFDy_DXLl@{a#*Wtx^-bJJ|oYLan#q=fQcw~GE=p2$FSJ0Y5s5G(HH37_(gAS)cB8s zTk(VzK=6YhG8T&tTDUx5OIg%3+H%sT$Vsa^u_C-*yPXpk2ZNZp-5K<&f+fcc70Gx6I+X4868 zTfHZ2%GtO-OXwZv;!@bu%6aF7@cEs=-c{_8gy2f7Q}5Pv9X-BUl+gVYt5EzpsO0qc zKA}T`x_uLtEdyYEDQ=KLk!WXjj364wQSXo%B(o~qQ3;8HykqnYt~Yw~a0h9#Bsp*~ zjf$JZw4p^Ek4KmtsIZX|%QKScXo;;6g@cdSrZLsmg@D|g07?b`Ct|)BE3>d#a?O?g zK?=}A-}M-AbH4XK56WVYilr9$^4Mv~*%7{KexzIsGlqwsyDOKeP8+HTdyb*snYcb% z09T|KaGJI7WG-nq`Iw^N|1ad6jRV@>Dv$4}V5;Rpq^XAvqn_SmVbIBmvz%BS%tz68 zfeQ3l>j)MX<5#&b*jj;wWbKB&p4>t0 zq7n&2()p5!jX1t9pv%q2E29^ikDh;ch&NhZjD787cDlLg9stOc=}7B^!$u?p|3o&=7=0w{P$hgccS9KW`5&vY@jD8(TlZ3ytLDq6fF@3k4?4UmSZ(u_Q+rLA^ z12#xJ9IkQ)2!pot=`YCrU@++GcWjE3%b#h=9X@#QLh%JTZYW^b0BJ5I9Io3(=&;A; zGJGmNh6G^Em68_*l@j?p?&`P7`FEag!Qbp%d=5o?ZceXIj%&RA_p;zCn4TK$_L^=H|=PzRyuAP zb#;AOw&`#DOo1e2U4dR74qp1!^tpO6m%l+B59WMiq49O|twy9}LM=wlB}J9CD43!3 zg{a0?jsCo%`)}tS>{Y76lAj;^*z3(I8fz}WpikP12?F2}$VR3@3NLKP?H{%({!q3Y z-Sh5zDTM?3(>=INI={nlu>ug_q?#vQ?7-s^=oeT?LKxagJ}?pjgkz8x?@EY;9^}JVzN&tXs2p zO1P!ztic3RJ^uV%MshJj73JdkT975&O1i+qKG1PvK)WS>6+&T+2 zmDSe7X*7y*8pa&)Z1Vp!MdIIzrd)OLa*)x?Sl_;fvL~R*cGFf@tK|vbMfC#fh^u8z z4UD2y;eZbYWi}HPFoUp$rd+PxzXsW1jd)#Wb)%x@i+CSR#-JEbVkPzqVewzYcUAc7e?QS{eZc_%C zcm8S(?yot!#8T5l2+!XjG2$+Fii>0%~_|Lt#g_{4u8qs3!D2uh`Z!D#x#2;bD#3=9A)2 zK1Bcj!C?FAkO#Qg$#YSt>_x>piNhwERrQcVp26W7MV}Z_2OuFA6&lpB8NRxS$#1?Y$(NpAYs1t=j$W8sl52ldC#8)ICbG9n#^akzr zEO@m`n~Jd_X%nSM0VOj>T2mgcpOS`BE0I1}v&<{~Dr8yD{I2=XdkJ|3y;$WrkZh*n zP>D%=<eNCf&m3h}(KVMHIoVooGV!Eh^Zc z%qFjIN$l}uPkSqcaiQqU^H3XML#{9o5?Q)S{Nt4Q5&0L}P7ASs22h`@2{W6-j2ju6k>-2$r_ zC#4A*+T$bubSjknYXr8Euz&3Aqt8aqep2sx!=CVRz96DKCPbCToF)Mcs!;{1ka_iV67_9Xn%>~) z>&-W%!oIG_i3R{{?;pNr@(&&=D%*yCb0ixAL+@gXkYg2OXzTeBf7$j(WE01;$WHMbYQFK1{W~9h#F-2U)!UHQ^yFc_d0w01wBKDV|h78kVR`hW_0oj&`H&LG7lfc4gOKiLq;5R|oO zt{UTgRv{}dr%~1%@Lv@EMfUepRsNMI-0_h&?aLLPfCRELT1*mE?NaX6!rNKa0}qch zTI6RwR3s*OPrFD4XrR|+3;5bI1YlZf%$@6U$x~>0g zgE=-cZW^77N^vMg*$R(ABdJaTOL2PsFJu3OGjn}0Uxep$%zHck$?BX8*{c!wueR&i zgf=KQ((|H-T}#HNE(B;y)=%zMdiE7Qhny(4Gy9BeMdZ4DjK>&U0>ENAVjD3TNA|?X zZ=()fDwfm1ODaWgu+A=_n$u&)C5D7So*X+Gfmv$?gh)wZb7n9I+#2QmTSU^aInq#i za#wQ$r!wB?sAPr;nH@?g&e;4@60=ntJF6B_@Qj9jg8u?pd(MSLX?dbS)M`h$IA-RQ z)&&&vGL;4ZaQrT0kS*0b{PR763sJ)}T;$#QW`lqP^Gx#Gjvzd?ae<*!Fd z0BC3!Y`nQap@Lpcy};GjP3R8y)FYY@F&0glx4j9RgER^>Nt^+goZsXr@XUYyt8Qa} z#wwxQCAenePX%~&EzO=$+JU!wRH_<@2sxs5J%dQiWcF(tOB*)U4B=ar7D&fvnbQqo zyddyWMiR4vMf_e5X`{UlOk20y!bp{EJRJ^(f@jt>`P=dY2!c`f9j}ZSC|<@}K0iv; zt}*BF00%oE{UE$~C1M9m>c!KQDo0{)Ed=AFvAe=`gYfGu?X6c&Vn(HqZsj!7+x71kn2>)UwKYka-=w0+fe zpJu2J28#}g71GMHMC7Y}lvN<3#iZf)-LeLD}jlQV;s{%kP+DB`&o2Mh&WPiI=q zsw5J>#7dU`q$#u%UFU zj1&W%bu>)lpeO{SUp)v!TlL0p>i{wTD7qf_pR)jbeOCpC7K(1}C^YpTV|UL99SuT4 z3F%;!Z3i&e;pUS5rKoba{lVo*Qc}w8F$gUo*W@~%!)Lb6sLOAjp6X!j=Q-awDz;^J z(+L$fJ$E4v>LQN6Uk4j3$DL@Mc0fpc2A|81zd{ zYJdDB-OU%@$Epz;K4B7So=|HGj#bP(eJqN}xjV~g=#!|Wv6MXTqc9{f)Sle*J((HM z@KQfyzz@~PFttfvB6Wfn?ce=MiS6NbWSH=_3EAF!^=B`OY7@T+;GAotP<&*5eoFnmTCrp%i8`6 zYD%vD6_cX7m?#IMG4X|z{5@!U0oh4hNVs3I0AG*-g3MIyJKO)hfL>J~J$Lqkb7x}1 zBZO=eFq}&P!@*myn88DpTlzX*9-_jC1+sqb!s=|pTGAmYRujY<=;}f9Mk}+`$OlxH z_`bpjOyg(Lo-$lg1x%Hq&$z6dSIRGE^)Dd*RLEUzg_)7h~YQHSnUf(D|_7G|bVhgeb#^48?FaWEC>3BG%)v<;rgUQt-4c{3LtT~+M2c>>Te}d_0bTo4Cx80z zyWEx~Qqh_(ZOo1tN{h)h3ShvDil*2*Co)ir*vP3=r{VEv*2ae4@4;h#+kC%T2fZ)P zici`SFf|cbra-K*wbVzmM{OGjdy4nOxvVJCb+xH|SMWg%@W~n}N99(3%pk*F{@RU#mV0zZG=hPZD8B-wZiD)W7 z@5EhVSW#Hj2G>vz$Pi?50_sl!oe6pvjBO>i`nRCsF83(Mj>{q05?$-_MolZw2G?`; z?oM>n1YH>t%1q0C#`?tRGPXPgc6+;is=^ls{9;<`AV8HM{2(vUJO6=786`^10{}(g z)TPnCx}6ps%Ww>5N6Vs78W*>`Ir$un+&F6o$}*sLf^KFI(>|G7yOr8fbb<1q!i*)E z0V8n)h4$tUyQ3qCmlMawFvpru=;(Hcegbkbz-zL&g!>+|rpl)4`OZKTQts4Lh754k zssoOhlAyrvGoWJRevHelA;+~ivj4kh{Fypt=Z6Plm&^8PNmI`;X0fr>XWHN9c>Urf zF*(@R)K!A|s1B!^KbD3@Yt~P@o$V!t})9N{YLrM@m$8~8Shwn#tjRfltLMK3R35W4mx1C zXx|$m;p)qt^uBrCp(u0yOY4-T@FoXs3nIqno4;7PH^ZN3BUO{Woi;=<% zcb5Pb#x_^iQnDWvkB(D-73Ppnw9Ak)(th=nNLKy;Ghb>Cb1-z%ufrFlrGY?5IUCgV z*puQa0hCX=fJO~+H*r)$_`FFV+`xr{5aAX35Qn8e&_uNAe zCVx3m5Bl_1kVR+q(g`^u!n35f!<+_p!?9Z+=01>-A23W}B|2XSblq47;r>+FSvlwn zw*MK2nIuzEz@n?q5XjD0Ut`5KMNxC1x&xlht&dl4&F9o#LmnMFAFY~qh4ZFJ98gU1 zL?`xIkP3^-vW&gw5K3qM1tPm-Rv!NJ?0#S%nVR+YX)6Q){reJf3xv~TS&Z>PvgjOT zeqERCt~AQ7(g8>1h)Y}{>49ByOb`Ll)ZEzd^~zye`nqT_Zuq`=GELa{cD}hrUKIgI zQl9=}90c(qFC{483}cNz)g+$gf&t+Z7Gs3D?hSI?4~21D5`Bg*9z$_o?!Vj*g&>+g zF~o)iMRQw{O`-P2jN#WBpb%03wK!Ul651HYW*eG2rY zGYx7x2VF+wCcLrEv4S{p*o_ylt>QEXwDWcK&h>lHi-X z?=z4)$la6&0*~k5^09HbRF9%^#p%WO)7-`~^>!UCJeG>^)c~apgty=BzL`8L0x1-s zljHtoCJx?n_d_?j7#{29#&hibq|>NE2D~8 zwH#(NO|+DjKE@|_81q^%-Y-GsTq73pw=~Ey=yIAU)S0@B!5<4JI3i++5S7jhR)&W| zoNR4^6#XEnb=`wsh!QIDHl(1~ijsWdHi54)D$$a3KLMPUd+(^j_P>GNpeYO5dt% zK%#=;6x*wGGO0_G{kJJv_~gT3oMN^PsN0+NA$N6oug~WjNX+sI{v5nb=~YM!4h61t zRE<@OIfGX)0jfMF%`Z}jnP!%ap5mzBp(cJTFm`Bb(0;CH~$^N z&AZUXiFiAnjp~d-u|!be*G$;quif(U-fnyll?gpGaSN{#MyVl0S$&4wkn8JDz_fI$ zE`7_jLFS;!NLWl6{qHM6REd=G=Hn1tqsa1R%E}tZhQ+2w;9qFTYRQH5H#eA36Nw2Z z0wl(=j|Q8@91Xy04Y2j8=< z^aABsBomJ0i8`li20VWq;4ycRY#WX@0mm{7te3ygXqTl$`_)5I-&mKV$fA=KKKKoB z+4d7tYS^zv&;{hW>pco%imE6_G(kx9`mk;X$PlcWS^@|Nnb|^#;>%tZqY4OLOJ2{w zWE8+%VRX8f-gv&r`RXPc&$37Wr_YjWM7GxQ*JD2$l{RLvTL^nf3>e6T}}t{uLZeD z2|a657X5Y>_CIuRR{;m2_Y8Jf8+Ej3DJB*VEgjt4a73hk*ZZ@vtH_`;$!FGr*QB^w zef<#LaQW_S#mQirx2wTnr|FU=5#NUs-rG(0_!^nf^|If=iH3#~l0XL_QbI-sbaU~d zc@nP)izjEQFU98tp10|wgDKA1w87&@^$APL6dvd0tKVLMG6RI1X*>o6OdDyhId|sf07N~yz zlvlfAJ@ODrLZDwBB4&8Z0HjO=4(a87jh463{LWTtn?*1^%!L}J?9~|;rsA3Vot#8c z^w*3ajtPUFzTRY=QK!=piA!iY*koo_cE|wpQ%nZXvn5EIq!_^zvr$@0?WIg5_G0ma zfn+R`ImNJPd70T=y z5t^*}#)yRZP^6gfG7lXDLV^JdQ)nR2L|3AeMh^|laPY`raTAXk2DE4056pHXTz@X| z>Ad4MeeQtt53Z}Mrh#5%> z{vGCm8+|!pQ@JAKI0)kkd&Lcyu~u69*DEsvu1^{IF0d&Hg$Fu#HJ3y?o>)uKF-7eO zGT);9j4KR?ZA%jUI@mH=TYmKU`4|Us_WZ4n*2m2*BQ`u6&Y?8+;Qeh25ocoQ@iBQP zuPx=B(O+1Aqh7Xfy+3%O&5$JP`se6}TRU2S41Cx`3|)5wvS>|@(c^H%^u}_R$0*0# z0Zr7`n0L~eY>S5x$3G*XT%)QacnY24*)hw3=YMHeAxEG`E6B#nvd-pg(7ITzT58%? zT7}lqaYA%rr8CQ% z&pWH@h*^k;sYCV21+UY0^PX%om=sEtNc3O=jhVk@ZB=xDU_;h9=&R#;uA>`E9;oW+ zeMTABb4Wzt>@^$m2`ck5- z*o+9+_J@ZDG)Pp#D8nUVtg-x&kvJu^Nb<;3+dh99lvh?3Ox->^n`ZCweRp)Y@V#;p zEagN}*kkK0NgbbyIr`2_%S23(J7_B$a@RVKawys+nPBMz!9_a94n>CHC0g#P9}YvV zO93n?2tFhP(N5e8^m1D(|8nGX6MoPW4&!U|`X(fOYOs=^Xf}}~KRm9_;A*BtE=#$e zBm%N}0zsgr8*kDG((vNYbi|Q~?2L3LE*NXD1QOexKl3MEf-r0Xsc2kJ^4bd$=M_?W{#S@PXjaWve-L}MDh5`FJ z{bv=t0s1E=^pB2MO>QH6ptL3=6+<@LN;7h>k5gx)e#9Qid)pdaMwNiI6F3?pURubY zJk;tk{41-LVe%skpdQk#T#XMz+8Xhm8E|ifIL=YgqwTyl)w7jxLDg`VmAD7a#a_OO4Pi7!9nf85PBp*g9CCXCl(i{@TXp_bC!HoU#RGVp83=85=2pe?tJm($Y|wk_0lE*Ibv#s{b*{LN)8tHJm&AsvP-hGlCZ=z1*dWH|KHm=v-VWVgsJ zMitoFqJRxh!p!2~pX`)atwE z``F#E>CQ8rMDSE~M2d}-hkf;eI+7jsA`lL7BQYLTaC6}4wiE!c!ur?Zl}m_`ViL87 z#!oMe#E6sNoA8wvS>RBy@ax>tMe7?q+n1;hxsPX#c?1}^l7@dlZ)-9<2nC|(NIh#@ zSDN&&&h8X+rK`Jn(D(CjC1USF3x~BuCMV7%9&7dUao;M=zFrs4qI3X?Z58(MltYDc z`SLMwv^em;GF^lL<}!6Kk->tdXFQnX-02{maa;8(03&w*aq15SiYuPG%R_gk|MtW(7IE zq2G0K&^IOM7sJ{a2b+P_AvDTq=uoB+O04^Dzm5qQu;v4CyZmuvpl$|WcBIF^clyfu z9qDZ{LQ?D&kq}n+iMxfhui~{BjQBRm5g?bdQT8aI_a@>UdQ{=B6S{??@Q+W$!g7NO zdtw78)tN=ej7l6CfzT~P`e5(`k_9>3d_&~%P5F`|Zz+Z)KAgh>Exma~t8k?Dj+|t# zVhu0kLOJ0HWh6y811^Uf_X3?nfEpHR=9rUXNxe=v&(xB^UJuS`p{`^Bp zhr3vF|EgG$Ce*;^|7r`Ga`~U?`p6Fbno+`p4)GFO@s}s;c^5K7F}teusmm&zo;Hl4 z{-V&WQa$5#8+vybNE-_N(5fQtjj`b_Sw^W>biB~ES5opgyxTBf0&dN(zLosb7X)Yj zPi_?2Bd>3E2aB5Kypo^Tww%)~$TS$Nkqf#}Jteur_-*uDHt7IrT=_}>0ztAkOpd~y znz8|_sY@fsd=RVAYTP*Gp7|$fDFl-yXFP%hglC*vqg{5lh8OX?cS*{XYGeLePs`MN zy~&GU3uOaV74%yb=ziuEWoN(Vq#gY^J{-Vl6#14x_~v^;YXcyq^?)VAUMJ9lON0}{ zI^v(~1mo^!X@Jf!i|x5H<^$w4XB+e`@&htB+BvjtlIjgpD%z_&S<_Oxyxz-dk-TaMeeQ&t7B79mX5HrdU*( zvE`u>ci@0^%+B)mLuwJ%me=BB90lOOVjnz1A|6tx>f>VP>pD&gn^kN67)72(PLN7) znz=^&jWxvp<}(oSVZHLda}F7h5I{gSj#R52(@=KgK}&S-c>_{-AVm$c=_QU$J*fRD0$i)p(k;m7+@pUq_+YGygbXz0X23+&duf5#9~|9$4Nzp{ z4KK*Rw?eqSPq}e4DrFHTu{FbjRpkDR7)54&h`>{M4L2-$?2rU&kp>ud@kd#ba^Gn< zVM~2KOVjK6EAW2e7+K>I9ordE#35XFyK0<0^Az>O;k@1B!%Ji7J(J7Npeu67t;$9r=U;Z` zWCaHV?Ap33P*v68lQ{YEaRRL^oUiUhh7@BNB{C;>mMRxyMs_(jWha!S5UcQV<0*y3%WNC9yD%ii?ve4Edj* zZ8bOZ+$#kRcMo0|@V&eddt1)ilL}Z0dNy3FRi5OaAP;L;xvRO zTX2ObfMEp8)_gVBj6i+_8NW+Dr}hc{zUoO_LgcB{Z}&$XhGFdS_XbuZ@o{6Ldr-rg z{c2Bog8=g;N<02M`De5W%whe?ndw}=GFpp*oYj#D6V{~u-AR7_F85;ySjb;djVG)) z=v@InRyij3*|Ng5r_|RkQME{lELIevc4VBMiogd}f_3``L3Vk?Lx*`e5gyp40d6gI zS^R#?t{}E43niR4CW-J$mX+m(VP`uO zDiSP{>P2kz6S;d+K-tsISEn*OnyK&^)Mn{}dnkM7(H@nXdueySX8bzZn4^1;84)XV z7noL)f|68w0|Kv>*MnrHqB;U^SY#S*tTww`-cSPrCtz`~3h}VFXo`A&vjp7%w=`<~ zil0B$VGfg)NMmyTu0TQLrYOq!|zc!dy`SR9% z*ZWhjhrVlaPa)0Ji6h&eOeraa*{wYZCo`mJ{@mp+Bp;kl{ny^d>eO;t;h zmXAHZRKXqf(FvG3Us`B$WByJbabjP=rqtrv+xzBzrr)RdhYl(>rWP3eeD7&y#&EAL z7m8o2Azi^V(a!uG-1^sgJJ{`RHOBaK^86H``FJ3KSSgWwS#Del@pSjI8VC~kdRlaI zVW4AxhUJ{RzwBp{n&W-z^I8R+LRs^ez$A>{qEQau^%6knt|F6*s^I=v1MTTZX_U$l z<_iaCLBs#2(_c?tZ#hAn*+!emKel9!zuJ^oR7A98B*b;(;tm5JHFfuuK9-u&GFfLdR&(21F*TWnc?$Z&jS9*dz{~s z7jv$L?$;nyw=WjgxP-g$$u07%kDE$&wo?ekgWF*Q)*80NTr2K~ne!i}QQI?rblam@ z#!7}&o@%$OR?HFI@;8zC5rL+_uJ&)NoUx)e#!t8y_97eLiSXvPRQpN{j<2sO_u9Xa zJ0^8(LWmXl0=@9QBnR3=B0Wx>`NV_=~M)ixB`erF@I(d_f>2dt0wM z1I{%iut=f-_c!qA-Sq;QIkS#GxO(=7@8(iqz<{fnf!I*Txw}&@gLrkT?*P2&Wgxg@ zq;4q|PXQA=-NF6!?b5I`98ht1^U}FXtB@+*V(QA@!T{~7AED>J{dxuE8Jb3@<{k|s zA%aUFGBm?(i7&q0{q3zM>jzfSK%Ip=^YO(c{@DjtfBNBtGvot}X9wiPK`ah~uoH~U zSZ!kCkYqne#Z2VYq~l3&WOw|x0w-hR{V4Y~Mh~{j=LLDTRB9A%ggv!tf~gtmt=kY@ z8%ldBx_9tdgYp|?L>K+1=bNqc&pN)>D2i$~n7Z3g^N^`>KIRtq>-*cq{^q+!+~_s$ zofE!>_G@ncEzNh+{S2CJ7j)mQ>J0=@%2ysiEMRc#-1($i)p zysOVWvE|7t%`zDkrDf;tZIr*dy?r1n$^*5Dr0wV(-t{aZhkG*v?3M8edDSMVhIGjs z9g01uwSD=&U$3G@aB}qNjuKbTPq(aesp2Tu);$s^teps;K(b++&pKh z4ZX-A)~|lG&(1Xnt$d~G;aYHXI5PqYLv*Zf?d!nJ^AOnG;7a7=3T3OTUN2YNpa%UDtY3>pro<<$$$_?w52mI6vk&kY zqfc*Bi|G<~>zB?yzkIi6H&2LqC)Bg6;Kxi)pljL#%ydh9+B2%TvlBQll^onnoS-IU zqPzWIAZ3DCP=mWxVY$;tn!mqGS}Ugk1^E01N3{pU$4AiLq?npxiA!ty#k+oz4!T@ zC%a`hh-_v7mV0^Q!s?%W|JsMwmzD_}m9%t?0D;&XW=?=GQf8#oQU z8+`6W=@C9N>h%1ee7LcHZ~bt4L3m7X<<(bsI|YQ zruI+uWo_!a4X>(|>k~WCHj!v){in<1Omo&O?w@=Acdq_%T5b*P;Hjp+!8>Iu0uU{LerS|-Oyewp@digqC(85f1h;PGMj@BaG9 zVWh!uX@Pr{&+|2MN{56KoE>D~CJ#6fWpX0-q^5I9O#yO+D$LnEz=?s3Y&jrT|K8if zKmXxdSI*?YMuLJF2a$Kn@YTJipWZ&)9m52LAq;{wMsxk@*Q+}L)MU~d=%0@71ZJAC z{MLyXVpwK;@8;#;CES$4&e-lej2-|cRRdre;SiQS2<#PqV0{PRRl+HPndVvMWpsy; z#6b6+5y{Dhp{MvWMrX| zG{c>f@Cd15OEY<1HAbh28oQeVFqQ4a)T(gJGzTUXeVU|+wI4J28nvbG5hk9;q5R_? z@LDT;3o9R|I4R9Mc;d&u$PctLKj73h51sYg5 zvqy4LXCsbeQlq5r0QBpX;GfE2f}m8#0oOynX`@-~{+pb&U|y22lZ=4hKP!kSu*D&Y53dUwGIrI-3H{H#!cNX#F&whBprVMfSXm1J7xKb66(gN#HG zB5^_3SA247``bsG2N4G0AZ}$&=FWa6|x@;GmG@MYO0667$r}B?eKd zeLInNlbguXp)|QONgyhwfzUtRlVd$c{au_8#YGG-xzRa7CV z{HJ8}Q!@ zbRPUV&kuCO@16IzEPA!GkEvaK2tNM}tOpDxvm8?&L6;phRKmG(ZEDX`dE0igavW;4 z9wt2;cP21b^BmPvfdPmJ6UuT#LLQc$m)Xz1e6kHQAN*M$C44Za>{tO__@-I*r0>e>td__#RC z@=&N+paa4;8}{tLEL(=_5|=;y@bVHNxH3UOu`TSc#wDBRuWH=A;TZkL(XW{^sT)TX zwFHDJMFH61rXox{ag}s{m|{6%GG+piI;mj9_-0*y{@LTldwxhu$^*Db+<$vb{^Ca$ zKfIQm8$cA|2$eY52ySMal>V*>mU-pE=~iP1RCUaRE{x#rIuWxu05_D1Xn-1Ea8+`J zsmD@4uC7L>gp)~i}rcAAOvUy_xqsl0`^CUEhc&k3LX4s>pJ3{kuSIyQL2+{T` z1*y9Nm849Zf+2HKDL|$nnf%tKMD7%b8@JV zOH#FQ&28)2gx7_isz#U6uW{=Mz$@9*bv7z|PJO<6X~fFPN>P^C(qLrRJiwg?&p2O-F^Y}fzI^uV5FAw! zVIWR>m(tmP@|2yu-LHNfwKtn`VgqEzoj}Afsu>7m=FA8}8jI!OlBp|jSfUhckMZj- zw!eO~9c6i}L?We6B*BW}?TMTSH2KrhhQu z!k*=ss=686ImjrgQFdtA@4nvI7{NFrVj*FOP@w8OmJX@vJ?I?1b8=`WLZGSQR2!bQ z6ycai!zcIGHD>B?jE>h$=Zg+zI$qXK^Ctvm4DvfO$BT;bui{4Ne%7;Hk)wwh7FP}{ zh(I(a_h6obP&3Khc4V3px?F#nbJ$TDQk+V6t{X?xL=AIF0!Xg`E@`+Vq48$cI4nIK z=YRR>z75VO1t$CW_p(Ko>n>o2>ENOs;8PQOxlaPc^ zwMsh2F7*jw{hBVB&Y^|v{$v}II{;<@2ykKdqCAt+&CBOl$1GfepFKZ#wgbwb&gKx| z`J|&2m(pXVo&db!D(j>gl^WDOt;p%_WLXle6QRn^wbHQr|2u^%Ln*_0`N!D6d zz8II!-oFSOpBz9h9v42{?X;4fMKAl<*Ey?+KlWR*Z)SJ)IzjWP>22qZoTp)Kjv4J% z=U<;}oAw{YRL8J%9$&ebRsrr#AqI=a{3jn?di&CH?juqq&I=5;M)I56&p!WlysuCul8j8U zNLgW-8$pdqWab%0S{QLMajy~y`rxpBy$W!Zy0!{;W;0*T=;o#T(n=O={!FeqobkjIKfd{+57t%%ON7j!<4!r}#RfeWqkjj8AaH5M4~>$bfl^^pt%R$o zf(Ij6`8U7)=IQ1k^N=|=V~1GF(Y*12L0g}b%DFrX_ouNq%`*kUw3qx$C&4Fn{b+ zfhOGmZtV`DrfJ0q+nbYtB@DK9%fI^M{y40aE(!XZDO>?h#d`NNd0g3yVqON^yqV_d zH|kjEk1B%AwX~d&8P*2)!8>QZfAh-PfLRMBE)6B+cOGs2?yF~;hZqx(i7N$ANP(6f z)uX|QC55+khba1jYrkF=UBMtkYG&?%Gcv3OeDKz}A;trNIqw|kw~v$tC@fh?)3nCN z+ZO56B?JBH3BXHLSSMH??b;9~@jX0|pH<1G2-rHroyS`qmd$7Yee2xPwQ~pxXkAUB zbY1ZN4BD?(KvC5|{&)72`T|1Zm zz3*Rm`#e^F+<+ox3~uYvUMPR@2v5)I2s4HenGsA0%9YHBh}6``qHB-wxRb(>cH z`+R}L%K-h?z70=63{D_nn)BdAoM8c}@OB@d`(a_SC1%)NcgPz}S{zjY?ZlY-L8sC8 zpiU$?veke6n|oUY4x&glP;+KBi*Rd?xmS6_PBt-4KjHCm>Z4B>urh;X>Pv?AFVjyy zJbUxvG8enUKxJtjmbb_Jn_EwBJ+&PL4~Rsfsk>z&0!D<8)ZQ&{GH<+GdXUwxm*)Tg zn9RXUtl$!Fox}C>%b6DhDLlLP^!fT8Bu}%LluU&h-<4)kD4nFMvQl4L?Fqmu!&kFv z|B8C1xt7N777kM2Q1Q*9gOO#?SO{kZ^!~Ngfg>jf!D_r>8o57z_Uolq6MU3rN|=n< zIThgh&>X}Ztc&6vQFoYAwAvw!}pJ6mztco_(46>Mf^>e#n8$j_;( z{Xjd?tF99_`tnLF-qpCb{yQTUn(|s&oKV|U)SL*pcO*uwMJHH)TR{J`ukFahgN`<7 z>dl{hx4GN5naX|Z{zzjBJDJu1+L6Q4(yyu=;BDydHPuXaF-uT`8bumDJCJ|<+l?3o zC9)!Fni4jRZg5X-RbJ2b0z`9MxCG7wVrA`3f%cd}fA#9u%b!nR=0cJxR?J|x;P~LJ z)n(Se6pi+kZ{6D|tJ(j?5i6BQyb~TsZ6D#D0`vsnwb0dyh9*CXWJUqF6B%Fuk2bKm z8;yp-JP3aM;>y_}NFe}KGcpP?VTSj6v|ler07xxW62b7mE^J_jYh-p3L?8w!0vd`R6p=~p0BQBBY;KE=2=Id|Q?ZEN~GMKx% zYwA>`SzZ9{W!U+WZCn4Um|CJER7@b%oxJHU`=$;k0aSng);|uRxSjnvrB80(# zW#4QZ{OBwjn8)hZCrKx4cZfcSAhE$8S;3Y&|X~wl&~|#-N)O91w=Av zap~;v`sHB&1aOBsz%Vy=OA_sV_3KrT(qt6d2pCL+)U-6X$X8LEmhP74*&nQelB~x)nVNdaK_xQNG7@D^C(yi42Lj{Yt3vA{^$+hru`*vWUSMW;p!+NlEkLN(GU zW1qj{w-+ZfKs$s1&AU2zx6vu&bE_NB_yR3DZ?}g88}I+lCtm$K$%`OPiAI)a0N~8Y z&^YVZr;+UBuW$PpV^3n4x*PaXa03BW7b zsqL@Lln7=K3$!6?wWeMyQfi@NM6F&J-CyTJIXTV`LK*s((=7M{MDBa4n5~= z;DEUixoRnb2K{rLWZH6juZy;hc2&3$(@Zh}x)tcgQ@>>ZT2BJhIlhY&>dgcx*ZgB{ znfquxPlp`gL^%N8)f=$5>2VT+AZBjAnX}K+ab>Ma>clO^(PXqu`PDXBqh>QCIa&HQ z^%lrGhOl*#S3P@Je=B_zO^v7omtp1Ke0ul64n{PH5Dr026&hX5!4L-35ym!E)So(z zX4j%Vz|=jBPL08EcbKz#AZ1b~2U)4XeKo@eZ{a5&T)J{rLfi}RLi0mg{rcg~FFxH| zKSUWYCNpvMl9>bq1-nc+CiSadFHv2sPoWG4G|iW*X2APzudb~Kv;@f**;n@u3kL#9 zg95~4t|F`&=b8RY%%J<#6M&a2Ql{NBp#dVIs#%^zHDfUb0v>Pr_Q6<52*x^k=jyqY z3{W%|iTW8B&dJ-ke{cKsQU|bbR4YpZz(NX(DFbY2sbGBjxcJTIPq+8fWk4Y?;@T2_ zbp68jZZ2O~21l@ICU8{%mOy!>^lji99b1O<7eCK>8tHO|xxs2GqL45sO(HKJ0RQb@ z-QJh88irbxd4VdE$Uv6TqX2Jf5@^O3sHq3Hh8O2l{aX{m-U9UXnDIpUgSNQ8HH0t? zRcA`M$EW#rW(Eka#HHtTOMn(VoEPL0EdIk6{tBK9Z%n^S=%y|-xT0}`ZOsyR_jB=? zdDc$Pq2?Zq;fSM2XY0I}>M}tgj3MLf{6GE0w}%u8$`yf_4QY0kQlJ^&aHZFF{-34? zt(fTajXaY;ZsTZUzq*E>ezf-CTWd=w20_%wW$F3YetT>E>!;(f@S!sgmWm=;^kE1> zh*3)|tsZ{sSHE7ovf3m}poxYd5hlml3f{W7G9a~BMxtjs`En!*f_)|-yD2-e>aA+;|Q1zX?!*t{qUW0H!twn3+V?dVCm=%2cdlTBvu+;D()5^XDzX~9@<8;>1fx_@jG;On;Ue08${ zr|THZMh$e{$>{`QbjN=iS07LAJTrgDGzVxvJYljunvZ}R{y@#Y)WR%jU;v%WIQB@g z=S#o*>hb6I4#u=%GK@y;jHG(@r3%%ah3x+7DwjrNV5FNjuA^QQ1;Mkx0mcz4jQ1~R zfB%P_++W(euwA9PASvM1*`8IK;vfb)zIEW}5G9U#Jhcr7jrQhpUPXJyOX6anC+Zra)$z3g^zVY3(CnMDC^~J1Q#Bt% zC!e?>lic)eX2Oy&odYn(|7Z5!5%nowew2J9-*89cEscY%w{L6T1@(u30ATrcs#?;HaKB!f0#xOHa_9P>;2?kpLgx7B?en>p zOb+7porA|)u_Q!?)=hxQQmfDX>IuN>*qv~mzSD__V`(ILX>i8g7~ecxHy$#Gt-OA5 z^~yOQR=YXiv323cwD*I9h3-oc1H`KGxg!pKl!iVHwOqG5FyR-n;zq zjipOV@Sq%0u=lGnc}yRxfzN-Is%j@1ajslfeQXwsesn8Lyog2BllAahqUGcykB zhw;wl=-xixULSclPb`H z{qb2f`CK%=paVeMy3Iyfwx?S8Z`JPeRS}QV<^vp&pRj;aRd%l2ig9R(b3nCgb4$(D z(t}NDfoA+hE2n=Dh`s)r(l)C)08G_vZ@t-xkqyhR{Kfs9TaRpP1Mm=*UQ??1lY27- z;3qtS7JchTLS6?YIRV5@>|hu{V=Rau5*TdiFefXijOPdV{>|YBZ=G49v5gNi8Gu)w zAMmd~-?+bleaD!f0t(eAO@9jR*UOwvn!J-b!K<0K0RS?i=$Fso`lYk11rb38cOP%; z7dR+^fT-@E5VHDAFfS&!Up)bMafH>{Nt2;65S&DU6UpMRCsDbafzaUtOUH zHZb5RWxi^`Qbh?;_B^C#t^Il#dg`h|%z;&~J;Ln=#n%tEw)c%V*H|tEyKqMS?1z_b zT*NX%M@3+`nVAA$;Sd6dRgJ*p)bdZ86Qq7Z_E~=qVOlQP)`W#Kwe&H4`6u@B#IJ;VZ_3GD4 zPs*BJpig@l|2FI3BXJ4 z&ZZt%qyJjv>keX4g8}QC{&ami8=i@ZjO@mh^JkLre=TZuH*#kuPQ^!3RP(_79_`ml z)lYH?T z?#KWF86h&1-Pn(zr;9-UNg<2FqLQPs)p7_)bbme?eY^4e{?_QulRXP(oB}fs^MMeP zQ!@xm#0+l0SwjEqP%w~zCRxA0Y_@I%>uG`-r_-QjE7McJbP-6MhyMMD2frAAo@EfP z`SyxC5_64@Fwjdr2g!0K zp%}{;6-ELPRUF2vtN4o_uKnQcwM-8PItItV>KBhTe*XE^c7ZTNjFxfeMc4g$8T6kH z8}h2-Ob&t(ER#S^c@``}7=du}>ZJgv5$8)!o^9>yp@_-wi({#iD(%GjnfoR{PXJ!} z3`*`*<(?+ZDu4vz(m6m051wq67SxGMmxH}?g}g)-zywugW;bn|LQ>tf*Q@nw&IyrF z`-P*@rPq~=ls?+FS0uo}1+fpq!!3OJ_2$#(W21o+72F9*W{1BX;Gz-DlFynYJ^_tt>2RUriFNO!n<8DmkDW-1~g z0idWc%Q$DJu@4mQUkM++b$&&3Ag*r6mbS6>IuM0 zZBV7?WaPxo>~L4Wz$hcKA?+4;@GNfaMWqa`IT!!VkFI1Ta!URt&dhGcEDkbCQ@~Z> zr=b}AyWFq(bm+#WY);M&F^Cfzv6DNDVCiz}PCy`5!gImzo)o{myRkJ2PD=tAqFklJ zfAEvbH!pFn7{JM#nVi(wK#5>E07!C>5v&Sor6dJG zU8YTT^3(*rGLbN+NrihuU+iIL_hcc)QH` z#G~3ouP@Zg38#EX3;&Qs{GlSg)zm7CXWrh{joNOlwF(H6#D+#0(7b>;D}XAMmvfcd zKuz)kPh>@tED5e}omhZIRaTo0MMMsiMVAs3@?9Ey`mFrL-MEWkNf{HwRon^CG4f7KKPBbxGr|cPAtE{B-zB##(o1`NnonG9HJW3q9#o&37eR6m6(?@YH!+|S;JIquo>i{RACMdx?g}2rPj2`~?s|9`<(SH-G zk(vPvz|6BjfIGS8Kvv?%AFgS+AM!9(-W%iIlTjp;fRjW`t>MO_83yZJ7JCBlvP)=s z)G4L7Q^5WhM)>yOI_Jy80vo?|`CJBMP_F#le9E4Dvi0j$SHD5~)jA;(oXJz~(mTm> zFgVQI!C*1w0@zpl{{F$8r#oX03KFtlhu7BfKl|a8At3`oqi^Yo&8QV}l#)#`e=GWY z^pAzn*o$0BW)7lii7*jj5s4TqDub^cY#z|+{q^xd5uC!r%AJTLVYWJxtMO+<_up1g zpQ{Y7uFbsHjgD@b>{RW)&J6Y$R^W}DS6e=GB8mr0*%Qqb8ofA3cg&qFekC{fi@&fL z9nlf_22-&Be%$*xy~pObKeeU;xb@%m@9cc;^;k*z9gQm}*O7C?AO^@&Byc)-nV4AI zT^K>)zJAY&mj1zgSQGA#EP zqhCjC-qy*vDGX3+7hB5n61NOGAiQ_|vKAu}i6l>-@9m5LfdU~*oFP%>>OA9az0jg3 z054UNB_pUisf!tbhzUXYt-bXi9fAH?oxgi1>L9MF)5g<@u z3#XNyy^ams4K`(WA~u7Kjh`Rd)&cH5e!jJP5Zy(jYBf~2#HY0Qv;XpBak+goG4bKcuUBiFOc ziaS4rDJRf*pNP+dLe#^CP04a93fdvgFjp}XvuKRGu)&uP)<5}X&+;W;K+a~-T>)sc zBX+`U5A9R~HudAD?NH_>dDjI9X3NMjKop1sV+Se2mIXh2clCp-O9S0r&7IxMvM1}s z&wu@FuRsCXFQEiQq+nnLlCMB2XH=m#eKc#oPI@Wq(%=*do-y9LnlH04$HL>@SnobM zEUh{$4esd&>##kd9^du^;N>c^lp3hy&hC^<+sFYIZ13UG`i@I3LLLv_y?$YJI9=@T zjnevcs{O_WHUR8I$}n;x2bl;LFv)3d*+9{J4#}A1lTwB zXLg385($xmAmlkb#Q4$mm7jh5cBcDF0j{nV4&vZ%zIeVf267xm=RAw1Qv|OSq})p~ z`t^cL06+j%81G-ZBq+h|Ven{UcVh<>5FKV(75*zZ8&$3?{ptz8ivuzzAt8b_2!vq3 zNb&Xk4dY=EoyjhpTfVx6LH~yK>t(lGb-~2o0bUB9pJ{oq_9~U&=a5``s!Kv^Dnmw%FO}hG>t37-ff4qzdnLU zAIr3lKD!)o*s_CD>4410j2vKcqEgS~VF|5KY4cRUPMkx z9HTRY(~BZYA+NRnMUVdb^@8OjcPB#@@$MBqzmf}kgcLOR_Q~#kgfmFEKGN&i;(ojJ z1mGn%Uefs1p+L^UB#6M{O>FO%(U}Q>%J*)Z%?S-WIYRy1uYN5CMBcH^a3Uvmf-{9o znfDd99v$3%@bu6al8;B@C9%t^*-yWJ@$3-dC9Dj@OhPW?3~ThhS_M%bhyGhwVNMx$ z3ZN_kA14GQ$>zu%(NR$N=E?Ktaq#8+O$}$F2L*^pM2KLfFqh={!!%{?*#N;t*53|! z?T`Tm8Vkr7v^P=bchUa@hq_~dVq{+I7n%tKrn-det<@wOPc>$};O(8S0&3+3_^fEBmG10Q(GYFZr#2hGygoo<4$DnvsmlQ{$s%<# z3mjljGb0d7^nBM=|MGX=K95vzUI~-U(ir{`xc`Kd`&4~^Bc7+u0C$1`3QEI2)nJm2 zBb(;r%K?A-!^<}>uPz65M1)}3(!HlUU)>!aD#Bo(E>)qdu@*=UjeR+`UoTX5s0aWc zj?D1xTWeH~iO3~;wtIMgT@@f^fXvL9NT}zVJpp(H%aC0B8OlsdjIm*7jQh`aRhG>? zu-&+Pc5Mkc!Q(VUNPD+`8~b%K0)Q0Bo5Fj>r? z-#I_{lMj|w0>qt}K{6_;dBzm48&U-i2B_1iht3xbw9J(&9KF@svd-qgiXu&WxLYey(dg)EZoDp3vP0o^cN2XwjfVaLz_py}RYVxV5p1VFXj{2TJf43)?>8 zI6cYZk2(n@^CdTSo8SXx^WYv}K4h#0eE(+t_Qfp29x#feBZNDT4?p|5+&+Y+d}>io?tk-YB*K(uQfxAu>&@CGfD3Cu=u zHIJW3378rfJ>lHyq!L^?fK7_ci-bedF$2pYwF;Q09Mr60e4^-QkN zLIDd)Pj-q=Ztv_Ah{Q$#Aa>{O5!kPOz1YcznH)aM!3BQ!?zzmyLdto*Q|QJXMhXbP z>>x8&w#>U=Vzn9Z6^w>oX0 zN)=$7G`$P85BofvJu@c!w|8sd?vvhTXPl35E1H^W=!PQH|F-;^e3q7Awj0pWa2YDm z5phSu18Pl@wEaCh?4p)(No^{`pz7D9SDAn=8MBia)L4Xq#8@b05B3KC;&)H>O|1Tj zq%55r5A^|p8O#4;IrgkPZ^2>SxTMV6h=79~g7k?Im^E#}I-Zc3n9MS0rvCO>{Mm<> zF0Eu*9!AlT@RO1K`u5I~J$N91tt^9!Si)lFJs|7X=`WP&;8pWNqXU^?h49{$a|0@4 zj2?zxeDm-SC;?)21%pK-TI_dQPXJzG^AVz|y5%{=5+TDV;>l(ldw?)dE(N`DaljF5 z#%Wr!U;R2+J!6&`l4B_!6r(W{fhmfV8Sbo?pM0~u?|JD#h$N1$tmHqudG^W*Xj}<) zD?@zeR{2@$fED&CPwWUsgm%^cm@4BdZD$dMa8TOg=i{9?xczX;!g6U|r^9r$94&+Y znef*MOrPh^*rWthQ@pjhqoeqrF?E@sf10cNuaqYfmH$-Le=hl-MXS`QLi?Og=5#p# zule?pSz`6yctq2HrwsdNW(F!n{_#`BPUu**PNfahdLEyc{M053%{AfC@=>G)WB=rU7qH^m`TX2~NJ|H)48OX!R{}emT5z>J+AL6J-5ut@r%=vCf-ne5$;qfLf+zIZGV({)ma!%7Z)-?eg74PMz_ioAPkgq=7qrd#*!H%CP5F`tJGHN~B z3V220((YIeD$^bVImA7{13(OCBtDZof(YQ0yv>FoaF+3-cUHcC<9x6~^}_Oeqx3Hx zZr^$AV}m-uG0cKT?Mr0+da0VM!wG5@7;8hkdwFe%Ox%sb46I8L%0TvzjyP($8Tq=j3q_@VwvjyUKK7qp^XMyk%Nuid$lfFs<c97TkP^r!uPz08WyD8;b5iR0S&?DCl<(ZU=E zgZoc+4;5+XM6DkEW zVg=li5Cvn4Ft1F^U*+lnq0{1%40p*no>CV zMRDTMkmA@x(%E}z$itBb+1axXwhnhnMi_#Fs=+NCdmtsaK*-sd64jZE?Y3ck7u6-f zdJBh5&}Y};9kb{kO?AJ8K09#9omo@}C* z+D(#Up6;k_z!9;;Q_Oj;8EEyG$wyGR_fQKPbd6%`SCYmLd?sYN+tuM(v(!As$iPY1 zB}Q-tlQY~w#6r+Q{n=su*T3HxiHwcBJ8W~r;0@-*>MbG$C!gEtlK&(fj1#{ACkF#O z=@m>qECwjLJCHGRSuVSMbS3-2jf*R+<>=5^bhv!$$>taL#)m+xG<-cM>(`4fVRAPf zNTH=WGQ!)J&MdRCMUbpNKiu5M*bxDdVA@w>djjxsS38fIi5OuFeDin%!<9ly_IUlm zxpM>L1XDOeVUk7w`z_b67X{WS<#$B*;_kuSr+cLjioyp(=W_bVdl#>*Q3lOK0UH%# z5irvPK>=xau(I(ZH*zOSEFd{3*X@8=M0Zlr{}CdDBTPaUjWa5!ps;m_hnu@4GDsey z1qqY{OUVk!jhq+)VrK>e^YUD$+!&`LU^~JO)J5NEK}ZWeVhUe2^7O`0bT)2m>QxbS z75qMv`87YL%4b#bv+(yjyQW^`q8HryOXqY0j{cLIJKOZH<^a=uo9-8r21}cnv^hYB zy>v4r&`|+R{dM)_w2GNya`q~E!-?Q(@vJs#@`z)P)+2nGav z`*^gkI8-IF<(zI_9)yUTq3RS^p>8gHd81#aI-_-6_M>Cp@bk|$p6r&Itwsw&&enqe z?A>!W&*5A^ARHE@2jO9UFgnaaO75)fM2HkHh7y#`I66flB{z1k1vXhwCZ-colw%>t zv23RkdI~-$@r&PnxpP=X7b0;-kQ_+)U`9|OuoECgoQ9ldefQhyf1VBSs$|@l#iK0_ zfVL%QJ?hxa5=K?~pDIbu#pu)eejJh2H5G;XcYaHsWYBZ|@b3(;KK55oJqdj5@2#Ge zr$$GJ<}{I}-HIBq(A30vmweXDlAJsh|JkXE-y4QNs;ZYDmLxzc}wc(fGePkoe>^y?v*ZPJ``L!yR^HCCFDD{oM@vhalrF@PcuX<^e)HwCedU9w?#5P}8`4icICp6U7=u*d z9KM(@%~sawkv22LK#yo&13$ zbx(GHTq4^n>90P&f1rW0d|VWREK`jsO{tykRYCLmX&RkL%Id}(DM)7;m|9+qGaf;0 zug?j+m^c4AQU1^Zlb_a~S!wzw0Rydf;AF5EM5ja5e=vN%NR~5y?BPVy0`uk{PC%X~ z);)9lf;wRWlUK!QL!d()C;0%~#?FF9!6aR{oetLOAW>_EzyWtlPp+z*( zG8t25lw>wZ+iW!xNRvHDR+NGXPHHjn0_1#hq)%RZ8X2nkGtH>PRKdW_MYxO#W@2&E zfgnU&Ucpa3IJX*%wIIS+eP8)+zI=K}C|H!Ztt_&7!eHtk>4`$Wy4%yi06ddWjxEnP zmJr9eWn4P5ET$~tS$_Z7#>hYc(X0}`rZa&vc@@Fl^tGI(E^}{I4fjnW03KPR7zpHG z16$HXfJ}v)h}29|_0HAZ4hf?SUq2r09#TM-MLVC#`&X94p@uMky0M#7HKU$!_N%kw zN-vF!h+xD{>{Ys)xfz^@+^ICgfX#@Xf3dkWrsyKj%=fRJ#gE=!IllrZM5^Ev@9>EWyA!O^Ps8SvD&5^+g%^>Oomc@? zgDEV+qZ-_cas)PYHKI~6LjDi`<(>WIcgMU;Aq&E>97`aAk%J*jIVcz#CNX1JlEEA1O*CHsqkek%y; z=xX$h-j=O1tv1Mg^=%+*(P8AM?ZhEhk=GrMhInOnz5T{ zABMa?#4>~8Jm;3 zM-c#SutsC(B`%-ApS*we>MBXG7l3GCH)enN>Elg<3d#~f5Kz>Th19GW?`hA+^cbpWw1KrGLBrrL6mPEj|+kdM=yzuh)h9-%t=()&B>Hq8JYqC z=j&s80`SLPpluaT;qC?}mIRWR2+W>`jeR`b-ZumRt!Ck^3ujkya8(h}szB3N6!t2h zezowMa1ds9bC@-Qx=sWNL8|gzhV2nP|7K^m1ZM-&I0$}jNq+R<`7;BsArk=R?U>Z6 zlFe6Gv`QC_hC%zp`b@9|E-EJ*z?lVjvAWxi6+7D)CVqRJrm_}xDa4E}=cW~?R z{!W=I=W0gqAe4wVRU^z?nQbBsF;65P+%1Q;OkmLDL)GBY37*h@Q_-E9B+&S~*J9HS z+-%qW+dh)iwd(IC2QPXz{lxG4A3p@@c5mji3_8%h`_4>i_S50P-p*&BIq4ASeDo6* z;xk}}E;y^dlU|!GZ$i4Ie4S`AFH93qih`imh@l;`*{EF&)V|hS4^z+O3!Mo?L ztSx6`LKKb0KKSI;*479#M4>RpARojs1`(!oUZh?l)UTtra&>g4J?UUzb%-k$&IB^k zGP-Q;jJ6M;3@|53$qXX6cj`E^`Pe-H_@lnkRLVt$SJww47+Jbdw6h@1oFEQS;L)=^ zRTBoR$b((Jh&-!mul1#cS~e5?>epny1rLaDMB}Kzjfuem4kYDR74U$KJ$&-j`rcTh z8p=_Q;_|tbKmGA#aSSt%!!35&?~WJPZ!dXSJ$5iL!EP}oXC;s9<{)P>u*1w$H5Mg< zU^vBpF~8VEXf(+QZqbIx zrL;vmn|qq?s%o>t%`AizYqcjMAI(ZkHt3hW)&Z@+r>^bj$JGGg?M z@|06(sYgj5^kUk6&D(u01Wrx7c7KQ&moJ7hL(ZUXc39}crw640$lTZ+&dJ}(EH#5Y zxndw)0G#N}l$^b31ORDt3AJ9?sL36z9N7Sv8XO>2U~i148+&FhWNhObSJ#F)Vo`gH zOjskes+0ZdSG^S!NdoTzC$sb)0~`h!1MBkg_r8W7?NJUaOV5(tz^JTj?rEj zI4N~HI}MmN)H|V5=Mi_F+(KmW?;>_)r+OG5HPMLcF$j&3h|Jk|`R*2e{ncX`tT1x| z{mCZW-KU^-8?R5a*DYAs5%YL^8rY{jf*jpCuD6*6(hmZ#}XC0TK+NMzM@c1agBW84#HhDoZTK%O2)0To;%(>5f{LO?3uc z^=UAW;5<9d4)M;l!8=#hmc#^PCcCBm?(2sehbS0YH|N|8?)7{|@2TCdxdedW>`gjM zZRur-r5rb}tPRO>3FiD{b9ZYm;W{yQLz2?DGdqZ#*dVFT462&*Z=Pq+8%6*?;>^xK zD*UHg1t?lR>g3MOC>-BDEXGmPAkZ^Ix_%jCDI7)HatnZ_#+drmFC;w)F(d;CRLL}< z6*cex>m&U7*0X)hA_5UI()X@k{P^a|06+nhIJ1;#Q3PhH2YD0ToLJQynId%Zb!>L; z(La@5138f;14J0y+|50WUZou0JkQ2uR2q&Y|7X9xw}Ug0@)*_KtB|0?z|Gpmj+l1o zp?2z1+nv1y(P~ggPMk0WO=`fk*khs?nH~$K1s?xC)p}W^j6dR?p31L%vD=j9{SS6~ znb&-hKjB#JG5>v@mnX1@44^e2&Ru(-dM2R_@x8sBxMi2g)7_^!9E%t&W1{p(VNSJw zbFc&lsaj!S4{QJQ7q<>98ygj7B%Dd+>IyS*a%XdZ&Ee!m3-SHY;{MZ~A5L!SRo7uV zvi+oef@{VI4wP71!h2T-H?OSaq(Rs?+t>V8Up;xU56V#$+&}_ncQ-Of6{y@_Li*J` zcOrEFnqz?gAc%|m&C9&DBpIWOcBpdq@j?(*Y&0>RuoTroP5^^gP&l^t@o0UA!qOnm1@Y}`7lVU=Oe*PPO&QQ!e0ud_zdGlu zWGLwbBXVM}2suLop6=q)J6ngI7tUt36zH8R7v8y&4G5WGzz|ng4Z>zxo#!TQI;WU6 zIc;5V(OB>zYr>AAAYJ`aiKYq|ur!{iQ56&^FT$C-8~Dxbr)7RFx)70wxVy%fS^?=V zYMy77xk$)m0WOSa*A1@1rFkCYi0u4k7A z*Dp(wW5!t49wgj!qP!mf?$`7t^GK#JG8ZNGAS~`aig>h-U)|o=El4S_@G$3_7teh3 zR+c-&kTC*0FvX&U~dMES#MRNL>H`Y)qDniZq3h37o)%av9F7 zkMVCld${LIW6vN#L=q}WPsL0k%oANlE4*n6sn_TYlx!3yh;3?epj*)G_$e+BHgxqN z_4M&fUhj(pb@j)^vH1Ro_jBt0Swo?k3;K*gY--Hcy99D(o6Vp3?mQ0@O>HFVq(&qr z;7s6p5kXbWjF_Ax(s0j~{@HK7*;1B#P>c`CvSbN~JTsgfjaIo0Q07|toZ{5&Or0CNe(oaz6%B+))N+(9fNl7N?xvm2rh z1s}XUc>Chn5XWTZl!m|Ru{dRMA z>>y^?kjsy*o%!fmSQU^0n#KmmK_qM-b9b;$u!XnKzb`^mO@(h#t~>#5m_k>x_+Tzo zXn!3ovap%Cxo}8t0g;!cC1qbe*#5)o8E*S5|U&kT#tfKCC-628Zht1F|-vytqkcl!D|~}ru5=g_`~d<&y_65 zm??+=Ftg^sjIrdw$}XMxC%^o1OcE&@X+Z*4xRN_*@&Gl5&B+3rP1nW?sen#+TAT9> z?kTnp6QhD!TR~)1nYQYv2)T}RiShAu{@(R-11jB0;&5o;7hgWzQbdND6SKj~am+(+ z3EHm?`Ue!y1iezsc6G?R`nVB|O@&y}}|%2*f&i=lZgjU^n695X#d2MZSH8UqdG?n4<*2wNX*L%6lq%J zU!(u_Sn%AEeA5~BsW)`a`Jhu0_QnS$mHaVjL>xtvuvka*k`?sHY{SWJc+Gu)*ZO)+ zrH?wgGtjbr^6sZuedwtpmoz+6bHmN9z$7}rCpp3Gz=0IwN9`=R>6b^7V|Jn}n*2sW zo@a+eap;3@H^!fSyK959rKK&$@G5u9tFSq$i%q8h?x$)=o&HqNoQ@{ZAI%;yuyv6Y zIhJ$LLtP@gcU9iGw6e^lYoU-bEdS=KttUIMAW_MU@TTzfs_X*iMh0-xL z+<&@Wl7LxkeD(aw`Bemh0I@7X2%e5J zR>opA$A=e}Ke{02Gl;@rPU^4*L0Jb%%~qXXt~Id$`X6!UwA_DAY;a=KW>BLPw+MGP z;t{gjPj)xs%BOd?w+oIGLYBKlnp@>*W2AY5xox38Q^&@Kr{vo0@y*VY)T$ouI=**H z{=7hxvM3+m`0D-(VeU8TAUfguv?ya?ZpJdTQoWkF-i8CTv%S*Z;AS|iWf#lSzs=kE z0P|=}-NI^MN~>Fy9-vl)JV5gOnEiLZ`0_b83|7jbOg81_c3@Ts=?cR|46XL)a_q!P6}TqJcP=ff{WcVKT+?M#8s#%D&n|$*M%1mGF4W z_r~fZ3=G)by}INDG6umb7Y3THBDM!K`}KxyqnUAA2dSZSs9<}9-`#q)AK4{?Yfi;` z*UrCxb$OLQg|jJKNhVf?sfS*TD=n5O9u1X_Km*5OtkZ`8RA$~pWH5CjVt~!bc<^+$ zyuV%C--=K7-Ls_#Dm7Lbp{BUsHD#||)tze%PlN0y=P#nl+`TgPX@D0^ySQ|xIV;#V zh5l)7A^DgBe>Z@(bK^-G@rzXSUo4!4Ufb;jG5wLZ*(u(s`{(|5?(3PI4VZJPuTwPI z9AJ7LV0vhHYT5*I^8s2N0H1PAty%|!?k{q{%~Lv9=3(Xb`uLN3VR1s!YaX+t5)=cT?%{X0pNvhSIY9?pet7N7%?q-e!OevrOkNG7PuJ4A=Rc=3 zR#4a2UKrmWeX&2eMyUJ96jfxCA7oa_MwWl`^ze|@et&PnvK5ygSx`+3p@YsREaNe314#%d;`2H@%Ie+pM{SzIC4hQe`I}n7BKPOl0g6Db@XE%f12kx z)eOKQ;C{r^FB2Ux6>!v{(asKYEaCt&o5yED#4w!?(A|FRc0oEwx(BVN3~VdakRQm} zKl$bDBIF~@6=ZHnVee3oRTdL72jx; z*4l~{BVvh^ee-BX10o)BzH|qzH)rm|8 zr0-ri|L&FHY6ep{nX@~CL8jg+On9p+*|GmierA=OnZNkUTZHpYq5_)xNOvcKMI~o~ zsFe7TbqbLdG$&@E~6*OQod8ZdLTF|IN#vYQJEv=X@$q zs?krz^!@1c8Row~(_j>}dHLcJKBM!1*V`dH?q$s0PW^bChA{Z)+8wjM{j@U%N0_>{ zUT4(@sI~j4elu4mHs5uMyP7fXgwSDXBD`Yt)bbVeY7!u=5Hcc)#$znqezg1511))I z4)SO)gIg7;m*N3VJ-2hLh4beA zczp-Ta7S|2rFKP!{M5F3JpuT;NC6T7NNk`A1Fp~%%y3ZP!P9LIgTgEjUAuVx+%kee z+{vApqbf_nWd`bc{et93 z+lXT6N-ko;&6r@qqxB$TTV9qfv*t&Zpic=4UJdi9I%AdZzr&1uZyX=4@9mX?FTZ() zFmz!K9Ak7x;0%*!)f!)-l6nx&ujMDqU77AK2B1kDG+nPu|2n3;BS8y4%2pUzhX(M> zFYaCcU&jG;#7qTu`waDW=ak{+AF5prkhEmeA3ZwHKX=%my)Ea;kccQ5OmQ6=+5F!0 z$S@d02g?$&GymwH|6(_>AS)BHsT=^RJh5Xc`X@>2J8dY~2?}dKtEDn=Vr?asB#1=> zb5p>X748mU3<)1y3GZDxvpj%OSq9p3`t0`3_8!d98v*rea!5G?WP~awyE?7Ar;@&d z!2k&ntDRfIwTqX?sdO$m+yLT!q;_HI`BY?&W^!=Y!Ae{}3gFXQ zo6is9xKx5=D6d~weZO}6OdWm*v9JMf1m;%6d3{xNZ-)SP0?TG^w)&=OOODr8v zby`nl>dM0ArWz%PQ`kPVr@QgN=6F8_rOfMbO4Ue$1zH;K<#Q{cXXmEhp+$1Sgw&dPrbFut04z z-x%z-qr1E_1@4vaC%2*isOv4;ye6(4s21f(SNC%>sRD-^EV{aDp65|9()|7|{mt$D zf(8z;+QcZS>N;Hp_v4RKpFZ|a2J~NG283prHcjR35FB8FnG$gb89=I$3>mP*_~5N@ z`)}AXIp#4&HDS$jt$E7gT8g4#3{jF47ydgN)S3($%az^%2V=3)QKm zbVSBZ#4kSIcs_RHAml^D53Zg6=z2C}K*0bfS8^j#h!c~UsS`ZK+Ip)KfW#KyAR=b8 zyiG92Ons5|mx#OigciVchj~X|Q5WAV{c=L{uff$VebN5f0d+MtMGg`1SGg{@Rz{Fi zDX?23n2kfr1Uq)c8`J*%-44TI4V6u*4Xu&T7q~6X6FA-D|6sS5`C}Kq{-dfZwBRG4 z)`yrRG%a8Xo}l*0&Y7^gYUI`lPK>T$s5ePfow8E%x3^qnCuE=w1FWMahzZ0{fr^0? zS~A#pxfovmZ~pC9+Zr@mbrUGe7!=$qjy;?2QQg~0IGaFxtNjFK9E2A11jsw#9Mlao z>vmvj9#!=-5>aWth}OGf)%)r~%i|4*aKXNb`1aW)B8J& zn7Zx;H$&^?u!F7A^!5zk&46%DaB;AcgB{`!0w=dAVN!QuHg^!iu_Sos%3uIM^RgU% zbAN9PM3EBa0x-`Z!HGrNj8hsn!4O^8`XSg&xI2eV%U^rv!`1H>6-N+nrG93n7zr6O&l{^?o z5vUnpqAE_VdLHlCW_J^aI+tOy>UR8on?Rb@<=z$)3%jL3KV3+0>Z?UncQZFd_T>3! zM+aX&+dZVbAaPXjdF)A`V?;hRC`s*!-Zc1CAc-ET&CXbgw6?_`GNE=jyQZe zd$!dGnizmOx1y)p1L!RVIOh+i)^oNtz_Gay>GFXHIq>|s4*&Yg&FwgF%CnHGI>3QN z%aUfAc(WjW`dbU8qfhu@r5N%BY{5Bcdwecw^ zGO{34n3ZAqm!Cg9G$;XtJc!1!dF3f+Z1Su6^~a9iCW`$@f455WC7<4J1X~LF_SIFy zkpQ4M&Q~(w!2D4Nf3z%8N^ znuEsm|HPN%Q?cHT$Jt2~z$f$oosJoH5*}!YJmf`b1qOH54>rqi=h;p{qVUSZfruRe zBu?DY($A{8=R!}Kr^yD6GXJ4z2}o1#pZkCl$j2x692m zX5|Q@v3zl7Z)AuHI0kthW0`1Q6qKB*!Y%6EuYT26R(4(;;H}GN2_uCT=J%dFR|bet zIXI&7u!8p;fIt2XQQgv~p9TR~obhA}+lM7_V6qJ3x33JTHz4TO^!_1s=BhZ@D82|F zHC6c7U4z_tc=&j8w{#9!mLZHF`khE(4pkSR~gm?;SePC_b|Zqg!zes`UOe6Nd)wvup+yQr#O{oV`)*UfnJuqQy!^@MqWN~6wLQ*DU5GPh ze3R$o100QzChub^IZxRgP8rkmrO4MnIVNxHoOj!S$~LG&q8FzT&+Lkc*zTw?U(9V5 zp{=HyYb-l8@|#{969g1o#F!k!L_%ONlW}-_DF5n{r-dvT2f&N*p_zsdrrbYI=<<0g zWRD|#z+Se5Ta|04+h;+zI4lMktiVw4(aq&6XP0u1!Gl@$Y6>w+~=Z5m9 zKfDqQ143}HY2ajcQ~P~VJ45KDY7h&q&?ij_I~w0F`Ylr<#W5OjRz@pLzIn2{RSa%D z**m0V;|u^3q|($Shmhp?>0Ou4c01oE_{lMQIJTwOP23W23UJ@4PA>2-N0U(2eYJD~ zANtqi$N$}g=`a6+kNewaM-Dol0(E13(GHnwHVI8{gGCj6Op{4aw^6_}!!|*Tj?Ao` z7%(+M%tQhfa3vnC#suJ$kHXr|fB$%6j04S_5Cmvh03C7I&dmpSF(xp#)-ZeL$v^Z7 z9c!i~>Z91z23aT%i=iN$Er0O-+J%*zqq2)qes5#v&PFj3n1P+0V3eG=-3Z1#`tR4A z4aY_qu$tlGnILSXx$^MNgRRoQOyo>XjXd@Z^qYDEgTQL@AFlqVz~(NVA4ZoQd+%Nz5Y7xy92A3q zEO0D~wr}_($?yc%uM-P@TShgD?f;I32&Ys3w~&DW%Gs0c{fz@W*eW&;V6p@fCK3?4 z*N%V{ESktVT4}!RP%zZ9&NP|D^m_Jps`fvr#d77}GG)oqf#}ojqOIK7))eGqgrIr; zV?oc+L07L&)BoLJ0xv&faPq%vwo5SS26$!W(+Ojqn-AcaN}6jA3QujbnGqD9_|Z^@ z158qfYtY}YfNEnWXPf#6B8P*=mhY7Lzxv(7!?3K*A+W)sskQL^sq%nljlWL*&b7>!2E)JX$8@;H5+uKzCy$Xchn_BoI^ zxful^hI;8k!TDwU@ZFV_5JM(~^O%>ve6ab=Gb;t;EJmEdJX1l2sGkJx*UT0-R~s-c zot2AchJjs;Ook8E_xB>Sw%(`$HMvg$eiHy3kiY>EMPOuj`uxyH+-(?ed2PUooEdI5 zYnIZlHyZudwoufBV8V%%@caN@-`^ftPT7*X57>VC@udqxPziPm>RIHqFfMOyjnq!7PVW%x7NllHv8u^`sjkdN>T|;0Z2MlUt4kUYD z0TYOs&CF%6i!=ZFlTFLcLI!F_RR><-VScK{!iyDUJLf&XL2AkIg2tvm0C~;vG z-+SlWQg9+b1_vtNZtSk_!vOM-$Qpa?)Ys?k^{cy2S(wQY8B&)>iV%=O6~x+N0Lr*phaj?d;wLptE2U3!gv@xdKp?d^e+mSSzwQ9iH?p4 zI9B&R_xH{}rF3$Fz4b1OIq3h--kjoYk=6BD0 z7!2?*4;WN;RdrP_Rh5-nW#-MiOT>*m7~JV@rYdJXs4Z&d?%aYALGrr65MYo_qq~_d zM?{XCqaIRgAq(gPR`Jmt{PN2?n~qjh;>X)F{`xOlJ4Y}9%sHxMIf4x)Vf>Tm{#7e9CoO2|-dZPrx-V|F0GtIBdA8jnh!WG*~v)&XSo}oclj_#_pJw-}x{A5bujJ;>P{EfBODiC^pO$ z0G%TB>QTiKfhV<53%YcB4(n^Eu;BCbIousDKXHB%ZqN+Uq2Kq3zDi?C(`ql$=kd3F z$Wvcb4d_A$e(dv81ppuLL-i;wsO{8rs?| zH%^CO>#mU*Ii!ziqk>l9(GC3k(VaC7jFlAQgQ&m%W_xc2^aSFAruB!J=bz zV~hv4;A?;;(UN2IY96hQECf(StB$6n7KORui1@ef4z~^&#TQQe?C=*4Z~f#hHWUho zb{L~E4qo7y)5ZW7H`dP6PmCpUp9?dK3$JNJ6@_kNdx|Ho_Gc^tQ523WsW25&p(epY zNp1j|$+mP}yegV8swMBu?GRo^@ozal^8znA&RgN9ffmW ztd95G$CuvE`5NshdlK?zmJ4y^k5d;&f@al#Ixvs{?(Y{65{(V1I@7;q62(et6Iwgm zC6Nl1GFE{!k&?y#`qQg7GX$)I9+dgY+lhid%Vd1dx;|XU!jz%^eq4|(lFgdQ3ekH` z3_rgwzj%Cm%qe1w;@{5rZ%+;mOZbsOeOU#wxZ18)$NV%mQbbinBOczuy&Ge-%7DXQ z-@iVjhd5Nh#$z91_@OP?KfIcm(aZu-0ozA-v9%|zaDa=`A3eI`3_dk=3e2dwswu9H z;lAjLk^0fJ!VLJ!v%_awd*(-^AxwYv_|8x6OA#!xhxWx_jwhWe_SW%fv%4CivgDQ253g|IR*!GPcw0|>IW*h zXYe8$IL>*8aZoGJEK&vXCiO1<)SlmP7NFK4B|AG)0R`fmsB_NgXzlfp{@?%jWH+e! zb%WxhME*y}gP-P4EDXbV%<|RT0<^so0zfQO6ScA7C->dY9^DDkJyogTU+>NS{A@Ng z%%V77NJ<;5=H2SZ*7;OHq=@sd7z)AX_cpwhjM4eg%dOpm5~hGES2Cd2e?Sl;=PX8g z%mm-PnpP-6h$F@A_2RR84gm^45fdK~x^e z`sEjH(_su_h<;R5)=%54C!=0-Cp2?kT3`~~5H@s?vg8tIvcSV@ z0n1+&zG1Ag{^!WdovY<;@eP+g5g&^rMEft`G1Z=4z|a-wxO^;SjpK8{VOCq1A0eV} z4$cV#Mp)YxV-buLV;L-rZv4-$zJGCqeT<^``M`Tw^qxEQp17)<#bNOLK>|fgB<24* z_G7j%c674jom z7%PjaP~iSe+#LInP@!dXPhV9t13YGB^xpl@hR+Wy000=`xEReMO2M1mBf2po)v7P< z-<~K&9yE%;24Wwy)9)@8Aa{htiZBPW0RtFKDkh&m~QIdvmfC?&~&Hky3^ z1)`kG+4s~Hd+5K%2tuE#(K0LMINTh(e!;y{894Y3fg^f%zl; zQ{J(D3@~@L>Rd7(q%DwkO_8$be0VUASCNl8pl2yCClAGJ055W(9)4461`tfeL~BAk zObRVV>b)q$&EU#n^KX9j&AW&oZa$JfQP+R)qYD{tr_U7RcQX_0&)2U`T^TJOk`w{~ zUVK>w@0|zM9e(lU=DizZ6`RF4mC;{bzI(NU3J4LhQUO{WgCjzr>b0^;96*c&Up%;@ zp+YpHd--UVay151gNK}EvXf&NpM}-%fHgI2Bm@>>apBBC!`_qfx z)VaiYbeR@VfIfYPfBx#}L3HBRydSGLp)k-C%1uy9RI&=1aU%Um!dr>X*2^K8uPdx_|{-ApNpXxd%UjIy1UxRDpcsiQ^#86Lm zJ`CtZo7%LV&qtVpLDkcq>bIoNe-Q1fMK!9R9WMwF!a* zB`I*-qrujQrye{D;=MW=Opf7@8E^pn=FeMuQyWb-5yHCiXOC|`*n|ca4oPynGOn+! z#ZYBdUu>_}NB@}L4o|tW&gcG5m+v3;8!!Ds0)WX4Bf}hRBVRku)Zl{nQYL@0FaB@BPhCelKR|1SRY4f~Fc%H)YJX z3gjA~XXEr=S|hMeb)B>R(ewXeFR{!)t!B{^tUZG}mw=WwmTCD9j466wqw$kLueCoP zjm>y#!p^$GrK=LOacPQ48sQ*XjD>Ro2_cRr>xY$;qdWhfzx~&#jw&fEX;oypRY_bp ztzhgX=7Lb++~$Du;!mA??wR9A$#e+@!{Ik1bjeybl zL%4tW)2k^kGmTC1PTFvwXSY}{<&+CbnXHaW9Ra|3P*Bch-W6#UdcoM?@!gG)MCW{< z|L*x)^O%-!&Oxk6{?>Rh8!&y@vo1}%3IIMGgfodIR=X||?K6onFr|4CYzbiGzlGwv1dPoi1xf zfRfXXmTZ-)gQYoBhb|{Th(V(uxLBeh%sVYaozWY8g&*C-FCN^PAee=j=yufKJ~^C? zq=dNwF$9TqPn9tehBn$0F#&6q(JBVG&WDMW5~IY4n@Fi@UMUJX;ztjQbzfCs3O_!q zMz6OK1wpK`3d+=(rvM<9%?hC;Ix7H*T?2f0^(jDY?xll6LO`8URal360GfcVm=SNb z4xDgW%g&8# zn@u!6x;^>nWA8$jk)za3w`rF@^%ldL^NO>U+U2Ytc;UD{p;jO;8k=7x4L}IdJ4c9# z3vRs6wZHjaf11f=&^4&5H}UkTq(=Yj3#+%8{?-Vrkx*p6W0HAdH8<<+OR@|wsUbjc0JKLw_cY%EjX8 zL~-I>yWq368q|d#;X2^Ms~-SRTIt{{SqBkGc8O9a4pRZv)5*?0cK7xLbckz(`|Q!W zcfAyBD-XCT5?=2^AWA1xf>fg#C8j}@<~$N zqoM#DO)RFg8&#=7MQ8YR{;~Z&B2=e=U&liMp@?~*Ph}8eG9ZlBqzhRNDewR^Y5dRRPR(5`!=hKGsm*H0f5WIK!+DZ-F|RBRC*y{ zz$Ka*$JQdwQ3`m^lEN{~17~;x$z=+1Oka2o?$I@ebn$09()yzj{fl*jR(r#b^CKC# zhd_OOX>I89H)%5Zy|4xV{U6Qk4QRlSqjP`vYo*(a2R* zROdnjJhqPT^|N=uMova+9&4`p55Kry018B_Ol!#~sUuS1hpaH4uZ?dR8~B*-r(WGU z*VmBjh-fgVM)4SJ9&q$#iogHu_q(sn~^JO8)l zfg}2YkEa2b$LGk8Pg z#siktH?UAGG&h|X48r+_fx%$TUB>$FeE3=F3EPSXgN9-%xBu>6zTFR~pb-ofR8#rE z$Vf)gC@|0jMs}sNW7~hv z%_gYV1)-d8gJ~?akO(ph1^!Mn{+$2Ldx&@tq)=f(Q==G3F(A&$nG|cUcf;4OXMg|O zx4(P7f9N(NyZ}p$wDRxQI^SIjz|_@6?N=01dy}Wv5Sj>apkG<}8~rr;GtkA6yNH=gS7( zTu8}9-6?ag?CJc>*9w{@95yas`EVR)5J`{EW+-Ov_MczP{_yOmDmH`BJB|JCQNnt659(axd#;k*4K zAUIH!q*KQTfR=iUQdx!z+=y4lbv(3z>u4monb@h0_|fAVV+V+t=-a*7L6xHRg!`dNGmVcf&Rb2N zA3zL{NZ<8zug!em6lGOW1s+Ec-#iO%52`2yXrASl4{trVr3ItL;2;8*T846Kn-5fC zJ`MUmX1iVXqh(=6Vo$@EdUOd;)CjXk$kf~)pT7Omi=)5)?UQ{@DmP}|JiD>Z&6O6r z^ z`cO|fv>o&5#d%w~iB3`M+UURi_S*wUpi5?q_g%}seAko zws*+}P}_hmpi>~?{w-{dor(pcxyiHFjD)HeQFg7rkZvL|ADY*IA#$|?fO$RPPDy~) zoCF{ak(gC@vokdr8>xt2Jh(kk6m_d+tw4;7F}8{VuKU3x_W>m0mj_%O3#bvX5}66U zdu2~w?ZB-=)ywS5N1LBN7(2oNYAVsUF1|t&T7At0jyGr6@y?C@-*YqW8~4y8GRbCG zodq!y&@saK@#~%Gnpo3Ez@#~YSJwAw5+0kZ9(YHXL-!2OQjFN1d8=KI?90Cdw) zQnREs#Qlu@-$Tjy5|Lv&)|Cf^3}_ok*Cm%39jMR@{<{!vUXDW9 zqmemT%#-UL=)b*%+Cg&>W}cGoz1v|7(0WbusXpB}=_?D(`+~Iru=I?pvr(!*=OQd< zjW3#>cp*qje}w{bn5zG`=Li4#%`9LN0wCTjIf*F@q#2B2f*kJROmP3)@cp8xL9|+_ z*#Ih`rjAgP!n>*p<53~3oZ<6(^2Pm4wId2ptbO-l`^A<`ONhEy(IJVQSt4q(v3yvy z1z-Q|9SsXiGC&U~=?G_dcz4r@K_$rO*{hv{8Dg_-q)ANL@^yPf0s7Prc(H~{o`6xI zN<#m;2RN8UxWYRfIX=9D0?z-e@dO9SuOKLGfAv;I-?!{J+q6*O= zZWQsyk0&?QpolQ276LGK4J56;IKkAD_p#^1h3>(v{Gl|#l0X3G{bUyOtM6YQ=-Qv2 zZI^DNG|B&R4t?5We~0Ef>IM56K5f%v2cD3*HEFBwopfF1v-_<@z})iOqPpeTbPRI9 z1AMCIBzbAGJoS3Empe2A0@p%_YbDqL?nWw)|IsVQpep?-?1$VxV8Jb?Qxi)~F zJ{9ITqfH>%#Q=jo;C$qxle_JA4%7o%2vTW9v5$@a@=sq?ZW3eyaU@$6Q_0^s(DGkD z3_$Zy>UR(D;SQ;2ueEt2~y(vtS0E__!VXnX2 zZyj14*K~VNqrRDU?Gv{c3I~n&{DCVZI+a-&XHoVKQ3g=am{fMcx67@2Rsq1LeZ;kP zJM-@_nyQ8n)VoLo03Kg`^TOarST%cm@774*2pB|iCh#f%_yHYNsGM`46F9AHt7wQJ zT4lO7!|(s{?udnnE5s&J{vZG0{<=r3>Mn631aOH1L`tr6E!LJ7-XF)Os{H_oo`#0I zklS;7H*ni{U`8{j`YHqq45&h#YO5*Ukah&At)Z1> z&oaq_wn%Axd3*bF&2P{)h2NS7qX**#1Pm4J3I@%YUv_Y32HDvQq^z8^R&dPgkG&2u zi`)-!%0k=Y4`*O}GDJLyg0(Eh8wR;qH6T&*8)MnlAD|tUU59Q~DFTq%QJB>$>X4=_ zWNB79z+8KPOZ~h}m8>4asvsB*G!aJ5;B_jKZ{E!Q@wcx_y=hb@Fjx(9K~kb6qmKsr z%*6oAj)jZExyu3<+6<7kXUo$ynofwo8#NkKMToKB|M8z5dOI9DR8fv9|A%k3_bLPh zRiXs|3KdZ^I)@PBDg?Ox=%2&!)a*`F!Wl-u=MU}{LUrEYo;-V9j8O(qP=yFURg=wL z9ZPiGHNdI~_|jDb8jzvt%*=T|tAcn0VEX{2i7N^V)ufQm?yorlkzSK<``~G=mWCh1 zF`i7S5G|4s76Czo(K#KBsrc@BxwTtT3erYW{_OFcF;Rd@YkWlOStO)3V&4rwecx)* zGA3^FEq(HL(O1+M*#N1m+#3b1Z)@U>psx^#abxJf<8NmR+hf@I#)L za?PJ33oQ%-<{$SwC#N?;vZ2*f06J3HLe^P>^3i9nQG33>bvKJqmvI}~Fjt-Y3 zx#*n+Gx!O|cmB(-zJ6CBz(hViNK9A1br2FC1w~(y&H>v&!;p#GA z(|kpEVnqD%%lqD@Yom!_v@^A@zMqwf8N?S8Mlw(d@1=@#g|}6<@0uUXy7D>)UqHO~ zB)y;zJib?`RSJV>8S(5jb%Y40b4dxb5n^k*37Gd3tO9^f{fL)710lpHQBVOd-X4}z z(!AP(+nbvs_@u><@qSo43QN`@v|1vrbB-VwjN+XG4Pv5*uplxczI|Rkd$q5{Cdop= z=l9ot^w5n3MY8#-GyF+K$P}sNu4gs>A<%jMHSe|h9Fyv+Arhfbi$-+;3Mfc{RTiG@ z9K4>%H*cm}hlmCx3w2VrA=XSD$@+R*D^^HS-4!qsKF_n)ee_>nf!zldpbykKqPBF> zjdf4PTyro7=x5$r04J%=ucpnVn7SvmXdhou!D7vyzDBLiIS2R3Q@x=js2fWfNvkdf zs0U`24xdP7g#qM-zJN*LMkJ?Ep6=;?|Ko1ZG1Nu1Ac2S=VJh@Oe@qM@ zvcNukSz++vH|@O-06~lA+xy?W znX!;y>UCVGvoff_XeMGSbFk~bOmwV{yl5NENOMXt+!*2R=ESiA;xzL6S6fjL>bkS! z*4LLf5As6|060hmwK#!Lb;&L<5{D&TZSR{nv&u{L`Mq^iP(Z|zNKnoW%$&tm=>J;h z2Y?t%)v3TKRAI0vYEJfM`0n{Ob!5c`9IYi%_aZTlAj`D59T&?Qs9lKe(2~9I!H$w``sP3*-(4XFBDAmGm$7=6m*2 zPc2Kj5Y8U+yatbW`89L)*L=j7#{jZ0gwUpWHyhr0G%J0NFlw*Ar5@w`rikv%I`tMP zL=+z;_x|oT-@cvVh(1aqbW@Xl#QL-SOsbuy1nzD1;6n}}6^Jm!07;)CLQH5qsSZFu zPn!sS`q}#3jRIk&g|EbY^K$FW0Rq6LR7;~esiN6J8==*4y|(ze$B)vLhC8Xg=m=E! z(ZidCMuA1>_EEWe2q;2?h^jc6E!-fuY6AZBPq$NfYQRUEgQY+m6ef7H9gixSIOlA= zz|9HPJcNv9>=lYSDZ&-{{~_cDoKq5^iXs4Gj7H}UBYyp-w=<4rWwkzbYp(iFzqq^R zAklI`I;oR$hLji=$#p*^`2q8N?Rb~G;8aV`>2>`E%;4^8M8GUksGuW?8H$&C<#sH- zd2_g56_t&gAFF7HQ4*Uj1N}?ItJ$t6U2NQZ+qosd$DMCFZ zn!KpI^~LJ+AAkMh0rZD^pBL2(aDla#W8$l2qOpq%zcBE$?uQU{0d0s8m=CkwT<9rX zsq{y3lMg2tp-}H!gdEVnJi>qZ^^-&0j52CP^T`N_NemRr8vss|>HpNc0JcC$zo3+e z)2=^HQl&K)ne7rT3aatu1V8_L{l=KFI*O1Z8~yRg&Y__+l!2pBkpxmz)oiuJUu*Q= z3QI5}lBG($Itt8e$06ugbptXAw zNQ~y3RuQv+S8un?jUq%CzI=So8^#JSdhaN(p31ABTW(gOK-YbZNS@G&VdcDP zdxyPxzza)YnJhz%3;5p);66`@jE5lQ!<=V(8)pR2AC1m*A)og&k=5y5FsJo&+)x?* z`oMX5f$ryAR582=dx7gB;#u#4+Bskd02m7OW)$`2ipsD5!|$KIEfHb?Q$i`AL_=kW zl+=8Go|We`Mk4Ry8*thtqu#rI&;_d27m~-yMdp6cE_`{Xr`05yVbYP zD|)~Qg@BQ!0_Rrw|7%|Ws0FDTDv%HYL8OT~5wU2A*8Aw*4aU--0sht7?J_`JlA42x z4s5@OYry}%MghR0)m~eP$F1#nFrC2_gpRyEx{pF&RRkzbV~g8RM|x5_KO`xW)hxQs z3q*`DIewd&ii?Is&xx0!6bAJd$*y;#DwXVPIA2-;wgG1JgdcnW z3&`5RT|o+?1blu^fBf+7STzJ^Zu9A@o!7gdL$Hd70>a>M9fVv~$MH$COqj1`c@R?b zzf@xgj?jp^H?cM;C}QHKRe1A`P(;g9Z_-2m*W%Et{&X9du4(a<#KlONOQ&T76|c7s zOh-m2;=LOaA2ISssgbg(68{^$?9eLfe`OK<;s)HsE=B;ncLK&3BNc_)KEjh%yGKE^ z7>%54j`;a~zviH3Bd3G;zv-{k#+srO2==VxWlQHF@*>}d(uelYqStpQNxAnR; zKr)&+rxT9}@bk|{6A6XFh)RmzfAe}T!2HNWRaIy)FfSu~2;=tE@#$*-Sg;a}iXw)X zgd)|!3Dz7Q+*%hJRpG}kw|1*oI|L=pSSIqJOx)Btv+Y#?@X;TyL<%FsnkGP{31YAi z1yQj#!}G19%8Ei{Y_q@qa${_W5maYTr(TR|Y_%H!n84cYV6`M%DfHh2gbOGIP5W+N zGBB0`6LC`b-GFc3mamVZ6=N$8HeC51e|GoI1PDQ4G*gkp?3a4mNDG5NG-dCU(3<+M zmYYj2+CERT^=)6%=#CG6QA9GwYg=~ZJoK5rc#rWfh_pyE(7;HGpccNWqPTI1(O1vj z9?JT+Zw_}V32tPBlazH!b#-=XKbb3c{ZMF4uC$S5?CrdbW+)TImyKqBR_E_2{kI~a z8J247*qTO6Hs~+`r5 z9P^+DgQOlgbw<9H{O^#xHb#>@8|hZ?3eAvCiuE;FUC_|#+M$^IF=|WT1s`)DBucdy zOGg%>UNu4wIC{s)|MfqCYORl%u>`aqT>6h*+7_tw;=s&W`) zYd^d@09;!4qoCFKP=gSnpgY!SdldkDqyTR&-AaJoJ0sxn^kpfdb*NXyTkE3{P#`w6 z|61p%ITJ$4R)ZD#zwSp-6d^>Y3xe-n*{hu+E!NE9#K$im+_*7zTb&?uuH=s7n*C<^BNZl>RYq&f3-u65#2Rsu#=oqc01w zRGMbd*B@gKyC9XJ53N?T_#$Va66L)aAG#=^nGNtV$AFH0#&#Iya{jeagbK1{AvdsN zJAm8le(rpiRmLROzgk$!%4Z4%K+?cbfiv}$uKoJkw=WM6WMmYhI2~D}%ylFTp#1U6 z!a~iTxsCU`6&Ap~4gBQctpb%V{LEypl&7z) z0?I&juFf=I1@o_W3{daa^*T=q;Y5>YH35T(V5GJ=!tKp57z3q(f4659L4m5&QXlO= zsRz!L?-9M~0YJS1Yx7B39zT(6QSf?en-BwD?JAE(i`!5ui zdEb;|+oWnDa0Er) zIElhqI6S_0TjR`$80F3O?ld46M4e@t-d)A%>ibAsg9?CxqBO0GthG9eQH*%Ijafh> z9c<+6;k{u}e`V`)-6nRYCfO4GrN>FgP6ENCB&NVO&$o^Oj2H>mJ%93OW4(YFv@VN_ zsPf~EmW5_LXM^>p6Z%-%F-%x6r$q?1cQ|{ob+}vkCvWyytf!t|X_z(wE?ig}z4Ka; zziR_n2*QA-8K6s@&H-^q&tEBrP?*S9F749H_9@X`sv7 z$LEoHi}m}(jiz~BW!_E>>~w)NvjSM~CYvNhTT*K;-fwwNQa@&54Q+{p+W7WA{o(r; zJ2B{l>Z(|&szqC<_KW47U-P}f^WPbK|2;Di7aL2MQPp+pQNX6hPadyrju5M(2$&oH z+h4Y#1HG0piNGx;N%nV;)p4zkoL-y$8)FpW!EIUdD4ZIxcUbKnrjF9CX|N_0!C0e% zt9@Mk3IG)lg(+hy1e(AS@zUYRi@hiX07ZO!?}lGZCPRM`X-7qa@CBT;eI>zugR&;NAb20%hpV>F1q-90?S z`d2UZ_M=C!o;b^_DG$^{e-fR`gAQ75kAvg29BXDAmTRH3Pjz6|TJ!$fuy1J0blSKv z&-ERX*uG{N@yiU>KZKtEaDM-uUe7L(RkXU2RPPhjJ;7NNkx7X!RveNAqdmKi~6vP9B0Zd9E6d&K+>asg7ctK$*}003av@VI|tT^RwX;Ge%e zq9Qg{-Ass+QD~G}`fn8gT!I~hEu^biKmnKrZ12wuUP-m`i^ppWt$52BT9H=A6$Ae4 zqsm30LEG=e0&n;5?aS>-M$sq?kM3;z=%F}+CkrRE0GLz62#8+D(sS;_*fQDv(`@JS ziM>Al9lngL#d#P_wD4;;_htRb)|7s|ijCzjln{ZbSff`ybT7)&s5Rj>^W{Y=%fnpE zhu{JzpKCbw*+f`atCu;Y_Mzi!XP$)S?VkWrKQgHOA%Oe$p6zE~YSi5-nGl%tdmb>z z&<~hqncjcjIgYv9C+3Jlxh~LLk|1{faMVlfV7V%fmP#d@}M|DE4(B!2JR* zb%95qQRsl8)*&?@Do{lHho9b`2)$|$E#2t%U+>Oh@)hoEo*F{qF+0oZxLygvEC3L| z8SZT0_QqHl37tlL_PUB~kl5%^$#n?_uY3id;be3ch>RK&+mH) zgazok{n_)kh=7S0l8?|C_mkCey&?e%QE4N=z0HY7j7A+zp1$5HlLBaK{&Rj7;VJ;Q zV4#<%0*HjDH=|QcO3QC|aTvs?PEasBx&udmaoMi0ngG`b{Vzz?#2D16nL%72Oi%%P zGyM7K>lxKK^$3seZalh;Wcy`CQ3ny$ivP_Ta1nt17({Xg*Pc@p?gweV?!O62WG-1{ zSvu!PCgy;drIch0m8jpR{>}gT%hbFUqZmpr$u!7N%jgQUktx?qc{Aflw`>Z`k#IEQ zQUjfHaFvmOb#&lzy9_&Gq)L}Fk!Tqs@x4DXxI#}u(fxga8SPBwC{i6%g!e^^!^b-{ak7{ z5=0uA6x$6}xrop1;L)x1kys4D-1zHfZ*~q51*V`%q>xnC85$ysy;jF{U0B+&ttu9S z7d*P-HVS~zpi^^i_E1KMI+_892B?cMUW4WT>US|GF&A;cprXl{H3Bc*9#y8!xiC9= zboXWfI9>Jd{9pqDjz%LhQ|Ch@oCKgGzWVm9jMgJX5jG0`^s~uCA<(2~B7rneFiWpOu&rDl5$YgFFiF5V2n1?u|*I7GtCvz1%u< zW5ibFLe&WG+%*^>SDyk@7jD6XS_ldbOT2owZ=z1AR(^JW!`B~mHK~6PN9O5RLxB(~ z5its!1|SGtY{fS_hasX+Ejazj<6C#uASE=3e6;qn5G1C1(wDmE0N}&zlndK}=k4xm z3t$m5Q&j*}RRK^{(PA21RjmL0@1DMzYEi6>1OiKb2rA;l1V(XGF9LxjkkN?wG+K(y zRMnn>XRgrS<^F5`)E52AVkQ2(2^fpyLDBXHxAts``Nwx6xO`9K`kq|*A98c>c|RtX zJ=S^h&-`vuSBGj!Tg%aJf1T)HdM@2BKr(Oc>Bvj=FFHHnZn$P&w;@EXG}>8GCQ;GG zuGlG@kPbD0ouI+MNb%cY?Z5u|$pMOKbcAcNo0_x^%`C=v`n70bZvL41!27Iq@3|NX zp{$LFEy*u6hA^{G7GtNxtqFed*}aifF;ph{>fQdcH^CfAgLqWIoO4YDpeqWkQingB zlmiJ5Jifazk|+!m_jdbWTA_?!-F@RMHUIQI=~e;2CqR0}Y_5ep0LOQONY~m9&1zZM@RR1?5jGaUT`e>cIpP~p*=WR^H z8uC=D`xj$yFlYGeHXhwtFC>yIq2ImO+C2gtf`L#`XJ)-3(h4~IU=9OCU;%e;V#C8D zl9)xjdPh1$w86Lvz!+Cfz?UM?OH!L9r!>6Y-WNXtP2%+Ny&EpA0!9&Ch4MelxZW2< zG*YD^0`cs1xigCat`M%d`18+ijDSKgDiYhDjd^%l6lxd14;=u!zslZOclSY)KuQgI z??ohpP?~N9{NMlM4^!Phu`X^b;s7nHSm)c&$!c}1sSf$&G>Kj}Kn;D^_36%g1LyNx znoeRg(S`KU{~+(HBJ*f$9^bcokM``yLUTV_e&Y0}kY_kQ!o=W5IC+lqwD&V>De3xm zPkKxF<6agM_P!o+ia2apX)Gz)7&ve69Y!Est8vO8Qu{Un*{IIr%ydm9YDpkP6cY5L z6DQ(GnmWHA5QAfEakH36%TK(k5JJfT=DG9ws}xs ztfyznmtFObe8npO_2h1rT>!-HA>Qpz4H7~*DRBR`M=j-#k;fh+E2O^}xq=rP2bC=QAGFRzqo)CGS7(=m6 z^wa#5CjRP+wGTUekFo2SvmTpMbP*hzS6-ThIKzr{MMN|&vD#%ofb?3HA^8B#3SS&3+X5gQ!~q70DNIWBNv86g zFwk@~s&w?H=lg$pW^`j!HM0-`vX;krVSw|Y`3nyTE+UFx9UIovtEMYS9Z6X5ij5Jz zxPRNj0tLnT%dMT)@1O-D5J^>s1wdhi9Ikzy5D+o4C?r<+?EZMH21Y`5r`7%p(B5_| z>aO~zxbi&!6c|kev?v4wuiur^Km!DJ_vXgh2r5Y+OlY5JZH)!6BZ# zd|gH{9f|t8H`l*-0I5(2EHYT2B!zF$CS0tkpoE-jzFfH7{qY;;G5Q`0BZ@pbn7-Na z1on=q|Mr`&kNnL@R}^C@CUj#n1rvTp3aT_S0?U(^op`^rDfz{O{vIl-r}dzQAngTn z)IQJqZ{7tLT|awcS(fh@ipZzml2-ct@3|5zCwg_8K9{zF^oLe2QU!*#UphCoTP>j6 zaA5x5#jo$R8Kek9DFxL*O(i;rz?&#V87=)zU>r}1Srret{y%>6&B0NXQkCtLPaMBv zaQ|5`{rM`8AM&Y7levLi&B^t-#>r5e~1v_oNqn_ zGv{Vm)d7AGA%JwgZ<`a`+88U%hyeHObx5O2At386fGhrauR{~C!BmA5gP7pm-Vw!% z$jIrP8*7g64m60Yx&VFv0YFOKlLLbY=Zio@#gmu&hXHgxma~G@FMf2>8P-P#m8pvN z-nrI9GoRn*bpCsfL|QVXIZfv2q@78+n-gIsv|fia0Y+mq#u%f~wBYFGPF(-})4e}@ zzdeWL#OPFM)-d~Pox`@hw(a7TY>%`4|pFkNFnA9Z2Ku5QskI>8nQ z26_D~wLkni&-yP>lwa^GXLX;w2vl=L&&v=4%*(>^jCU11$e?Tky?eHAJHba3B1&OoV9IbO zhmU-zIac^)Zh?|huS@givB2y7dk@kDoAo;VHwG(wk$Rj2wz&o=@mF7NPMk4TZZz3B ztiFGJM4zZf{JyQdKGb<(qdAFhCrPR1w&fmx{Xb zO~4^eM`K?GQZ*`GZ)5MUR97I<(H`CLV+BHV8qFxGt08{9(SNk)y($Q^dhJ)CNLfW4 z;q4Sp-W?uFL6wQje)0I`?J)`>1~?~18fjK{wX(tBnhF5&0lR>g=Uf-=nyKx@mo6_c!_@R0OrkF$iNV8xm4$bQvm9=e-Y+K__pk@%DJ*|NTFnPTftD0_s#%5WGfO zr8RwDEO~F&n$f*<izxaT9#pZ@#-!~pC!ANRiBy-%~n4F>bogKYQ>226ha2JW}hFwx|oy;xKL zib9i-27qMI(ZtVEPpG!(g@WM3lp@r$JUKB3V>E?&sDnB`3X~vz>ev6D|M>fZ&D)2e z5NfazY9uWHQG^ZaEiMdVh;wMGyWBZE^)qz68K zxaL45Vnwoey^TsyDNIyIz4{5|D<1$jr&U#|iUAd{wKt{u5TXMg-Mv)^#7tmjp}zsF zj_Y}-Y6vmL=$v{7i)KcM`ib8!@%z7Q&FCrKVz{&6zr61~p=|X%xul{{LnVH|g@^Om zwfuX>m*!8Y!Pl0y>$GOwL@xlwkrOE)AO6(@OXP+QkI%+TLPAbQe61`m0JG~P0kE6=@;~(We!m>)yvPfPSc|#%1x{v1^gM&kAdm@9P+)0pc3dz_j?C{1H~iwOB47ij?sYgBLuwbIZ}3 z`e5>IZ)%EJ1$4S|D;1zm`n*&;BNNNNG`!v2H&F;Z!sB}*uc?XO83b}kl2WVV!=+1; z3XQ@Eg=R^%S4kWOyxz5gS)hnoED*nZba!ohnR5}x?2dBEaANR<5QU+L;!=kLJ?LRh zsIjV?cjiX#rt!PC2X9OL{gdZYb=Gv&W>aTqx!PFy_S8Jlr#KG*88eTtIhUncP$f$- z&R?Ogv^Yfh$Fy}yU)6gV_x%UYp}#Ef{rKB^)(3HV`-O%79cXmU56EFN388gca8I!+ z?`ctytRY?eWJX=iv2N_+enV?B372tTdX|L%YM@m+;dJ)$3B5>JBFaZsa3jXUC?{;kRWP7$xA6x-d=_LR;;5z3j=^3#B11fXIfo2{) zWSP_+qgpeOpMg~>P7?KB2*|qc;8ez29|*ag8?asj)P8|+l=PD5=cgns)Q6o5Tsg1# zgRJdDI@b%xa0CK96M&|br8Bpd%qg3h1I9oRsOxxXV}`5`fvvnxzCaK@VB^&;{^^g; z4=@2nUVI1@1QF2?E%|5m?u?w$IpoA2Eo=_vW$MFIz!CRv;oi1{i-5$J8(}k-h;7^YB1SU?s5p;OI zH7&(QqcGmPwKkH*C6Toc;wpT<{t>(i&7x7X=6zBS72my@y*so3=Tz66{p_>x!~xMR z=M+A1zdVQUCP|@)LD}LOM|xW7dSj&R&FuTF=}uVt-FI6vw?3n@uKvv){ObHoF{lZ& ze^7f`>4|aFwgPu+ZkHAv%?`xZ9$6ZMqd?xfym|{?fV? zxMw1Unh4}8j)TAR_rH1mb|$6iY&P|NTm{Q)&H)gqCkTu0&uKz}bGZC|@?b!~iNcQX zvoF>Qsl3x*Qpx1c-_K@AT0}GnNQ-FJ3$!|}>5&TKCZZY%Cg3e(%Q32_(Xcd~##Bh3x+ej2sr01&lP%2&;2-AORgcd$U)%8&BTM z4s9*!1mbgL&nD&B&t)!7TKANHn%-X-IR0vf?+2;VF4@+%6sWJPnKHUA1ZT`ZbH6=! zAOI)))54s|wQThjLy5sQ>m_843=pT-ocLQCaLvreeut||7M#mOF5XsU z8B=I!-9Qi(L1@}^H>VH)R5#k*E5Cnzc*Kn-uMeYcRHZ0pMU3 zIv?l$&yR{FVa!0}C+kOV%L_KV}l27`gu4ea{gPIrinA`n{V?53F3TL`ot zgf}!KwrDjRl!cCk1?ZCkFkq}J0Cg4aqO$duKH{ZQ@d{M< z$!FuS21TT}3dNH*dwUh42%)vBKuRF4j_aMZfGAwD)gw({4!F62&9P$)CT?cBwF^2J zu7j`a)tAL22n50F?LGLBhrlcy}alu13ev2=_{iT+Icb8F)2Hz$P{8O6Wc+N*%;p$U8C1Aq`sJq|0p-94&|DsWbP{$N84 zu2~y3t(79g$_L<@PvB@I;T2}6h!XhA^Q}_GMmScV-QD=&o}Z{OmSzUUhYR8BE#uS~ z&4qjIDL3Hx^nWe;Q%@6}*uhf@2ai{cOKi{627Ndz(!Hc$O z$hwPHwFcrq-pkvi>ibIk8M2v^NvV-a!cHmG*3133zojbkS^q&oH_3ae>Kq=$vJA8= zz=EhXkA#q(^7-*Z^V6SwO8O7?ypWrzie(|mvIbyT9u3Zy25HyQHRn5y0{6GBR)ze)ZMu=Ld zs*x+aD2!%iW~7)QMoWJ;nIX>ma}BzU7ut&FPQweoK7NVo`FDI+E|3`Ey|-#s0QWZW z`JHuEM-Z*t~i>xw;*Z62{YqX`qr3q%ZcWYh3R6tSxZhv+ZQgnUg zhl5`62PVGI((rZ{GZW{$GTxZ@jS(`B2BPLUNVA@=j%yqOI8|?{1n%(UW!Ntf#g7Vg zHv93zwJ~7j%&9u(qJ1Pv*oRmtmeKu>e?0*+E1WU}6{7_ciGKX;>;0*_@!i|Qy$bLn z1D$iQ*dPz)8N$}eS27jOjMCF>;Qc&3bG~vWh~5w+$W}^JGR{LLyWZ3LpA&(>BAFKq z$^z2)7}N{CN)vl@U6sRAmM5Ffc3#uofD4oNIm-#2?N`wCuP->;VUT|ZSSTaJj29%i zrf2{CbYrslktEfBZF2wGF?_I~LneRQ1LNVY0Mbm8T(hWwt0P~KX0TX{cWm=-{^e;L ztyfS{Da&b$QR?tPL8S>!A`_l+wOOG2dno~*IE~TP#v@d-3Gl^(jm?Rwn7HvlB~MBCv| z;P%GYEy4m^`FLOZ*((r7MHwPIc8>7$_0BAM5wCIj<3~4dP2d?-okgg_=~Y4Avkvh7 ziHSkK(V0O1;9Fw!qGIM%j6^Ycdl;YXh1XMk^7i1+9Gx>p)fO%{xy&B^?lBzZbM09p zW2blCd4Y9(0zI$a{DL`9ln%-dAw?2L}y&kn{L|Um`nZd4~72fuHR%3zNm{}&L4oee5d4ft^RbV6>=q06qO;>ZBVJu zu74(*3w_5u2UUs!COY*Szy9{^vmHBPA%#%NB#l8+&}LL>z)4x5Dn&B zba?Xe@UWz)SK7u%e)8EEl{rwwMMIs<`CtR$9NhioxwjgQ976}1SNmD;bwj?e5CpJj z6n7Ne*DtpBxb~M<`@5CUk6E+(sZKLUG!QLGk|RCFg7lDF##)x1i)sscvc|{W^;@m< z`L2isS^q^hQ|7{tUi302x0JV0ez*!in@?Ju7n0GJb5tZwY8B`aexw(gW`xfr0Ij$%Isn6nH6B-g^~H`r)%*IF}yo&z_!k7IDbPxd(a$KQT8)%BSH4p4*` zNfGfDdrY1Id+?0w)fs|^PYfXlQB-B{PQ@xEKD+NWM&dv~_ov~TXGbMK?~SmPjnFku zAm&O>A{_&e2zY#Nt&pfhXdnh9nDzUn?Hr^P6mSn_h^lu^* zC~{uV>bSOt0XmkgeZ1PEk^^WAEzbl+_qM7IX&%(3>14toPT|C!3h6kW14NqPk%uESUt2RgY?5?@pMU2#7SO^5yZr0a#b-uQB_Muu6!3iOu++_OU+?c#LMhDP zMZJiMm>K(uncCy?bQVPo_dpcA)O&|TGMCeV@(KEo=ooQ#nd3a5i8}gV2!nhrj?Edr z4};|#$n=w(AGES@j=#I?{HWXgNg-S_c9?tD&HWZT)37CSqB3XZH5hwYk8iG%+jIL8 z@}>U=OTQ1U@v zBc&B~>=UCivP7OwU6l9z_zk$1jiY}RU4cJl7|=zevY`Jnj|#N!D%cFv#i3>&rq9(J zWd6CJi`Ft{fJHZ(n#}@36bAv6>cp!X$I<4m|NQ*>m!)x?>Z@2%q9K@->Im?Z6@Y=@ z&%y=g^sT_>ur|M-_1XjsAyS0uLX1u@R{Zp{J7Z;42Gh~IgYwNT2w03*9oIa8Xn-Z~ zn9{~AX_FCmZ+RysLPGYB%A?sT0JzxOFE9an?S@IaQ`47}BwU>6JVL?Newa~33l$kV ztdB8Lh@p-GgcNHoB&+oQ6`PI%6E>Fh+MLT1x`F`Ai0@zTPNSN^fj39;ePadLm>ay3YoI4`5YC;WtXwXC43j8-Fsm;fp3kVFw_Yy+soJ);i&N(Mwg)i=5!^0~fGBtevX1657 zJ9evFeg~4yK)vp+>;kSbI*c3A#qUa z?_9E;flC$u08!1vlyD7*ua`GcgcOTt0KJMSp1$7ZXrl~J;KALEiNcO-%>x8QqL5+& zQ?`rw>bOGjI88085q-l=(5li4gisMnEo-q7m6^k{U3+^}!LPwEhW*E%-*pv=W;2c! zy%So%g{nF)D{as7VvkkUtL3-brKgeJ*7S9~?~*Xq1uh9Dk%$0cfI&Yn$ zZ3@;vdCS!{6DzM{=p`%Dx|z6-oEm4bR_|PEBaeo-!eN58180kLlio8!znYAfI7_fp z({pgnXV#B@`mKI{(_Gu2a2*(R4V8rkeY*L;ZuO?>H<|E7s-LwWzO&!X^hp~L+r|L6 z`|QmNnhRzzun8l~Db%VFDn}EyK6SVL%O9VAdx-s+j*GSG@Th>8DYOU-R7;iss;ZDg zeosVNww}hKgsWY0iPkH3-V*=-Y0bIVG~k%*$zZ{}Xn`P$HuD8w2121`P+}yI8UEdm z?u;dXWd&>XV9wwSX)nBN2vjfUaxS3uf-odTvN&m>QZ!5} z?9W0O;Z(ig?yZReUJ)zHQiAnUS&i>2oS*C2Y?5G66f~+d2oq3sfvA9QpTD7ws!)x* z+`qL^0BgP-=xrdF%0VA|I-UYM_VV4wvk?|$zGaYzV}^pQPjX7Y!Yqnv6%2mO{KlWZ ze_hJh;A>40)XP`{cRH~`wD3I>@kGW+$QjIeqEtGbG(?6Kjea;WRP5-t z4SdSX?gtJGR)NID=H{0jS&#V1&cw1{^2li>XKv%rI$+P4^$vzyEB=FgNH=wWf$~)* zhFfogKxVH|2NhaZ$-0JtJnG11SvFr%R?-AfQldm$rK32x`*;8Povg1_^v-#Uu_#7W zjI8lGNz$yzI3#q=uEZy8hGMCU@LY0_i*D-Dbjim}Jm#N(3XBvtCb+#Z@e|I!1~TI2?R!B?;wOg5Ke6Dxw(NDDNflaj|fGmbx46# zZSLyfex;~&m9vEYDWGaF5@Kemi4W$Wc=4*5m86+iC^UTe*<>#HbdPl~~IE8I4TI2s-g0L=%&u@WlUCg7U3L0S)f=z`IVl&=a91BXF|8iCw;-6dY$Td4Cf*(11NSHsC`kO z{6ll@KUNg_Y2f=u?;_x$0QywVYaZV(i~&-G3QG)qb&h+69LJ|iHvE3=`-0_vUAyQz z6AW#y)+hoAMd=j|N-8KyC?txI9RJ~~7vH=NM{XR&k%-aiXoU_GM$n{@&`$Cw-6}*H z7^PV#PNN69DCL0<+TeSd{Y9uk#||FUEN}tF9zXx`wvUx3LGB&Qp1%P+Dic6d)nEp* z#;HLFCA15UR{8&{2>+WHym8vAIb8}PRb*pQtd9#P2C%H+{(dkjJ0Hx%M`$Z!8DosN zgahJo1ptEVmeqxPW>$zwLPbazL5H{72cjc|s#P~P$Atp4^t9N{aL5qMtd6S^01!e| zYMc8{DqSY1%&3lph?k>ykbWO; zuK&|a%o?xMe?|u0sBLyL+wyz90n+)TVxd4vzY~BN%c4%H)+#7m#yq}6fcQfL=w;yb zJ@NE19Q>)9fO+0u;qmu**&V1+Lc{4tW`La;Qw+M;`@^z7=Cv=}*<$+6Mj(HD7(C5f zHK?0$+6dsPh)X30O$jxHs3-vha}_54^js@_p( zuxJnkQiRpzeA|1qI<8W}Q6NIejOABYSD`|TeseuHI+-yL_g7}>b(|ag;$68x9{IZ9b40ynD&2# zD3L@>8a{Ckd}JMmHS%fHcxr}2MuTo?3@Lg*j{f^P=!;x_Yo-=@qU^1$uR^t@BrL_7 z3K^VrFF{gy%g-+3^FhvYYU6*>tp76He-^-fw(~5v^vpYI^N8CX6-r;uUuxQKlSJ=- zQf>UU(y7fjtPS>B$ACrMW?irFAjBP31BPm$xe`|%3Ag{wc?;CDPoWN~P=ip#YHFWA zl6Ozt>uD(NHW)QKCL?o#!Z#Cw)bXn+2Rsm>wr`hx#X1qfY z(R!|eCfGT|;S8V?>h}AVUr-?|65RYlZ_pf&% zy{KoLJ-oNMIfg`xy`#m982?`R!*fRn{Y`P8b91t&|FSJMZ8$_y=PHATBUOMo zwI4JZDY;)*W9-FF6CFeE*m>ltCked|Mf%UeDL)6a{W$3Vbc68YC0alJEjqp;(d$uJ z9xMqLgi_tuOQCNz8hf2)gEp1EdX@IobqD4cT|r-#nS>cm`*z?Z!xE%|>a^G%4+Fo}F<2kFRHDKV4A#{FtLOi=}#9A~9B@ zkvL#;gvWPp6#@gJy612A_DfI^BBPmeDk9Mao6Ctt)vM!@A`VGv7eb(QeKU%Qb7pXm zk>JJ{8)K(}XgDgdcU0%8n`BsK^z_80K{19;+P-+ueNRHC}=TOp<4O#FK>84 zVx*Z<-(E)gEnn}y)toQ=fBb?lMET3CzCenZM3X>?L=;d#iSQI}s-|Kstxk+EBG4V# z7gdL9nyQ+Zf0$!QQHli^NTc7yJ|ZDGDi;dJ9D6Q+i`>Dg$bXSAZihdJAZn% z_xqqw^idE82M`jK`%U$765a?C_~Y7)N+#W^2iOj1WbdQ^-R zw4i>pU)i&_76_v_bu>!jg3^$qz`PH8wS`}$^na=Zr6*_Yx9Z4PAcQlFfQNT(3QfdO zCa>OBsic^;H=tqO=IBLM0l=v zKvuE%H8@ff-r!|QY6(!PYg*-?&;o}Qp1#?x;Ee{W9^b#URsaMZs zXqW78a>my$3Iiks0A^yX(3P<6oK}ihlJltvyA)VNl+lqN{lo8`9AQ$?ryal6{z=PK zQ`)aJ{+p;t+S`^TIWzPxEpfTU91Y5$HnGD%$!LzU&s@tqH(Huc!JcAbb3OxoQbzw% z!q!D7mLFj3eY7j^vRR2Ox?nRfbk2fWPPkM%4z<^*!rUHsFxnHeZ$fGI42J7F);0#P zive;4t*nyPIdFGHxqgdt(h2P$Q4^&&r^V#3M5QEAP09%>Ouk_EZ*PvhR$*r9U%cI^2ny7Biv~;WPfWxF z>vZ6uD+18fs{l0mKlOfEPiLbsnNLL&z`dIju}W1DV`LI3C7#ZDt)jiucErI}jH zv96D)29RlCvN}{EQVXz9s#)d4i4hh6l97lah=xi=zk444@aiyPqVVdxkpfei!ihMl zKw%qx*210xclR5AqX*0jEE33#t=%gXq}e-K<0mOE`OnB|00v%A$jUF z^YlVW2MMw#_P>BiIukJ!`e^Wl4;EG66<w)ZPjZ-f)Oy)h{i+EA?kuRu`0q|K^GUWnl()nQs4$4*CUO&pq` zpcJJ{3U86YEC6nTub;hy8;d%x@xkr&^#YFYDydN~8USs&K{7S#iyIQBMwSSm__H*ELyB$3}g&OKe=&4{D1%Pce}QZVguqV#_`BEehO_7uJifIc+y$Q zKg&>dkiF9(=^7UEbY@BXB5z;mM))AqZ=J%LNDn~nywS>SY38#rD6nLm40*b-4b@Bm zho+xbk{p4Fw>KqBZM3weLusDbKCiKk}!M)1d#e z;hA9(APHGBGC(;CB~&61D1mNj#Xj)2|MI7x8xi9Q4o#6;}&J7&T8b6#Hq+T=3{o(NXN9!n% zo)dLf4V#YvvfkXB{olT(H?!)*^PFiwf6V7GfDC%>wK4z7H@*5InzM$|98o~M6N{Bu zq&V|yd!hJ;-+p%>zQU*sGzvtcC5B;M`DqD14R2`?MqkK#JQ2|Mr4de5WVnzBK{9@J zM{#Rh&k_X)5o-=#KD?u>oQi4j{hRHh2zWpwhL8c3rsrw}HLl0%MM;wsSv#T<_ipOg z8xc)(@2EN|(M{*PSkM~vKs?^&0xzVSr6V={Tz|&XdQIH5XF1%y-(Zd^SiUM!|U?vP~ zhj~)O*L-XF$Rpx38`d%6KXd&6)@}LC_Cq#3h=O3DA}cr?{w%>@79XH4WMDqMYsq4nqSc#fa84D z|1^r9r+GvdtJL|P*!O&B=EI%mKTO0E{rDB&xLSZCL+x!lswN?gghGrYMTi>{+?aSWm>|G!?*Rfc zI8_?!Vb$%Dayhflmy80G%s3kVv{vx3#%`&DiP+wqQ45Hu@Xn1jCv}f78>Ixv+Anwk zS{ke4(*@uugUqDfV>PW+5G;zKG(3N^Q${CRh{XrDZ{FSjDlkw$gF$JC%@h=YkjmC~ z_TomxLcEggXL3sPfBGy}^L?{cyQA)EGtdBwF}T7i?> zr_t*2b(-|n0N2a>aW7v50Lilm4Q+AIN`_g9?Y#qtPd=#k?{3!eF0~&L6#`nLqcFej zua2uT8Jn)GI`peG??Hh$Hw$?ArkVv%i)c{VPd^`P0Fr_QU^J5`j+ELHt4ovDjL#1@ zj_3C_Ipr@dO!hBZttdu`OduYnh+XyAOaZsHKCT_h#CMM&8+k{Uhc(T|Nfi9ql)lmBI2VlMl)lR zz+meq0BN0)E+!d&Oda3@4hMF9h9*fw%_v5i3RE<`zyV&MhA$r#BkuxHLHDNR&JiLR zqGk6QwP9f^3A#G2SP6hKh(Xa4vZ#MxxO;m|l?Ef+?%q+TpaNK`{dMxPa*6vwE~817 zG}22wZ@uIVCOE3FKMMv`np$=12E=NwlR;fl+K6Hmh+oy&$X1F=sBJu+%)iXx*_)li zk|Kp#{QTbLW&s9xC+bvH(mOQXP(@wGJ3gT?}TF zAfu;SM{laNKfE|N#c znX8pczo{`9FxGM?^%wowJjmU?FA7|CkC(+cmu-RUD%AbAXDx-YNl8lM2n_(#bfzuI zdYV21j!)xVU+-SBoIoj8$8Lp-zB81IT|DC0cz!Jn>xa%2Sq#8>X3fbcHKt#6A8PBK zp>-%e=;$4)6pFM=y=LaJ6_(9P98G-Dex$OjRGq4TQANj-_0oLlHvjh5-+jL?fd#ED zU_^t8Px2b+Pg`~ydF*Q1cl=$<+c|b&yfCWI()r%ql)g#?vz~0#7!5Qvtb07XwdNQ_ zlz#m6_uDd-$_8tF;+n3GtBC)59$w8pl<9r9`=eoV4P!M&GwQ)K<_@JAICxaPs9m zF5NKIx>-{Uh)K3U03b$l&dm&O_N(9u6BMW(-db~n6RJ^36__A`Y``CSH3VHv%PSWE zR0wbo7Od34IZ?()U}o4l#7>Fe#tN)S{HxDK6TmxA7-^9r;*_dUT=KY-1|HQI={z-n zW!-GY)~Oe$-Opbq{kPRPk|o<@TZ}i*+FTh4vs9*xWB|(82>ejKdir8d*1y{G&#U$5 z$01bCdl7*IVBU^N$t>g$=CD6X2e2*-F0VI-+ z3zUi0xA{>bT~>fxo=EywN>l1>(U~Z^bqmOn*EHtioc9P$YVPyrnL-6-$FkzU;7DDV z&Do4t3Y*8DUo*m@hNzK{+7FH<2qG0E0uVT%2OObM5rt`iZG(k2SCx6dp}i$05<#Oi zC)@Yalg>V40G8jq6W>Is zE;S_80wO8Zul?5cPSUCo)M^TD&81*H?*&P2DNG+h#k!`1#z}wj4?X@ayQHrF-^?67Sz$$W#t2K^2R{v z@{iI@PJm8*G(^Gn{xq0SpseoQ+|X>{M!);MpKe(lSMU&stG#Kw_ZAFh&bbJnz|&U; zK?+eH%cIBlZj1nrnDp#3=it1Pq~~PxVHXe%-9Jvd8L*T1Jk^Y8swC3<5vJZlb!A`_ zzk67{+L<27+Ba{HW_~lmv8k}tzz?Ebejj~mLC+1U!5p<9Z*;uw0EOI=MpD*3@2!T#oq|5Kp{+>Fz`|rAzs*( zlRh@(;L2A3u&Bl=fT%>E4A|X2O!^`YynSoM?799S09q+eNKLR)>>T3FyFH;g+DOA^ z4@b^j&hdP<4eWSXy+w@yDlMI(?v+47^%XIr|L*n9k&Rxw-QPQyrkA&Ugbi@%cI?cz zYnXx4T->aKAdA&G=QT`veURuhf10SH>p2+w=~gdAdMt<`GS;3S@%eCMA4-3K5HW9f zSfC=m5Dn*v=YDuLUwcr>C={dMMM89C&=^F?HI3^o7D|Cs)ET5w+9=96=qP9r)sfoT zm{P?Y;0YhaMG*=G^v1&IFp$PSXVkRp>0Bzd)x76)_E2P5JkxIl?s!3xJKv#4;uq!$ zwiFpOyZ71#1WV1ZF(=8@ICY@yT+U1kSo;t+F&@AW!a*7T+wZ^Lm66I=f<>!LBB(Sq zaaOk~oDI956~P~GpgtdWeJtMqfjAL-@p#R%EFdC&YxiL15T<}8?H>?`?KoM*0M{9u z;O=b|3#v-U-r-RhQWBbr;^50@41Fm96I=FF5^W*KXlB6PA%cmjQ(%2kjQz@L``QQL zR8=D*;ngWL0#Weo%Yz^V35nJHTaz1WY5D!wVfI4YHc#w%pAGN$G?=7}uC!i*5Q0Q7 zlVbd0`|#y%b;!xr&$i$Sh&H+ZJj>W}S+dT>=D%~uKI;Ys2I`!xn`sAnvYy4xF(4za z=e@!U(0{HkB**8)F9v{~HC-bo$rSegO72>)_)RZ)SI0OXcLPQMrAkflm#7j&Ow>dp zB!V@8ClQJaFg2>B0;**OPm+GI)<|=`vZ80 zTs5=F>pmJeh%-7xpne;@^!^0&^6yD&hqDZgM?wzE&w1ucI4l@*YV)?#KWBWX_Qwx(~#axy1NP^Vbm2o zx!wT)G4Z&uHU^`SRm9!_qJhw^kXSbk$>kKGzkC5e;{w1=!k+?|h$&vZJAf-lDDCde z4KJ%1cFiYPTJsGCPze<^V86tR?R^##MvlZjySF()(?|E|0~TJ$YmN^Ca`Hc^#-=5} zk`gEaaAflJtKB1aJn+7KDcZxN8eBId$Dfmao-VL#&zjo!Q)#F($~@%oXmsx<2fpexufYxla}W`O%Rkp zK^9;EIulebl)fsRRVoqA=!_aDrN~rerc#Oq_(&g2D`F-#l^B#!Q)pQ~)Jjt2&EEOE&WJxVIi|4Y^2{mq*eo6KhNR z_Sl1%0Rv)^4(HvlE+;CY^y{z7@jw3IdF94cgsN(C1STTYAPoy**rLA-vY#@Sar$+V z*&2cmNDx~59FsBdj~?CDSTZu|=*7GJ{TWQ4;h1vK3e_-z{zHW=#te>kMHSu~~HUZ33ER85Vu^0C`Ja`?3{*?$_<>eGB@d6K%31gabCOh6;0n7nv* zuv596Fn;pph{Y!1bJb2{8U4Z61No7<$FXMr=P&M82D+%A?eT3>`%PTYq&bmGA_5Cj zyj`2Yz-Vc%g;Xyh5x5vQ%2EWm9KLfIWW<8*hz00>STkT}GTM>#m!R#`HziP*iY43@ z0%H&aXhQ$V+|?ivs833SMrv$>$;1y~l9iIoA(cy_m6Iy~C**5;X5VM#^q|9XeWhcUohoG`cuHPiUd&IY>^S>b_g?q74#fA;>g?|jgR-DCqx z;6|hUX{n=|J7w`Vzxwl@u2oSbCf_fDCbU}W1~76Nz+G-${=T8YJjLka5`hS#V;n0U z-@P?$oG*ghzOu~1nr7C)?m=(#N? z&$30G<*(FojZKEQ)~yTBt-aay5w>Ug{nlZLQE3qMGA~;?I+EX;V-((j>C0nMB`GlRfHE9zHIUI%~kFWsiupl zz^RHrRg>sHI*srKF(fLss){;Qr`pPZW;UfsXR!N@W*UX_azL3NNw?b)aGH8f-Yr4mJqQAA9OcVX>sfAigT<%5jMz`}d6 zO02XHR9%{UW;R&C7OrOKXYS`KnVdTYE9CLZ?EG~;5a26k)50qw3&q&ui-)&8qKHHt zefwg&6wnDxoN9=Ku0(*YJ3=v2;{L4-k4Q37Uv2GC5v?1vQcJ{M#<6he0)PSE7mf3g z3HFXEs3++d?%e_-WR?EE{s&1|jNa>v*gnER#Yi{t&c)f|dt)V3Uun01R{^TTzHt*g+ zpE^A+ZNeGsQjD!1uy&xZ@2%Tnphh4FT}BfNNRmlHfxR}zX?)N)zbFS7sqb6{^i9n2zJ_B)q#}+jrf;!}0Xd`0&B_ z;PKk@;pFh1+qt9fZsXkz?5^>!uyR~DC(^imA%YR0str-sc})*4DC@s49+P8Yk~95P zIh9;#8rR*(WU8leZi>l#r$;ssC>`Cuc>(J>Kni!k+EH6D*d;mNa*)O9(5zO_5GrfW zvbIM*#nR)VuozUJetck~Z{AFQ_hf74H>H?Nr!&Mj_8vftVIfR^pTztzVoH~1nI4Zk zX{xTOFjCyRC1W*&O5FIM}IZpUMv3$c?*3qbgmiN=4zWgG?Ovx zY?w}jWf!>Mieg^RaapqYYyrk1C|nb4GB=_|PNMg!WFbpPO3WJ>Vo1ea{+IY|o$y!A`sj~u8a|O-CUf?8 zwd-)7+}}>FoGFykgld9Z(_~)@|2MU%M#hJE*KgYi&?o|Nfsj?!T`WD{?#x6l`3GAZ zB^z8(6zgvf;{W{9%Xd*r_~e8eDua@W7~|qv-FervtC8^qEk;pI%{DhCcyMDJ?3lLS*S|E zyFE|~LR5HbeWV7bUD{=JT-OL2Fp}zI7I9>Fy>n#Zy>lANFCW}SfRmJjhMB4RAmjNQ zyVQxoKJ#oJoVr6Uw;49V`+`aOGnz^9;@#1k1AB8|ulK9K0^*#wVkgm@E_mni3 z@;y$Kcs>_4?GuW4j3DVb-ax;bc8>Pbrj=!Jj-*EajWEA4(NCO4@gZ#5;p5`y=Nq%X z+AMFyorz6D6<+Pk{`h?NSKn;?%h%ig`t{B~fA#8Lzux-&)9GJch8J6L|6n$XyLV*k zukXiS+^Qars|_o)EG5E=X!3wylbUHC+}ZE*IdnOf#0G<=iuydh$Kwp|v;D=n>*s%{ zX^7y7F${Wy{$UKIa~61LowKEIsPpQ4i~)obdf@gt){_jK^LwQ| z-$JaNqUl!2$!njUOcT&>|JEjB0BGvo?e0SWaczR8mNDci065L8W~*reh!{{t92}J) zBF(y6H^zm+tQNjo4a94Fq*Ap3QSkKDw#k?TWBJ*G+XXQ4U^H#=(#G>(k@wj}&f#ct z)_rSP>u~M*1ud)K9AYR%-PZ2m_Mshw(ernQm5iVTp+a#gw3xx}4lT4q{JtZYWT8T* z+~4CWWWhsQQs`kd=3+I}o}noQ>Y|t@@UZjE?F+6Smkj~W z)1r|ei@gXk^k0tzBS5iW1z5zR8#w&&9rvT#vMC2H?Cov8dj8`1H&35EeZBSWu$rPM zF`luY+bC_kJCj$t)%S1qzJK-R#mnbgub<-R%}qV{{02Y2DYr*)WJeNa3L}jILt_Pd z%-dh4&~`fh&uKd@KGyPo`~Yk1f#+Y=3idCI0dn?T=F&yX)fwtBGYCj~!Fes6t;jD< zQE8n$bV&%Uol+1RZBRg5)KR6ACvOk_{A{Ox;@ox4W0uX+Pw)$t zB!WazL<{d}R23C?;PVG}6fs1jUwgT|ABbR3)n>_E9oINR2_r^|JDY_Q0tm$ZvkwN3r)tFZF7~D|iZ_ds z!ri-Fz>p|E+60Rbch#LCmg#3N{0<BR!li%5BJZ*=sN+u?q(KaM*`hr8cAfAQVc_N$}mA!yF2idYn@ zJWOMBq*F>Em6zRUuMWercl%FXJm21WK8kN2tsj1VV|J%F9NSc?O4zc1>IQ&T?3{Bb zUx3!Cc!2)ToxVLj@H_Dlzb_4J(REH3035~u{RGGS)Zn~vSgv?G_bG;s-OXjuI*6s{ zTzj1W(kJq@GfPB7Ng;hPF}UblrNys)|8#$*m7t8JpimS5%t9ItNegIRuIC&k00WJn z{H|VxhJk2^M(0492xxG`;|Jq$;Yfpy_NQ@s9~21qp=GI8$0v^fQUTTh>tjsDg^^U9 zg?KoHvG#&!s?IHYx(2?@qjq!Q`2ULMj7%b@l4peJCYAPT**(&Uxec!U$ zKwJP7s?_&|MytiQAq@wEM4VMq3d<@uKQhXVJ9qu&gJ)Y)`VI9H0i34&+*mu4x7^=O zsk71Vuak({xS;l}05G7R=p6cQWg*)JVnI)de8Br(iqf*&{}3%@H+t~j!CC)wF+&7P zg&&C%&)f`4-=p!AgAugkHSFBc6X`_QXu|_ywJB4w>xvR~@2-VMo4hry9H(3F-adW# zW@~>|xx%~?2QR@{V*gLqFr8pJ#!+EMo>M24I+%KMlig`}y|exH-D`&ZJ8SX5y4~{A z5f34Ok~)rs1_L3jC#--9>cWrH*i|0~@lU*eL-dc69@8nF<_YI{3k8D@FMUOz-s=~5 zgtgPKW5G4~d$gVR+A|A7?iben#lFxgx>t5FK--5vf>LM|OQ-NEVkAY}q>}YNzc~1Q zhli#*9vdZus47rK1VaQws7i%3k!hVbXeEf!%75CGaFFI$a()UQ0PlLq6+ozWuG#OjIVIf(O0I(2ZjLLAaJBN2iKGHV6u^zOu_6|QkH-B& zR+h9fnu*8DC|aYJ?1rLZrG<*Y17&4Yn8)jP`!qoeh1jjlb+2GFuh7mvWp!MQDPw9B zQ$kIYLcoM3h7|K<5GQF&h8Rs{Kj6jobQVAhBTj$vaAQPxNwW8#7{wIQwFF#5CjLZj z>)cNl>{6u7=Wge7UFi!0qcSR(Y&xkz6)=53N=m0DGJjf9V#HKDjYubxfa zEt53{6i{W12o+1`RGP$mi!G&%2QtrPZ9oQ^?%sMQ&p=57>(Ou&v$FCYEqU*7va|F_S6`S`|P-P?FD!8*$V79vVN+2#1f ze)#i~7qf%iJCpGFO}jNZjB%ez2h}J7C26q~wWbo_NoOP*4Gi>baT7G`oyb0WoAhlP zUI%Rc;jNaX@DLf5^xP-gUsnZSYr!F{VyPlXg@TbmEPBSVc*aSphr zz%SGmfM!7zAVggt#fez-5kI+qqXb7 zRnB=a6RU3DsB6zEkOm5^jw=!|r?W@Z&oIz}qZmyp;`KI4(_%Dou$yCdV+>`z53tsa z<)@xo$K?BYoO#pWby7niP+(n;U2}_Csc|HDG#+`g;Jlwz#?j3`J)J#&cNnCAIDx28 zV69hIs|=_;)saqmromL5dC;6jVW%%%i~1uc`LNxwo2(WZd!z0iV91Og0^iOIWbTRT zsR1ZbU2wiPH@&e{_4a zi9Gx6x$#$@KltUBkG{Bf^XAx1G>%ZMX)J7Zcg=r(XY=2E z`QYFG`0>Nd^>y!@cvq~I(I1xf`qe9xN4H1u(G6Yqm4qWiQ}JmXhG?ow3BXpGIlWC; zx(2i`lnWxCQ{LZGz69r2`&nLpSgiST!Xp>24^h+bDQ8YFgTO0Bf%F znQ3ih-N0GP&74Pv_O(Il_HLSjDoP#2@y$Oy-}&ZMImHC3WN=PH490pCq)(Pe(W!jj zPHw52#`_6So&eJqe&;NY{ezWy+Z8T(wSfvexP@D5eq3lYJE-D|Ew}=NgUo+kF4YEF zq5rFPIHyRNFW|;HBvvXA(P?Q%B_aX9snSeU?eZzZUakN@ASy2P4w6s@GfXQS%_@qh zlX2lTCbjoa@>W<4!7FsMNwvB4v@x+yTNmr(E+G*v5U;m(LyXGk5g*>aQ~0!^N<&(? zq-wA=D`{!PVE+CjoNodHBg9B!jieM%idc=h#XuMkL;_=+mf$}0?|${QNg+y6gEP|r zF=ygUrAhBg&$72qDel>__APsRg5|@+=YThz3z95sD(F6Prt7~N`QkAG>8Lj!ox=s-W9G@eEsZ|MW-@y&?3YK>3BM|7vH~dv)SDO z4@Plfhh~wgpuuS3D++1CC^dzx7QB0ZbEx-!E*JY~21aAUe&2=P(cUcRMs?GzI~eW# zwiz~BSgE|wr~CH;1JSuofPuI%!w=WQHCN&B6f%-w%QM#t4|fl9vn!6+f|(6o!7Eth5ED;K zk;zyp;AeeW0|2AAY%kQ?{=qkCy58Wouez4i*%Wpuo#D}gbF^!9(-6LWavzO1_z!#H>1Rq zROQ~uJoiskgPG&b2jI3%8SdzDPW&+jzYID6X%e0-@%(Bn8jzZr>Fo!B*8LXalG^P6 zZ!)+){N(=f)uFwLJrafkUZPhzv>`w8@e=}rCx}+5TKwH_FaPzcs|fAE?+HwRsY5%N z?^1pQg(`^e38uZMM3zb>#RL*^?$I3mwZjNbyFjylubPT z@#3N33%uZ(kfkHdct5r+7iHnz8ls73Ah@Lp@j;01p2%GAw zXv|WEcO{pUHDSCXu<-Q*8D1i+_nVG~n-L6lon*$q?PLt^N{^?Labg=>`U7k?2e_HB zPrb%4K{O3KoXP8ht3osT&S^jbThg?y)?WSY>-EQ9;i{#C${Ye=3NST?!4i|vdh|aB zd8*v{B1o6A(YtT(UmN8gqm%af_AgFjm3+?w@uPQV5*u|h$J5Kzx6jacma*7U`|?e} zU*0tUZs%b!!I6t0mEzv%f`owye0JHfalEf+^Ns|3{qk%O()u1b6_1}iH&G*FY#!b} z73;N|D)IK=X}t*0>AKnf(_bM0;050D zV)f36GKNz;OZ5N)N`$@KZ4Rot(rUM@A|_?kpne*w|Mbs)ScUtMHAts95^_M+RVjoN zx^GB^V+TFado{ok#qCoT?hOml!@G2Dv&3z7Ak=)@P?hO+9p`>{Xz ze>JPhjq;WQqk~zq`F7o0z`Y8v_WoS{?N8sm zH}{&cQkP1pDqsNBC5RfqDrluzRg@|wpH(so=`^%I`{=EAAI;sCt);8hzIk?awOqY5 zmvWVUFYsYz&_RNTKZ% zS9bY)4^Uv~3GN3e48vdAbTzsmE1?2hD&V00#st0YbJ@PGOH z-!^)7)sUhVOFKYYunIlg{wq-l@gtps{*(xf-Gp5xU)}039{Q zGO05cPT;`vt5t%Cs-^b+DJz12ne~*QyW>_x|I@9wD2EKs3)$CC6I)(FUC2Js^6cpWlR9FjPf}?A4;;4cLs+<+ZU*IJ#Dfj5 zv5Ef|h7X^XSC5GQjt%1XsXpG+QTT9R`Vyfkx5|Q@Z^ zoA186O75X@!THJT&wuisaP77fCc+$+EV`ShCY3eCs#z3`ZZSm%D1apMmH2ul>FtLn zC-YF%m4~nf|Mx5{Nr_evGUe^z?dX|4JdI6#tF}ARC&YeU^^C4LIQN zGQT}@+(C01;H0FOs@cg3^Iv`T^mpI1O}N)Ys7Q}WbkCuGKXf@*#?iA}5vMipYdfOb zqM|ReT)&!(V(jpY>rsAAfeQGu5AJD-s@gigeEj^Xg-z!3pjon0@#l^JeEW`|>h5MP z0&(0sQCK2rl*?7yBxLtQ5qX1ss#}`?5TsM`SqYrDTw$F&IYFP-;baCa7puGD_NL8~ zm5~KQv}=+&XuwyGv5G>iQ%a|`ynP?)prt?6y1BD*d7~}r@Z0+Y*s~3?xeazB^iC=V zp3A`QfYjARsN6oHTeF^Cg+X0cEV?A*HqEL1@;Vfs$d2qiaQ zqzI3Y;)z$+@csJiqK|&OH1@)Va0&{LG`5s^wpjuDYX2`;zkiv+|Et2Cvx6LroM?w6 z7jrQ)xFs`1d{nm|oO7Y+`SYjiHc2%z2R!}cqjyzWNaGq^lGAFHSrw{TXvF_;@$?@) z{p6qi@abodpCN?VJcPEgFLhXx(|I^?8=5dlW zg41b9+=k%43;D;`*hvl`#vT{+BK_5u59nV}__bNW>bEOX$Ac5h74QTNtHg`-hLl0q z(A^e;-A*{~j$2awcM-Z90R>KK%>1BjAZLE~{PiMhFODYrBfLAz~ zU;bT3($x0)`&vh2$o1XH7U2n&n2|pOAV$4Pi1q2ed}^OOG1FNxtLs_Ns@GB#X6l`o zVh8-il$;&vVjQ%GyME8kA4>yPb9lAQx17r`7 zX5&vxbGVd-@cjF?pr> z@a*g)@U&J-O{kdC9BGUp26H{Y!P`IFXWXRFo#BO-?04+Po0q!+ewx|81%f5ul3fo-d~cemKoF%!K1 z)&p1s5TU>S>@pF#`r^YTw?nV)j>>pDgBieLQW20TL4bL{*n!5{J@$J)#*g>DugY%Qrpi+{E7XAB5tiC%AME`xo-+lU|nTu#283+Uh zT(0otw@)?9;U*q`{6WV5Y-_)EuA?tGyAFpG`)XGc+NtlT?UdT&9hAj^`^~ zN@p2HVen+;W~przE-<$Ux`W9XSv7icDfplN%dcbgzzh`$b4x~pxR3#qY$E`69L-+5 zKkNEqQk(B=m9rjE>3HQ6e&GA z)9-s!NqBd*y#Etk%+q(*yKY7r=G46l7+p1bCJcrG{y3z4$a_)d0G;RZWOee)r5TDT z-9|nY2pXGaeW7JnTW^vB24j!n9?3^zfL*hp4nwLof_Jr!5#jlv~{-ard(cP#| zE|$wRAh4eHmQo6;d3~QG72uy<$olTMc{V5zI=z>;634yMIgvm{=i{fB5I`i0mHQnB z;M(~mqA5BB1|;IDNf|;|2~Ot-k~c;p@7OZ8HEGU%C}r87fU3qAMa0YvNRC82y);N2 zlU0JVxh`sWa+Pd)x=U5y9yapI>pdF%P9OlM~_|^wSY)Wh-tDVJ>I=$2u*xQ1Nz{j$O`)R`bPBM z2R9hwqyjB1J#d_p$P6160lVtQel7TW=Z`mqj=b7@V59b*)gm`WaCh@4S<$IW8{G*H zN?SjFShw%Y(}}i7>&w;3wE|T|PG?m>ti%*15JJz+?zgQAtGb$#fvCtCQP=f(o5T=A zYlFBmC8*RYm4fP4(`NMZc^xRERqFDkhi(k6G zjynCD>;@d4NbEVKk^Le=&J315*3)i4!3sd(6jsWNx(~(vfe$dz_#YRViKB4ADe+R9 zawtr&S0TvK=Gll)yzAPTB^5EqT4s+M`J11An`Y;xRg+?ts;ae0t-&A=>214)Z|TI4 z0360l-jdj_*w6Y9UV&M_{gau%3{2GTo?CQy_H_h82yGj=d!xFG{%_x*B4*Y%+gyOt znFJ;h$#K=Bb?Vya_Prd~-@6WgQq0WZ5ojD2t2Xz$=gNEYQU0YPRoo50+m|$FA%syr zA@4xh%rYxxIng>=;H&SRxde9)9^ZX%KFewoJ>-sC75`T_9**4Uk1t^!Ti5L1@cCDL zgkWYV!c7Q+N09aDS5Mc!{_N>5K3o0uFaEHCGE`u26HgX|nhSd*g$mIO{g*Bv=uA>s z@Nu&r@ZfVZ`UH(Z_864Vha%>N`gmb4ie1q^H&P4qD1Yv#u8mNNA^Oj)iBgU68ikfa ze9#w?4z07^i?<|dsZLWhkD>C}4Aq=6Q`U;0CN-p@J-l}s1f;lx zXO~NdErP#QH9tD1rmMgd;F;!@l_M?Zn8(eFeJR;CTpkBiVqYRmzi~=%lUI5fi^~Y< z8JRE}V`DJGF32&AeUYh>(FFyJBv9;l(F{gysMo*@oLOdBJrd=KIbEx~g@bdVY*5R8+|J`LBJSe?y zUCsjDeR!tcl4g)^o?Nt!nB}pMJ^Kbex4!|i!n@=37Bnelo}1}8EV*}zTJn_P)jD0R zUztM54?h7Iu#6dhaIwNVk`!^9DNbf!XQb&I3{&rpTh;*RkT3n}*#&B57D8xaq(}yq zt|FdXtPCWqM*G2A3PXm6WoFGr+5gQCg&U#&kNuq96xp+{YEJ`oOCmJ5K_aWQSHJuG zyFY%j`rBW9@!8XeFarrHsb-cb!a(LxdzVsV2id;qUj_<;gh+{D7+}F=0TP>4{O%h_ zZ!*@szK|xIDu?=@b}~%%EfXb-;r^y9&s0ISud%*{lKgA=go7{Op0SZRWR^VT4TP4| zqsGgJbAR^~r(6mWRh#4~_nXOkr;8v-7=a`t7?RAaK5N725{tFWm!=Xb0cl=W^R?-f zS4){)p;~(#Q9%L;r3ZQ?>HKs?64Z6_WgBBkm3Y-Y`{+S+ze*u3Ys3I2;lfM^eI1MQ zt_)$LL39j0=M{8v4ui_Jp4syWgLcpaNjAzU%cJ`rTHohLIhY~e*fI&jm%9d11v?AuJzMl*bMG)8_n#@ z{Uuk+@5x5yot(Axy_D?vg-Y?(xz5C3DFII}R#y#-NDh!GnX2{^-Uk;<{}XLtcgHJA z2;pv-@P1n3q!NKSxr(@IzSpfC`5s=&uDUOH{LD=%IK};J7HTP3Qhq0ydyBJx!AdcQ zrvqA`cLAW{@l!O>0jj5ab2*;@)(hiPxV>8PPrQI0>GX6+1DkGc?$%d(yRQr&gy2MD zDT+kafBgFSHAR2osvnr4tktZe0F?u-K^$cII4rRDie< zkvldG0eosuT8NWOZF(n4=Tpg`{(Po(V|x`ieItL^k#QdVkeloDzhu&Qcx*TTQ3uVE zyFmy#J%zMBT@~cn2{qpHm6uOv*skB5hpNHf~ z2ncnXysGD^UC$*gu=?Php7@o<6;hi|+1yiZ<4#TMUPH_`j+P^$f0PbPukcZ-R2|bL zn6xaqPrxqE?8z9G9eolXyfrofd%KcqL7@UV0?)ntQ485nVb4ntILFvs+RJIH z?A=HAm{0}8lqkV^tI4uz;`r02+8eTl$5?}Hy{5}-dk9ch1~#*pl97qJM)=~ptF@ed z`grwptrpJAC8(nBGH1_N7bi?Tbvt^d_7!UPrMw^}bwSEB(&j|Gzmy@LL@FB<{f!by z8S(6US0NcLN*1e#}-XeJPU_4L_A^p^7!P8wM(lQ2{iad@cfW#rncsEeiPcbCl< zkDr>Vsfa2Z0#iES6jHR)X(Ix?M*H>&-Z^E32uoe-$&*>M>4ZFx1Nci-gl#i#CVm%N>i{Us5>7e#H;88|K@q0ZqNgz= z;~I-gKl$5Vd~z8>i^@QUnYSW{mb`NTfcMrV`2z4jy8F_~o?8k5uRBl3WC@3lBq};; z;;nn9K>*SueEr?C)OQM0)hrivNMJ4I(xaqRtW&b&M*9{L&7n12NQa`;IZZ>g8 z0zUql#)Qk&I(4Ksdw501%upP_GxSoR-45z-LmQJhoZ33SetP+IW#29F@#jxk)X`LB zCZZG?ESXW&ln_@~$g+H-KO7+8#B^gqcKrX@^n1v*}44#!-& z@iWKX#cRaQ9vKL}>d=sTl14;>JLpl_RZj(eI+J%#c`hqK>XaIlmIHJqVH6n2q#=b_ z40Y15YFmJn%si@~1}lder8Rd3txl+Oh*otiRRs;Em9a9+;dP(}Sdc`t1{2j3+qw$T zy$U?R)d%;&Nk!%0Se)o78_8xU$o5dbQIz)b;TreX=3hV~=-T4&_8{4isonUTqU1m1 z$sDYFQAz-9rRdUoarBh&!S1)1I1>}^&X;4m#h0!36jY};DCRU1HL4Kwj@+RTGBjSL z`rdCodGeb-K8*;idz%_nI4xQ9t{KH1^yz#()$JGd5`Iz6z~;&`_#hgQdmdtV=fOM( zvb@v9a{ct8|MK3M-t^5_-!pdZj@xv&Th@BYe!%xmYsoz?$g|63>L=!%55N%>5=C@3 zgk*>@n+%#Dot>a>p*R3f-V2%B&6(RXPvB1Lx?x^e$P(5IP2^Ge^uk(%2ngDFu*Dpz zu!Kt0qscBk<=3sTyUjH{dIa)Xd{PhjaPM$Vq)X4HHPTd-T1AAlSAY2W$@3JxdLGx9 zGt84Yz-HZwQdP{7NFOC&qy9JY2ulx9bV8pfg*!V8K#x40DxgzFVj{QW`;Gl_L@)FO z$^9~m*VhN8=D@G^fdc@NLPlxIOP-$5;qcHi$HT#19Ih99gpG`tYzYmcM~mjx2f|6L zS;+c9)jX(UZ7YS7B0#0urEnTuQzBg}hvp)Qiv9VIKRi*)y`6hgc{3BQC@`;PA$g;0 zYqX)cs?zGT!h3Ju7aF_ZO(B&-dzUtdiV8b;heu6U_pA7zYEQWi76slpI6K^tGD4zr zr6{TUoh<=953*f4`Mx!ab~!^I9klt42m{xmiS`en!yN$MVCa_bDrw-^R2Wl0UC9vO z#6Nf(nFBv+bobl5nm$DXdbvatug!`;d7*Vx>EzeQx|)HqN_=ATzyIx*S5Y8yqZ-l1 z7*v(eL0~9j5M4&V{1`aD%#wZVYW(Wbb@!g5)!oT{Vd(ANvKkD|PcUN&NC}7xPo6b- zt4lG4P!=w;#Q7bZ`L-TLm^&bW3bWjhp4X7~aO`2Dj*x0b<(Bu-_xBLLsVs=v{kE-q>!P5?$GGPw<Y_yRq)eQM&q=jejazBXU{yF1KmcqK_UbXCz}{%3YvSL!FM zv*Ut$HUOY_pex|cmS}`ArD!H5r+@tV^6RBPN!901(kji(T*XBgLhzK3Vigo->Mrh1 zT4%9Kijy{^0a@yMF#pLwtgbXD6K-WTBJRXPeDEzAWJ!GBZpc)%QvgBtR|c2gX?<=q z1=|RQM(f|nu0GKP8s6f)>(Gs2xb2v}e^~$6d{=fGDE{au-`!bJxE}}t9iA8y6F|w8 zRR=P@pE*!cM^<5^bGOy@Bml0Ok{U}bP<=_cyfXDGpPu6B}b|o&d?ivY1rd2yoqpw z6Q0==?zZRF-)#KsNg#L71NONJYyj}O7*cvJPM0vcbm{=U?GaW^Vd>31q@ScHrs@V0 zpmY}=)`Tp-;rR!UjsVl1eWie#Igu<@j8s0BlV3iLzyEx-T8E^It7xH`SxjgnV+1WB zwrCSfTofT!I7*SAZ8wZQ{dMeV0hM+cJruNaNPn?zz|rvuj4-T3ME!-#3w>DcnpVZ`%}RAel1 zduMBvQw4X`5M92zY`%QDO4YqTeD(b4GPzbHa~(Ac{d7gQj?CAE^APDhy?jHav#;@Y zsn^uKXpArlagst|a8ga2)Dio%VIppkRsV+(4L~5u@zg_DoBZdh=zKx zPToeZLKVnaP-e##p;@vR1Ji<6@88q8U7e`AC5L2ITx=n9jIFl5k3=u)`lT*V$$%%yenL66N)@k7-Op)9V#53H*40rU zCE{OsEm|Mr)ktXx|U)H+!*%kC5O%mk)eu9Fr`+YKA9$*SnPTR_)# zP~Qw3AU9ch6so`lKnR*r5}_z!LQp(7(M5m+X`M~Pa+wi9PC-A>dx%tb$L}hdw=SOP z67=9zba$nnpPek~pfawPrH8;P+{mwi_U^*$-n7+l#Pfs)cP2K* zh6bdNTp}d781;)MPoAvPvrByUq)C9&AY~-#``k>sa332|n;4aUu!|iyjmUc|)6(9{ zId%IQZglR2v-p#}%dbyMp_^BjqjeDv-+}`G{TEIKwyVoG2{f-C06h|B=ry>HL%QET z%raJv2AIG#CJXecy?pO9JUk65X39iS(OeIq_`Q=^ZKBOQv}adOV&Ec1N;NYHZN?W_ zss%HJ(4sXh+61JPa#fx1q;eHYmKx9`s6!~VB@wAo@~hP8$*@MMmP^AeJh&oA4 z=cjz{Jk0H?qNNleOy)2$?|$AHQRfKLM%Z+Bap)tI;? z@P8>MqF_TEsF;{2r(PGHvosUfV)+)FU$FXpW*yup>(soPO9^b;f^JYB`lzPm`($?re^uCYq0+F+$uS5Y9Ge4}os$L?zS2A5X~ z$IvpK7$bOhZsPun^q|A-kXj-4M`O$;fTq3+Rx)GuxA`$|H_fBSWp?V4A+)X8NP?c1l%!fa-iX7Gn6Cn1F7a6<@{ zXaF7FR?>X%V0KR%O-n%{X*tI4klz_JW&OhKeK#tL#&=(xH$=+bl%jpWF8W5|Q3q|O zui*?#nIscgtudS!=9F+dRTyCX8xFx6r^+6b&a!x2aE?o*AWqhS%`AG;j-xLq1W?2L zNvi+TKYzTm3OY}21~b5%p3!VB@T`|<`O^O z8ioX+s1*2UVdo(_sp|DtrZo4JBAhSci6XceLXFPGej|dP{G*6_Hf#UguY8heOu!E) zI;T_M^36$>I6kmD=9O~8wBVSLkP*W<0#3+*K!!(jTnk4AsrP(C6C|tA&f?{dAI$D) z6MRi?Nf)8?@|+@aJ`492RXwXBkW@ea_Ax>o9aIUGiXumdPLZIZS_j7UmBrnQ>VbGB8 zCXqWV`+etc?R4wL0HyDZ+;qwui2ga%zJG6O+A>SW(C?qkoda-7RbXf>N4rJCO35MrNVHs@dbq^_Nec%WM%- zf~U71oYyo3RVq889 zm;)FSb&jUOS+Mo9{_3B8|IJbm7GNeDc?a{d%w@6ze61rr0d6`ZUa=uSCqKoV z2~tc6Ku~dWOHg1@;ohPam{YG>`{tRO@=gipw&no6G&E3Dvm^pvKE5)k z5+F$LKD?)Z_Bw(2UFOc09=0306E7AWZg&ih4-NP5gRLVrXVfgBA-S_P{o~h9mt1^% z$uAzSQxXVc|GrWC=U^t> z*Z#4k;jbISE|Ep&lRHo6Tme%-S`YM)i|#o?Jyb6z-ZslMJ3qJ|q9){YU@tFFyG1 z{_>rV-dl(-h34)`tu+KtMWb<<vbA^un7~9yVCqBCOkbLy3O(I@;;aA5?t@;WZ4<7G`) zf4pchZ<^SH*}8i@H~~9+m!!|DME<bcgGUVKUx(&30da`od@-XNK$GhEGH>a33BdJ>teWF$-6Rq~AWrAC zX36NgWci1ZG-ImXlZDZ<*5~7AmkgCz#{VcH1g@P$fOk>y>zqjY6lq@h#Vg83T!k!`{+S+PuGDhJOvGKh*^#!D5|0Yz|&$TKl$*jS`rA?>UrZ|Jicmu zrq!vrh-fmvISWBjTgBDfS7*}9uwq)zf@YXDUEI|<^KkO}FCH(Gy40Wq#1G!SKd%Wy zp_`c#R0%3HqhS_mSPI^pOY_l#O510(M4>yFfCxCmyw3r=S4}Nebbmb)c^bgI;A7`l z+IVv3YmQk=woZGZ2-KN;4XHa(lJ84|<`3ivBWH_!*r*M%g0ojJh1%Qcyyt#uklp z)GGA>9hbA%pyEuFsCULgp>4Wp?pQ*Y6tlUj)JFyp|lXP%l?0Ig)+v za)9q$2Ot?iT&&g*p)$qh{IoN{L{Ut1-tlK{@2nZZpni!aVlpbfeTszOAYt<$_ZHAR zM%@c9suCw~EWGE6T;&!g_ofCX;PqlrX+9j3It#u?yGQve5ZcgioJdQyx5?jLX z*piGq{^D;olW)KH8H_$R)@NRjQVh840$(OZrjnvfxhkXsZ}B#KW(CC$(r=m{WGz_A*HAhax36th8k3fN zf00IoeoiI8d!+xs04}vvy@>N&hD+3U5;mg$F36Y&6pj#NOyy0s%bW*lwEek(uexx% z?}0t4jz^aKkGcCkO>l;`jfkYIpW?I({P2c$d0wsGyT_9%A}s|jB9<&jKrWC_1(Lmp z00{i73U8mCJUpGxR8=eJ{F{sB7r*=57x!1Jm&T-(gc+#j0)~2aB4JLcT&l!6%4~_* z^Avvl={KJ}ey+2HnazVNXz$-YUC<;8c8Woa%xDn-s2bc6B#65=SLY$Ucdlo$nn`PM z1%j$=bcc|dn+L<7%9qUsZ@pJnxZSDS^TNa91xD9!r=+(Yh zx!2?=v^)Dh*SF?|Aby-v-eZ1 z|JF_(Les8eY*nZtPKl6bSIdU_c!|%xUAoR3%ub&oG_wMygECy`>_j;*fcwkiF1?#V z@ATybNnn^)Q`PWdjq8a7y$R8P``^?oAOBy*7SrX@w}Z0|7~d6BU)xZ8A=>eFjqXJw zj6UKTu~O2;>~<}1S0?e*3|Bw8FK;cp3egZnRH=kh;8bT2gg_CR&`2S)SuWo?Kl$-H z5AM}uToZ^=KZ)}H{)b=u`s*hbQmu8iM78ED%30L&r?GnO^-AWkK5MGeZyWj7ub=&DEfIOH6H}LIA32I{W-NfBSXQ z%EDQJ(zLCSqQT5~U1WcxGr$Y02EDSBpxntupF?tVI_q$p0eJ7xjMfOTZC9zCmC zOuDiidfe}dnzuBr>4cpJ|9BNDaWbF54L|}eS6L7Ft^;r|t&WbXl~Y7j={BELD)63d z-BW>ky^6c8+3lMvJF)$bh7j_<%*?5Y0o6R|;^Qx#He5I>Qi6(m5)$SzQhp0bZ%{VbdV?YmdnnFC0-Oc5 zm?(`x$H0BG0UA|7`pAA%8Z9G_9X0jBW5_v?7ex7^@U?>_Upb}tCUJjJCMFCXEu~KQ zm!!-KD)vqojhDsr;peE`>&t=;tyZ^@{eDB{`Bh7sEhf! zU7jxF-kksK&ptYQvDC%$M2kv9E#Nbk^Kx{=OzQ`L#ttDO+U4P~S*~xf_qSkpmPa8}2e`AV7Ag*-qX4 z`UJknG|DQ%q_)l7>q(Xb@GN#21eRPx-IHrr%E>?c?(3&b9pxlJ44zU7A(-`qk3Fp4 zeYgAjX92b)?b_3LP)aTV+2HbYj#>;JC4^;Tmrciq!L~o$T`+SytD0Leh`YHGXN!3* z)j9C|va#z*tiQVU>0yl^9H;oc^O*x^=Dq_Edy52JM_WaE_|E;Li?5!q zeRgK93d!=?o>CG0W90t&ruMmv(jOS3{3+nLQ0+vq=T8*MQN}U-TDJkK*cSj50rwCB z7nX2d7XA+hcDUAPY5J?9Jf1gRwo@2t`x_lUmP*}^ERmSOqvmdIMvI&m~r=p_zzg9=xh{Jor9>%eCDM50BP{3LY=d>hvFe_Q9Wj@E~9*INww@p1SPqDC&=|8QAt?y}xww&Y43|@|O)L;K;2S z*gN~j`9%0$NpV-u%|z&)jNY*N{nr;Cf7L8;-WcjSxTV-Ox%Y5PeE$NOz%i|ZSC~j- zF|E-BYO*kNl59DK5l2PbKVQ%zK%;#3+_NEeFAD50*893Uz9+e0udLf?f#wJ`kASnq zTwtI%ak*SOzjtBl_pSp##pQDC4!0!qd*^C^!HB-fh|XQG3;OPkTR3BeiavWofJ8ib zc4baWDTu%I;Jmkd+j!q@!>^r?%$JY;j|}l|ng;CubF8YFh&Hi-Kvb!-%QgPxH=ic0 zTSzpBD3VvA?k1sNkrf)=B?(bR43ATK$j(MFeuxH8QhPUFSzvg4lfpQWHs5g{%3`N* z2ROUrJ01wrfgKFZkzBI*xEZ74+En2sM^rBOdzSBWICw(}n4rp(d$FAvN!xFaGU^@BGDkZ=H$-G{UGAok<9R2m(=c#pH|x5;`mc zP25ccwRlL&_s*+#&%(?bYgR&vh!Y8(UEO4QVd+wHhFRH%>#HqHQ+4tMS-2h+% z5wyeIWFrUYlJJoMy!rNVg7nFGX%w*0OgCad9 zIF}!?r3iOU#Jl7B-v%g*fVxSsZt(nSl?){3Rk(Ks1rErgy_ss?F*d-*TNmx~4Jd^! z)~mLSCV`OTu;lvBzk2%h)3sE=5upmHm@?$sovHWPngk*2v(l;!`6}I;=}*& z!8`BG>$*uHQKd?dC@xi?hYGcL1%oxsjPd=m`rp2L|3Cit{h!`DJGCTjGpmBp)>yHI zhzC%;7E}&G9dr?DUZRy$I9!E6MXa6s>PL@G&u4#ghygcfHFUNA zgF#`D3y6Cl9-Oh#9KFc1i)GXHY9{WlNdx!pcrzQt^j||d*O5a`=TOqzoW5GO$^QSZ z1JH}R(2SA<8(nfh=`2VQ0QlimE{qIg3s6*Hlx}QFY{(JX; zDUe`DC&rTe^dF-WA`gbq`y;0pnCyPj`u!B8jU(748P0AS=jS$Mtayje>cuWIkd4Wa zoaQt$xCO*HSC8iLtp!6|%__BIo~#NXsB|YNGD+YDKt2h2RfS3`aVj7dLt33``smTw zzyHYx|MB1a^e;br=bh8)Jfsu0bF62+s?+jJ;``@|fA^F3|NEc)^xysXy+3>R{s|-7 zrMFG30hUxKD#=q9FJ>+OJcdL_aYsG@5fKqHGqWlP~I^mcmqz5Y<4j^CR;ZZ!pu>#T0C+t+9{-5|%iN#)4_g9&j`VNMS!PF+P` zw%sP^EXd(^!NDyIXMDVooY27mI_3ejx)2UoCvPmzH}B&g4iU0XfwXT7+QQE+(rb?X z6F{-5cT6y&Io%ReD^H$b$L@)OCG-!^@blk)v$lnL`{8~2k3V}rpZ(L~kg=9a&rC4k<(kX$WBn1wf0VxWVz3RW0;G(hv zAoOj>GR8}Zjkn~u`DlZr8|MJ~ZvMVeF%8<$6Bk*2loxL=YC3ewYJTqM&@2Vcf$k0> z!5m}~KoUH{yXrXw(dB*Kz!C zGhA~iMrK(uclRFtJ^@(BLHPc5)PDTU}`? zzZ^gAp6wL-q-68oH?0I?5Vz_syHSEUe)Y-aFCWLH>q70L`}KeSqxosTs%7UG{IA1JgO>Cr^ zJzJ&~>%aTer%TSG)XpFjabvbjLNDr9Z~$aN?d_zyOAs(nasxWP;PA4c^xhS6z`2Yn<3PeZ8rF7EE?+_Y3b?E<~}hjbhY zlns#W?@#W2MtVh{u8LlC|BC+GfY$5rem(MJU;qz=e-?eb2^I*$z?-0eAaGbNYX%o_ z0maCu;dzw*Q{Q9 zxmAw0&QIxyq*0$;tsxz@nbNJ+erE@K8#@4fM|WIiT)MgJP~xOkagb`%tHvQTOYTMF zO<3P7e)C%SK9KicwuInc==U@sL0H>X2EL3UJ@d(?H_A9kGN7#Tvu#>RpS&+S;4o}zuvVj=x#Y3?JqrX>gXaDoN0<~9- z_}|AOIFem({K;%cmu&qbBP>V*oem~A+>jD;bv0o|hWP9!?<^jk1zHP$q1sexJ$!Uw zdJfz=H-{X#rDz01q^c?iT@;~aeZnw@)SxCer%_ykh7dX%XpEXqkiP0Nuu*#?((sRM z2}*PlpYh(Qe)O;k>+dQ!EQhLQu;iKkuoq(Ig=X-}2!kFN8;5=0UjDBfGv2z;oLkNq zBf)o5Idqf3PiAL;1LFfbNIM%0dv2W4Mnh&Y0Kfn$=xj}*AplC4!h(?1{Ey$oU;OdP z^`vQ1u5-H)Cb_ZDx!%znk)440fc!y+pgDRqezAdZ;Eudf)gYXmp~}ru_p9ZqNoW&D zadUSQ#n7|5J8oG>GZFWh{6OO5|M^gHyBmAAvk5TVdN+_Re0rH;j$BiFI?Lvg_NR*YkK6+e zzhwyfdVOe2R|xjeKLrA_{^7z(>(iBlOOgNdUw;?F!w5we({+=jgZj{A>e@4C{cRBS zWE$uU6LJIaQ^qHq*!xiU@2vxdJ2>sVc_AjarBt}#in^tJ{+dGn8)X77lLH*ldMXQz znG8VdV<5PTJ5xJjyszs&dwY)NnbJg*REi!@o7oCvMW6!dbjJHLBSl3;6mI4zCQFpH z$yMu@Yj>#`s_4n-$y3`lJ%UWS+sb`e-|k?#JRdiyv~p|Jmml8OM^#(fTHOFQ_hiZ3 z4BlUmK2dV)$)k#E?yqH#9N+nQv5(zJGUmk3Yr;ao#5UV8mD5Gf2N*2^Mnt)9$L=!i zY-~A%And#?pYW1d!SOl93+ybaV&*D1Kb@I*3~n8 z^sg)yjj^A3vIxC>EibQDARN*whHi(#Z@Q-aW>kQyWiVA`xFdy)+2`)YGH$6F741=goxvFE1Z)fFzKyHUlEuF_3J9 zP=SbNz;trAWF8Z*S~k_azx&O%pFiiC=LXH3J;?|QkTk%ABl)jKgM-sHy=Ej7T zw@?1%H-G%iAHMwbi^uDfpp-yWQbaZM)B-6?A!J`WV*e>Igc_8f2);Vw)xUZFY@RM= zXpvpd2zSd=_&%zqbphtVspmWPm7}Y%JG>*NFtcs;?Tss5haa*_lc%o;vY0ZM((5NF zdN17RMVSo61jXd}^7J^+geEi|87FMv46wPF3@<~bax1;>5xLW{F_sxyudXov!_)Ym zfAzT0x=nzmjPCCRaAEX>t_c87ZgA`MpWU%b7V1W_Y&+j_fCBy+a5&kP!Qps#wg@ni zCgH0m7asDC=p@{Y#2pIgmWBVt7C;ord+Z?Y1ZFjqSrI~3>zFLJ-D#8BmrPf-Hy7K= z>%T-hk&UI^g9D(@9IFP&00`V>b*Ms4lC~G+F6Oz*0&d^oPSQMizil**rXjCu11n&tSZs)aO3~RbWyK3au!0^?h9G0)fznQ>j5(x_RE99? za25GBZ3DTbTSi?)KGoGZIuK)ihGyO|GC>E$;w)Xfe~S0cWM<1+%`HmD;oihu>hNGXeLYq8=AmzcsV>&m^?Z=rK3J49H|?>$#_Sc-jUdW6+K%cH9@O#NUh-a!em- zGbT8M!rA@e@m&QLznD8c#%~K9)V*cu;RWBRz&rH@#+Wd4greS=Z^+eA>h2ZVV*MGS zgFw5G;xtIUXaq#V+`>t$&j0EcpM3HRUY%ObfX!f?@>wp7bQy7m0CfcAK2bgh`nvY{ z7t?Ecb?XlWV#zYu{r)K`x{%TE>}uUQK&WWeLXbNE(CrImwxsC2|F7rUSBhB`+>Ml& zeAU4ER(dy=%qI!J53U0+<^U6k+@idZB|)QO)tW;|A?##Ut8@i0?@D1d*>#CE-O({1uNqvn?jnFKD!n&H5M+7G+mOy2ZVPmJ9n7K{9JD%MW}dB(vTzC|Ij)*? zY2jIvfBKz$`8-@1BCQAeWR{qVi-a`E#JvJ$v?^WxKwnN%$;m z`Em}B6Yt*Yt5EmP1^yiO3v!2X#QVvB1u9wikU>14Qwzw$gI&5P?u=dFOEGhISzGmG zQ~llVpI`c{Mdj}BNRN`m9}Mnv>#L`O=0E|Q+-K{1qbPs732;pB_a#g6nO+5R!j(9m zW2S&RM6aS;~aYr2m} zy0Zg7O7BM5nZgRCuIm0wTvZ`q9g$c|bqbw9HDyC#LEA*{Sh?Nb$mp%@V0t^~-_;6m z6$n^|DmBg7Ozu_d_wTXxtKe<6MzXvb_>ePm;{xuivcK-2e;0A(wS^E{n}|7cA7;k{T;v0aZ!-tL1j0A@K#rCm?1g|Z1rYWSJ|B7mn^IctMp7Uybz7bP_0K>4 z)#uL}IZG7x1Q5y3psSAvytgubg){e00TlhS1B<___|)|##guYbVG8@NC_jDC985qA@j zn34kwcz(IeUa(3(KdEvmWoCmUBr&OR-VMK7cUVe6#mq#-2r54R`pOyFww+b-&ZGMZ zr07b0F;dh`y(EvU9_?g_?R@XFXYIMdRoD_`&o6J9CIq!?{sf5#4eMY0{>vwJ^6}&5 z!cHz*fw(XsnNnGZa*Via4Y|ap!f9oWL+xLL+N(uQ{eVl2e;+)**du;qs7K1+FE;*_ zQu-1DJYf1wC(fqar|9Q9H9+@4GI-NRpE<||?O`ia-C66+u;6{g!W^)cS;p{UbMpy` zJ>Ph5Q|tL74WdkKP#Qw?-lvY;e=JG2%NRV_>JJI-GPUCzkt(zR}y zdR`|_qT-%qLaPW}MS}!$fK(MT3n7e`M>b7lWf#t8=f&CJg}bAwW**xGmp^`M_Gq5w zT&HHO5>oP%y3u0Ybt)#EWQ^5bk)>;;fp&t;unTfF=|}ZJbg#Iz`ym}8zwg8y{m2TK zx$X{bjLH4cFUP%a#Qyby!b42o)%Imb&c_^pgLhaz{iW9w?%vT+FuJZi3*YWy7tWui zKme6uWFjF@y2BDZDVzpjm85zW^?&>4KR!v-%7v9!YLv8SmCjP@a2d&ubnm*NUC9I! zuXI09&flJ=nOr-XBp)<#*&ba}M+kp`6vEwAnLG)BgtzXW1tKMjknf&1P?#fII>wal zGJsoI|1Sbv7708%h%fG+&6S%{h&KKJIyXEHCOUb&u zl9JC$eu($bfA*$A`Iyb><#H*iF_~-CApG&`=g)2aIL^Pgz@-JLX8;6NiF#Kx$hvqF z$zYZaTRqNaDBTUyjD1f)3Q_POn2=3ubhj>ac%eZjbRtSPmaK}(Vul5bHN}#%c+lVX z*vH}Y;4pw2FQf#2#E{@tL8vR4ml~kGNt36Paz?gZt&UR$SGAI{zjntoyz+X5VPs_v5t# zwIsvr@~hhv`Yg-y*izADLGQ_>$84!4Q^}wK+28m2hT7WrDeETf_lp#Yr; zOwyr;L zB$}IG6>+t0%}}YRr+X)$<$Wjvr2WOzUN;b;`xfq<1)*y?K5eR}SDK5vNnrVlnlG zXnrj4cXPG_)a2?u2Ett#?gJ>>dNTC`8Nfg2MTcdxizpC6vbJIVTcV)C2{T5A1t+}v z@{)i1yRRR&+UTNnn!A9WOf{6jK+z%bq5OZ~p1!b8%i))mi~P%^lq#^4M6{y;oS>pB zLCV!?-6UlFYsnO^J5uBAJG`?4o9=H8nrC(#7Bv(mfIHSrGB2sHF1?H5Mh)o=6=dIB z*gyGt+%k1XOlaC{{9!6s)Sz|6;38+(DDK?>fo@#_fPq@*g6B)L(E!rY$-J6XSv527 z{f1Z92HOr0U)WUWKzOl39jMg7a>6=|#u#H&hc?ATiBf&`?Zu_fziX;bzgPTNQxE z7=e`yncf|`=Zp6J)?|swXc6#A)nd|q9OQ{69p6g&AjClHOVqMGi4KYpm5HJVGeB*8 zvBI=@`jfZj_p5ehOQyy)(zqd1)^^DCcy z{LS*0pFV5C`6>yua`#Tv*mJogg9?jn-4D&U*N5rfUb|kRhcJ#W0*e_IwTc^n6_Yz{ff4?A^V(;6<|%sAQpguG*M|?uS7v9T}F>!1f0s13JA@oNSit z_8D`+9P1Vi$y;wO&xX0$L`)64mzthKj zoh0D>knUsOc)UKH<*?6sD3EpfDj5abBzwASKYx7HRu6vn`LoN$oq;M26A6Ht8O4Po z=Ql%qI>Vg}Wd9fh7Gb*dE&(zG?kuAAv36K${tU>XsY}tA(Tr5W!m4{`iBzT$#s(+& zHcEdU9u+%#N;z;92`L%G#Fr=W*}r-BwDzljHUL5~B1w-PaTKzvyKBrlAV66~T{;(D zLI$u$W)3(IRF$p(-Go*J2|^)Nf@C7_HjFAGIr;>0C-i7%h%7@>LXcriqzG|d^OUQf zy>l{8&uTVRU@~`?tdC^Ysoc74M*qj;-p9xBNB;J849>khfi2A|6#Sp<88@l`jUn^I zi*&RD>sNw4;r9)8gggA%s{DK78h;xU;p*1 zuP&LwS!)>&qo9lYreFFgFtCr*n7&0FfupmJEI7 zL->?9ba&i>mA}{j2LVX$zu4hc=x{@&sB3XIkjb!a#*SAf6~1xX-(YO}#u9)bDe`Uk z0(U^LTxI#6oG8~qz%o%7r6Bb1(_IE|D<_Qk;4~E-&n~a>b|dhI_iIaC394)UzPi@`S^mzwwqr&RpQqH4D9q{vDJs`{eU)R#ts`Y2RG5TFuSO%tQku7{&XzPKy}d zVcAi$?8tAaefKeUQQ<6Kxgi0>X(%9*P_L}|lbb>!J@S}4Vx|qf!b!bz50LLRCIfpL zK~r3rdB$cZv8(sb<^40M(NuKJ0<6*}cq8H(*H!(C|7R$5Z=#nA@6x+?B~Mhz`m+KG zjGipDD#$L>^ek4Y@ zGNp4)@jrgE(El(q_?1Wh$6(d2?Fkg|`o;+ihF{z{?>1;Tn-IQDAt^5#cLSf8j(ul7 z{H;>^oTHQv^KvA}3>HEpheipA5Ybt}{P$n2e)Y%aNkeM@nY=X^mDvrtlm9e_=Xr7z zxa+2ZKZkRGos8iZUXk1#gPH~19rw@X(m7${`PGt|HNl{&(b8Rna0@#Cz*qosK#jjF zp<~Pm2zY`Ji&>3MF@wt$Y+AtPpH9tE{>0a=vxR~KS659};-oL;HLXV!bSPSGdXL^6 zxA5pH*`zsI!_{(?Crzbty6DRP`JQLu)XN0=J2%}o%M9*OyOvo%l1p4}o|5Gv(B*3V z^>@#b%s%<*Y4jjMp~J;p6JP{X(1WKXSK=gZx-J;E@D9H#JI-K-{*UYk`lp_wWknE} ziusJ6j6o}Kq93}eDttX9W9u|tf!_c28wWqBSDJXR2dhki65ohaz~mwl#NxdgKY3?f z+w-{yEMK>zS$9apn6cDT#PtzJ_7)p(V!eeNvgww&i3rTa{bW8DI+12|$niNrHxto8 z{@;OtEHcO_?QtNJoxTJaNHVaBDai3+YSUaePZvLaG+Wdj(^@3BNtYXEr?l*$Hc72Z zjL<8a)OV>zCcaIpXH71c27C zPDmi&Gx3>Z3$QF+4U(`IpBy_8oCQ;p*mRQKe&)u}|7Jys4(8aOxwM(HS%N{u%w1+5 zfBsz?&Yw2&)w9*w7*h%=K|)qTBz>b&o_(1H8;wz;umBpDt^@G`v{HZ7{p}wih~KBfRwfMnZ(ys zy!g?B+5IY>hU6)B!8%FgRsc2&t^3)fW$@P*PT^gqT?Uk{lC?N%5mDOP=d)93?$zo3 zLgqn*nr*qtD`!sXtiN!r>SSI4XBUvbuJJ8hvhQZeLePEue7hv|2&{h_|{p$Izzj)qOr>g{z zDu_+fbwoP}-QGUC088H};omL^y;#!t@-m}EwNX!)kStzLi9$qhCSi9{qraspI0C_v)r zs%f=~=0SNj*NR{V1~o?_ZHV~QDAvIb?*`%RI-;8>J(&PseTS&0Nh;7Dp3Q#;$t7y9>M`0!(uumfo|bbNH^x(9uM@93We9LOZR-5^4{^ zJ8Xzs#~j#_Ge>5EWH z2}-I!D@X+dKK%(#HZnStehcn4`Y;Ggva)2S>1lMMktT#PSaf#}h=2Ls`TyAN}pJC2<)m%-;;Hs{Q09S`5 zvw9XRUY%F%pWWk!^ETKst>W4mQ@Tmpx-nKMB1kR< zNqG0+iMz9!FHOH&Vigf82*e_ISJb>^6@LQEaNJ^anRzSX(UJ&4!o9juc!I4QPgji) z0Z0Y|UCbqsDT4%9WEOA02|(V|Wh(#C$(eWRcv%6!5FH7*Zs4^-iiz2&RTM=~@j?FJ zZXDjG@;^HhYyw!Wt#xq{@Uuk~08i*FLDA7(UsvWn`Nvdd>d3X;cbAbipK)_Hvy{

      6_=x6&8e0R4dyba%^4*&H+$?`=i|&tc$pKaVHv;s(-XGxFBJmNdLC=ZKPy-@dMa-NM zGMGg}NbVw>OO)oxpTB#y@TIRWt01D1%rGGSy^p;L>BnoM?V0KrEBHpb<9NE37yTC9=^Er zfBfAut4^a=K`V<9mN_Cwop>@guKuBA*=l*ZWFFwjoYD1i9bJ&S zgK~!gy5-rxFgNoKm^}>@m??w~!bDqh8>p?M!_8A4<(5%s&09{K|Y4yP+CiG zGJY+&o8?lzxjRy<+U1WQo;^INE1HVCCk^TyMSSR$2q6lQ2^pK$nj{b+y{fY;KBKIul~;-;J65aKna1sX)XroY>`ESIfSUiA1=a&59Tvl zX)*#}gqWLq%F4M$BzQ8=pl+bk`<&R{2#WRvD*Zd#Tt^PPee-?ihe)T-Gg|eP=3g5u z{{u~oJv?rf0HN_^jtzFuwKBE&B+X@&`19X>^5s)oV_^*5OAJ}=Lpo?MFirdcUYhB# zr}uKBH{SFdhCV~igUy}9+1UxPa6N~$(3_P2$IQE z0=%fkWq+Ru8Fvd^gKa)8HmH768`n}Tq*Mqg42FHDQej!#n#6)H7vJ9;-t)?GfMXVw zEyQ_;t}?n2?t>U&OqQtH#+02NEj9tBX?;JWKY! zl6k0WcT`mskb*5gykEbwptLJ-Gf&Z4rP2^%D+E2uMvC=5bsaxuI&-hvO8Elg=cdE& z+PwWnqk1a|ckG{cg9{kpGBkvWOhEc1fm?b0#=PEQBm=#H!1$*f8~C^mgS6>h(f7$n ziylHPv(vAhHUIFhU#w-eHl>8V@M$>@$o}J2-~bNWfxW;^aST!jugDX?duzq~kCO!| zC1E75maF6)+3hX?xRoKzuAkk@^bb`)rIKAcV@z#A);G@a?FQfLO`2QD8^1sUH@Z_l zb-D|djrZytRt3qtc;`NZ&t2L7c2Ak)Sgz5=L_%QmN-FK{I7fe?8{FjsFwK1eoi|M? zwm;{v6L9}>g$ufJu;+a_f?qvbesz`B_5I&`@igj5YZ5|*&X9E!UhI8#Aid{Ksnsng z4SgY#dYkvJ>8DKZ?Nw;GltIQwHRl6&_3&7?_BDcJfH&7VCwUBrtMZIx|GtyaO^hs3VG7Q$ZiX=evu zUoVBEcIFT{k8loJ3Y1b1asZVPCLK;ETU1z|BFe~O>zOe!HE-UXgiKw)Xp$`l&_(}U zE)lBGwoyY(2UEL1dycE0KAN4fQEQU5-UE-^Jy`(<=im@NsBZHn8_^BQz{iLFQz_mZ z4|m)7IP#B`j4=io9RBFw`q6eiGI(ud?Ke zyQ8i!uPcF(Xk%P8edc`^*W9i+rbOFu#|Wf~vlFap{ac_*J+pnD6&o>#FD z?{R3l$wzeh{Rc9Htx6Sp5HtXHOWDP4)y6-5{dCF2mrvuDPu8Y07X_u#AmheaQ1q}F zsZaI$$7cp(&aQFqgIgzMtM)(qi2^G!k@6f~FPkcmJ3>I2B7zPCG}B;$+$GG!{c24& zjm(Zu4-OZJr{(|Q#ks=+!t(ZRU~-y!8>0qscQdbunXleElMl{A6)!4APwT1<<}RYr z-_N3_)9JxZOx`x{;Pw|`VfJJND1VH7`_07*P4~_LcwmKM#GYr@xzVh014b-(!s%zfMpZ&>LhL_vwGw|vnx&wVnRbP@b0*chr3Y_f#=JWf$lCy_s$k9LMsPE zauyVN-H_}^qZ@QMQcu#wrw|ZB}^rB3TGb- zbiIMPR|Jr~9S;Um&q;i+VJTYF^SZCHVLvN91CXQmH%q&sL1FOPsy~kxTYZIVH2IR_ zXA1z(g;lu@oy!??7evAgA+buN!Q2h*fCTuX+J1aLEd1)Ma@v~W8q~~HLRK{>s<3^i zCldjeeYDYC@=DfKQ)m;@H?W|HB%dhG4!7ftn!LUYH0Va1t36p3 zitKQlaWn{q_Qt*j5LDCor7ZsW z4_|-vw2ho4I1p*Z!T|!E)YaxRJTeD3uEfLFy}!8Svx0f2qf5uV)0xuTjjB(cU!}VQ z;0F-faBK!JQ=Pi~6mXo*XN18`M3(DjOupTFw*X$JQt(4a0LDOSKp7jbZj*y>7h+ar zJ$9+0&fv#_9 zP(=rW#1w^4Pnwo*&F$?IXj}$K6szj0i7`|)JjdSHus-$P0dZ%2eV;3EMo*CN%(dzD z^z+y2;2GUe$-B-7^dI!uINi^%1Bs3UrUVlLDUqQ%B;gcj1}S-R5fN2$7hwnjYbsyA zed2G;ZRRc8Mg&fe=FVVH%lryY!_Hv7_XZs^Uw5LtUsYE50)hU~1+?*oZqC*%D{jFC zp}$lFDw#zr1bo@|g-VaV0^Hv_j$>>ejaC0nEZB!X~}$ zhJ%~uYsii2tFwoT-(}6W>c}BZ8)3wgXP1^Yk<>mogLDu`swm)YcI57O`^0u( z=|)J?{Q4N15J-WUIjn74h2A@Vi?e&b|Kdrs5W)>UK~W+xG%!Uxe?~_XdG* zZeW3A5`AIH4d~)O>8rkjduzcfn3Mq7TlkG1B~ps$mtJGz?3}uW_0)x49kLJqJ7CEX zIwU*m2ke^<qL^3xvru`8xq$nBjjD0v?b-<-7Gt_6l}LscIwR!zjTW z4)<%2Y@N`t!}oGswuv$QGdXF?C2iq7`X{m*$!XL~JsPZ3J zs}GZBwicCZwEuS+2pry4NWv^P^vsdXSRR~%7DedJt96??ozS}&;kJb|AkjN879%O8 zB&z0yEbk92Y9J*zV)CnX(uDGIa*HMQkZCX zqwmxU!qjJhJ8VsFR&6cPhux1!d%<7!_U&st>?m?%@Ml+(CLkeHDVe*^f}e5u)3;_b zzp5DlgNO~-8_Ezx4TOlCg;9#?{Qf{>^B1C`d?x=PRk}rYQz0p>>(@*Fmrq*MXVIle z)+DRzx@p!qN8C4OkLk_65PW~b8Rk_MhzDAj0JUOKDa@03YqD(a0-PUEGr$K}Y;Ju* zh)NMUg={v_qaiQ3y}?xx{c|%Zz0C>04xB)S9*Ua_Xh7>|qGgI`AZmql@QI;Acb6Lf zP%>uHfr~37mmKq)&S%Hzr%YZhKfl46RO_s=sj!~RKLTNK^-kG;Q zx-Swh1I%NB0Wd>~?&bo^Mvxu2uGl7Uq+IXuF7<6bz-HpjwY15kg6Yhyxa5g*db4KYFMS zXI9y&7SIx528-@-gxL6If7y?n@~@UX@=}=ogT07-XS;EE2dOSjChU06WGV(wD1eo2 zahoc@MGlaa0EQ@bpapMIj7r#{OuYrhRSTAlDiqW(YdHV->&u^i{9O$9BWjAaF#<>_ zZg?aeuH_#@`TOyGgW&>SdtZ*+TsF~H8TVy4J(&Xl)fq095#Jl>(!1jYb|oKKTL4%h zWpfj=64a_fI@l(UDU-sHk&rtZ32&hA{e}_%-6)DKy?~3=rNMu zNKU-70lu9%0IpW8F_?qE*PJ`LLHMs!=qtrNCoZ1l3pOUz zfr9#`-pKxK633~a9J`iuMdiInpz*iZ{atSE53o1jaJO7UHApfs*DPo#78guse)(r_ z&CjZ)mWHqpsw{z$<1x*wRyxF8yjS3tEdPUpqMy5kfV#0jbS_x}&+?vKAVr}O1}5s` z=c_Nie)h#TPriG;Gzl(hy+z~3#@7D%buUpB zpJ{WZ>%VyWFh=1=e9v9D{8OXsI zK#D#Gt(AzlT0)uH}_sL=Q`7_^4=YW2oAaSAVRQR*?A>fz~rVl$^tI|x)C^?&+>AX zsF%yeUW2N^-SLL2+hxtGqY!0jXom{wD!3a(lCwz|{7zM5Y9{bQApvh}+tX^znD?xk z0n~t5T}iGrj0GK*%!qQ`x;t)Ps!TetY+8tBd9=kWOQ1}{wO4`rdV$Db!%af)>WeGCXrdER1*s~5z;anwI6|&{z({ixX z?I&M;``MR|Kl|dFCFtQcNh5ZOue}vWB#Q>5*Wz@4%_R&IY{inf*%$PEq{9ene$4<_JIZJKr7%t zDqDAMtTPm@*T()l5VbM6<be8nw z(`WY2A74ThF3F9eq?p}UfPde3*zG6ahxd+6OwNnv0GllVS70#*i7aY+xmvs5IRW41 z=zqF5cHmGSwYh|-s?hs!$hz4Kga0J#$2Y+N*mt?u`v5ep57~HK)w$Wou5xiVD}HE4 zj952qCjk*$s2nBhG!THD6tc9rlqzxdr!PZ8=6)X1id zF`7V>n%Y?IriD(b(S$5(+3x zXcTvWDO^U#zGTCogHFu5TLGC2O%W)ONxv!-6-8zkR25WR<>}RWozNsazgjt!wL|#{u|()jGRrG-SoIy2`i!2iHyKi%QbWz&9TIznKKUdjntk1Phlj z|8NSCqGiQ9ht;94S#`$d`Nboefn~0AmmA!!T$yZ*jiG6iyDP0$Q~}a!-Q_{z9q-j& zOaN|ZStsEwN^zv|Ha4OetlsL7p|2PfCm*-5-uVk z1oV`?sd)bY;pM=?>rb>a=otaHD9{3ZVQ;AY``|KGELF}4W_Q@UeIxqch(E@5KW^5u zd4*xt1_N<;Y;t6Gs)B4(i{W6Iin1_~-H`w5bRvyN&c0~wgsHc6y8P(j>_HVzf|;eN zo@Hijr|sy24_AlLkg|KzRg6S-g`@|xIJdQH%EQdeoKC<+&=@#7wJ?j27(K(LVoV)< zEuV!`Iu7sjijfW+PELyaWT-@sPQ@}dLfktN3`sIbliEKY`j#$t)zW-;(@^H_xRlN^`cD?k4Q_O&8_nF!U&T`Q-!lkNiVowJDDeSqDzT%?JcV2rl&2quzy z2sK^B89WI9t=7;hhNz)dYK#hG1{Owq2=hqpWh&f(!JpWN+*+hO$sx2?iqo8C4pO>e zzh%=80mbMha52xORbXR{)**}LA+64I_0fF&XJ^Ldsft;$Y)#RoXiiYGOG7T64imTo z-cEp|>@9Y6N#EA9Mz`J}*f_|3Je=k(FP=xs7i?{zj zrRSoY)Pv!`#ssH3%sSh+&LAwm-Px}^Q%`^qenw1c4LXGCaLZ=DLXZ}txCcO~$*VQb z|JPrB@ukTMbv2tMYebWwaV9#&NCV9QLL?=)30>hiJTTwV4Bcny;%?rrhufLmbbs0G z1KbE!%5Kwh%Sk?xxB+6+XelTjoP;VhflMynUAl$4n&xc_`*XRn3r($K$`h8o*v(;` z#I71nW@<=@goLYQ;|}I=J^FNrxTrxKj!cWZ(--w(cTEn1hbkTJ}+(ASlEQ zW}Qc6ueLF^+uiTDzqfX_zy!-CbGIvZ1@ehQg=7AWXXk*v~Y6e@>l=(?N`si>NKY8lbO*U!vJoTFLT)t|k4c3ww8t3r=SoI%t*bGrNNC?j+zq$sGpu41X{av6hsmf!7GQvVU)n{!pUx- zCn=Ol!=N!Kg248kwjZ8{2enCDDgjE0F}umeWP9$^&>ia@hOz<81CiVtS7N!rpBq<( z5|T9`@oz@7Lt>AC2r@PC-RckYm#xePhJ|HR_a7R5E)(w1czw~A{|jBw{!eqP=jSR< zsOPQJ&vE)!|NOO8i_2B&pc8b@OnVWB7)9Z2xybgrqQi`hsjb`)%J>f$BzFYO_+g4ka{OXghR|qb2#GVW(@IevMg+_XTv_)wJ zQ1;w+RLaM8{3a)F50u=8&_Q~_P4B;Cu=ky#uP+mSby-KzP|{91eyq|4F4w*e4|)i`upxw)Y+-^xqV4DzQy6|zY7b# zSK0Fgl@8C8MFQ9M`r(t+$AA=s7~z`!8d{-YS$l3Vr93)r-t&g}>IAuO4$5 zZ`4xW=qexUQol6>$G}Sjj+4cla5E?6YPr4xHT-bG98Qp9If$*QDz{PH(YBH7!0mfT zem5=Lg)q%f8n~=i-dF= zE!`VRN)LLIL-gMzF=nYB+9buLia7b|nf>80{>#69^YzjjsiV6{XV*m^MEpURut(=l zqwR^*PhWwXs>BqoK&6~t*J$B?4R-o$6hO7HTQfEG1}8Qko>H1R9W>)=f@``-|xGzmhQHn8AZmdeoi3Vg{JOos`R~CFL$e_~9Iblhu%2 z*Y%iqw{5i1x5V~VuU>P}?Dda0?{$Ow^>YZCdXO$sGIz^u#}NJmRl~dE4NVEa9P2h_ zeuw525aa5IK`HswO+wtz4gMM-IUnF`Wh)-uDNH-uEjO&CYLfi+lgIz^ho^u2%g_Jo z$KPJ~!orDEm8!t46Ul}G@D7aYqyO*jAgl-E^nx4xCW^8uU$~I?Ku16?2-sT%PvbTj zV~ZiklLC=E?AcOC!S9Oxv5j56Y4m?EVDe)ESsuKtdlS6OD9jyLADAJA!DJV7gL~Ki z@r?g8YN%t36=P+WAKVY;p_wz*ia^o~DGFRwvjpfqX@BgGpYQeQu+;!o~ZXVRd(5}`qcTi_1s({l4e zHQk#VLhT+-``U*M4D9+q?jAzc2>}tFp_|L~`i=l_%i|j!M(t$1 z6S})2nJ4Qu7;cVk99bZ^1qr~oluTBGu~^ea3?jrqrSulP1ONQ+j&+MRb-kY|NTq;} zyNhqekuOz=d6}ZlKF8le{;`Nj&2x7eJ>}FXt@(Es&8OckFLCypua}RTDu%Pjux^`_ znjV#lzEGO^Es*KH!qR7FTa|C{2rJOQvZ2l2i-EAz`!9?A*f0g#Y9o|dqJ_c?cZY!2 zbjfcjpuWo`(GPv{b$x(qfIvNqgA-5ajuYI$ejJ&LWU0FtDZ0XIyL|t?ymvoHdr_%* ziVCU-+%!;vn)xxb=6y2%H;Vpc(-&e_!{ms&ume9<$i?jL0PIg)wm)+V6eLQe)6EU8 zK`2mfXTJX6UiIDyPq1=pAQVwEH*+6|+l2!6Am4P1Cd|v!{x`v%!mzP&4Gnq z&P3Ub^77KzcX+#$IRH0PvW>bv3a9WACNw~UWcnTYnK&7N^eh8QLP?=G#0F}DIZQ&s z`O`T6+h2Y0^`#|UxJ!rIf*I2ErgX&gJPJS@=@<4|8v=WBfIK?$CF!_j1ge0b-KC1j z*X~lA$jy=Jo3sPltrMx#TfQAOqybKN#{i)r z+Zi!Mn+fh$>mNVV)6i6G;3;Do1(eMFa?f~*Yhf@4O8y6&p(dtm;Gvkc$nmb99V5z( z`-=D5PwxBeHW^@p|B%mEU746gV*poyVtpdbN9Xd+EQzlTiOl*zV;{ha9AL}ob#GDa zIPk^|#`DWW{72`;UfB0e3WqYVc(?BI;11T;3raRHOA5iTo^05M%hX}8vlcFL0NF?e zWE34LG;aZB(+A5E-{xM086aR-C$@U;58tkT{rU4H=g9@0@&5@h&~hJ{M`ZXfll2|B zaoog^p1pQ-KQ#=MVm=GVX)JZQx{DERXVw3@+W)Y91QqG1=V)4(@0;8BVRQg?;vIbm z_#9|chhPw(3bNtOeU}OR@Hzknad#mq744}YeQjjacYPIJz%Lc89*PDy;6pqM{^at% zxq&oF3%P3X)zj5l&wlsiv&$GzEn;*6O15p&mzupp{=i8gwFu2eeI9iDJWP==BN?FB z4!x7`%dvZB?1iH6KSeL)UrppeyiobXM!kP)-@O^8`4!!-4b79io9*@jats7K_hhH) zPowE?u2$rdvpFGR$rdWwUVd;-?}fFdWhEfJu4lPQO;K}CG0p4Qfx7tNCdq*dvQhZI zk#tz6u+GDSW83059#m21S8s&M-I$`kqB;Y(NdY zM=9llhjpe01iP6hSE}kfYQ5HzfBxg+FE7xd%7*cvp_d1w6C+!S=sn`NKWzF_Hvu;5 zxg^}6#4IRs1|Yg>??}Kul)Rt^QfBr_r#EF#>9oAu*~V@|nJfsrzGiW|IsltKEgVa0 zaA37gA_~AQEoQT=%Xc>;ZslQSC5~&@Ri0h07%FoRett5S4!&+Z4h%26VIO!wIgoO^ zzVpQg(Er`%oA+{p?y%&^I~j49rP*v|mW+thwaLGH{Ar^nUtP41uVRA27)UYeJg^6B zzVr^T6z>b}Wg$&6bi9z%=)xqSh>Y9zSYn!#206vX^a%rdV~K+;An^Sq0yx{BwYry%VTYzJ17rI=-ZI7bm4e(i1XYJUcX9 zd(jSPlI}ELJEn1wPdW)q=uYtst@%3(JC)XA+mkWe%wtLrA(<^E z^BkWJ3=F2u8)vm~->-!c4rreVNUT)Ooeuj0BflKp*UyFBO@@)^ybVc_ z{ny`py+Y+0T1#YBOhXTy&M-Xm9s}-lLz?iljtJs6rhoaaef9nu<^Uz^c_cr&rJ$f= zF|UJ)ITE;RI%4R?1i6cXZr!l~V(+6MoSrN^rHsgHQ`ZgZpaXpi)2|7IZdC%n!xxB% z$+|%g4|+#~|3OWF?FvYfEO}SWu7k?JPAgQ{w<{*E1kL}-Guxqx54eadmrJRt*3h_o z{d{>5!xHnao~@TjD1m^&t1JL*ecg^FGKZAx;Z#)LbFE;a=Fw~W6xnrOM=MwXeX6jD z`yWfix#6-|`!DrIrBD~eraf>O4HV(vRzy?=887fC-@D5I9At-wbE~kK+FYpAfC2}p^<1m%tW()lW(x$&A zDuOIaHJGE_WU?IY7#!$e>_vR_>|s&_Dp1KOaixY>YpUYq&)zwkx6fu`?lE_`Ixz{e zp*snT_m1%G*H51GeRtnCut23D^mg7Zg;j8wS_n&1@DWeQQ37bv zBACdL0i{dHi1{f5Ln+A6IpL;JL9HsiWth_~R8M2|uU}kzb7c){ld5SWfo8RyRh4u> zKLIK1J8Z)pbRQpJ`}v)!ps!@(7+G!Hn%V$?S*1Da26ffMZdsp-)ZO7Aejq^+5QK!~ zIhM_?cfN2ipMTvgp*I$AkDb|U?lFw%7}HQk2~!Br-SGoR0CGst)l>xQHdz?H-&jRwy~l3h1rb#@+%aFWdBUKxqt8XaIDxcv8#n3`2Ud&=B$WNy3!n zJhV0bf9(Bdb0kTYB?_K)``=eqR#x`O%95FR(=*MB zbyZg-XAv0$#NAZy*$+xg&D_l0fgqWPh6ySQ;cx&BH#60H&piZ<__#U_=}xNgU?wJj zSROozsA$pzyJVvrO~o{Me!A5qR-Zn-`iFo0_C@S^bm~?Xty5>|OedL#38;x=QSa2_ zJ)N)HOW*979AAkE-BAb(N}R4eEDa3x{BpxL3tHVBKk~6EG>!Z*1Rod@nH`>1M#G zy`ohlM8b6u{+l1ppKs-*t-gM?y$AyBoJg|yPXS>y16T!({YLgdm4cD;ZS@1H6Csa*Cdpwas-(pDZ_|MJ(5 z*N@lHg%`q5$5qiRnzdfjh4ypo`f$TNZSJx>(q3t{tvYZ{o10Ft&w!|9B4H2#mxiIa z@kh$tu~|^_YH9}XFgDy7EwWj`M8<04jP-~~QUME8-~b0OM!-ZV%2W{3tuL|u`+xoB z)2DrK_kwgr@!rQ6tw4skmBlcBJo21YaOdD@IwoT8dVNC0b!h^eo@53rMX$E~*g0Ns zmxJ_f9i4ZeiGskk??*z%;uA%@JsAAW7Tk?z@a(OX8UR)uQ0MQikay%*D5J62hGhJv zf>oFH3!9)LujO~$>>Cg5A5+qBlahIG@oU{Y+j-&GqA^2ynODFa$Cw!b66dH`J1pndw=rF- zu3ds!kB#Tti>~D=pJ1EzQ0mA;EKjTjW0bhLuNS|1&pliP7q29h*Kq0b&VDSy(#5Gj zbr~<;qnBMmi}!o2?*8Ni8@Ckag7+VIe}->oiNRZVCH2Ng6(tuUftR|P1PLczd23n) zgBJ&gSzK#e+r@wU<=Gj}6~P*aH^vyEnI$`3)D1QF19pwl@MeRlV}bl@0{`uAsxJQZ zSIZ%)Ee7&WdtHsZL3jOjC6k3XB!LWlV3Q*@j1fk0!O|E9V=xO!4{CWm^q|5-;W{;m z6jKpK5^C<`tC#q@KYf2Cav49sF{GRpQ#!|A?E!vZgR^ zfN-d6R0aMz!Y4Jul=vO@?68Z5$h>ptSUr!USo++zLJ)62`~ zC>N@0}k6?K9G+dITtpa zs=}N~jONsrCXJG8Z%f^S1!nv)7N|!e#Pi;us)NgBQ^1jQE_vxNJtv8h=T8Usz1hR> zRjHlgthXr^QUVf-Olw1{6fse#$jWsL?3_<2%pTicobscG&LhMaW94O~vnJC(sKz05 zkJ|f&D~vQf^L1;rYubj^ZFO9)j}!v)&6|w!fH|NG1tS;}0w+$pl*R~lG%y@If5v$N z*?&w%VP`~Y6ViQ=DMM)%s-!ZI2Jue4ssIuGQttom^JjngCeoipssWMF3f(`?Hwv_I z(BtbEL^*X(T}l4uzqyo2{X%^Qsp0%%2teM0qM;A=0Vrh zFTZ=C>jw~*TVN3rF;zGxA`b9?%ZAvQiy_Jy)j2y0*)_r+l7mNL-x-#U&eesx0$-82 zg5&67{dMvFmq6&{9$-pOx&ekaF8Zs_Yil!~^&TWu<=)zT^q#w?7hin?|1#j5kbF8two#f3qTcBfzWjw8n>?81`I7Fjz7N#sY(aq&op_* zXOg*zny9F_4&Iq~an89OT&-QV{o$`3pPY88I(YtIPQ-b9xqlOH_y*{DokOt$@9?Mx zXl(auy)Lu&=F({z!hIV?ja=gx79|}MlN!lTnjoo)0#U_89OzV_VvrCe2B?Vx;lNIn za9h3i-KGBHA3nS6(Hqsd5Q8B`M1zqABa+|NVmRTk&HwRN#W7RF$pAnW8fFoktk+1P zXux*Mo6Vr^j$2R>A+sJ*)zgQt4>o@n8UUG*VWoj=K_(GmVy04I-rZd!w+-eWlFmoG z@jRMNGzbz96Ss{psER1fE62?9h7OYNCZr%Lam0> z2K0ul$@ed>o^P;~dw>4wdC>JXQbbjtst}TvasaB-z3AppJrympHUT24HI`xcf*e_`{9uevbOsS--B?Y_K6DrqfJyig#oXI%66NUe6>VI z7eftdy>9jYItGx(TVgd_9aax9G$&fex8cq$+1iPYk%DSA(71)Rh=8IsGo_5d0v(Mm z6O_QA?w2-lIHmjAFpw0A%M3Xcp+y0`fMnFw)}8&!H!uJ4{U+#XFmyqR8 zaNInH#>oc3LkzCtcaw#}eKJTbKgXzob*Ekv^q`x-P-nuVhz=LpG-Ff&0dw-hd4Tg4LkD|wwkDAYzib?$a_VZy^|{e%+xodw?6xKD*Ser^1EggL zAie&y+Nv~3e@5wnpj0tu#y|^<5!_O*(Ea|4C!5vdFQ4l-FC^*-MFoUeLi8Qk3DgV# zRn4hMV*W%(R6?2TPZCwv(%S}@3RT#6Bvy*Km0<+avLZuQfCRO*E*z=}BpeEbMiI!? zN_^#}iV^7KsgEmNigBf+B4 zNY{gz*(Q*#Gxd=a@V*N_$CLm0eRT24t5b>2GlJrr!JJDx8dq#lRH3Q<-W7K2TJFp$ zYbOuxD%ytuPBvg?(Ex2glE0M`VunaDC=I5n66`rk$_i|^ahFtJ?K<5 zp8ubJ!Jo@_C)_fS6r-3rii?(2vX=8>K@eHQQNn|Z5x)%AkIdo%2jEx^E&1-WWU=d; zP7jU?#TcQ>!}l^-DQLw4(n4ya?e^`m6WvwxDx*JUywp(YBRM=IKMvZEAy8JE>i%25 zR35ivgQy~^6g4^r?SxKEI+#byI%h_w=);Dqlh0r3fB)B~FJc$8?l-8-vJeFwAAnXm3Ifh^tkfKVbOBKKL2gsLFo{#rb@3KH)5 zRgaaL!HK58ngUWJ`)A|Oy4@=1bA^*l;tN$aJAtP9yv6lv#g9>O zKY(*1=k&@4N?%RxE-lhu%KbLKv%V|Z7=X5>^-FlQ0zlbKhg-7KT?(V! z9d}^HRJ83&ha4>mDTKDeE_jJ2@x{OY*~vZGbm$qWZWTgIWpB=GsLKjRFxv?Dp1gZE z;b2@3iyez9u5tbEbQDWSKU;b3@Qous(3&FL&JqQKPd9b&7aH#RvQkMq32f$D9C-~5 zt5dZhE;9jGs`X6-NI~dyBf%0*Pfsp3ecwI!^LLk@ez)1;gyLaz21$Y}p-HLzuUj$k zl{S}af1{*U6xD$#!Aed|5rrUhYcLr)=kdMMjHX{@hrBy}yh8;pd+vgwHaC7OmIZI+ z^}MyZaQ234gAkm%BLKZy4M9n_%FJn^&$4$y=nwO~UUw4v4XXU9ELdQkbU{LpEon-s z1p!~2Uw;4WGUDv(?=QbUzX~dH?=k;{eIRG(` zaiV0cgR+!XpT3Ttz&OM;-$m2g!->9kZ~f6Dw~o&pXa-fyX02v4Q$mHHkub{a zb@Cd6pWbK{d9eFhx@MLx#Yxu3==r4wsAfJobqF2t`$sLD)&LWX`*tp=N=n$dj0{Nu znsr^*M?Sxb|M17JUIe$zb7Ke)MWZN4O-Q-O%@+1!R+SlM|B<$1hoB4Z2lJD@56K;I z?pMfL0fq05H(78ioYM+ML~DVE>eM^@_g$C(j1bE}X%w1969UF3&z_xc;zeA4{q!n`OT3v} zi?w37S$$;Vz=I~@N9xVP#uTy1>6GaP-&XSzoUir$oEBa>Da+V;xX)Mliz!h&{G8b* z<2cM?@&k{o*k)b-$KRU>UIZNpFpwepJ5dY(%qfLY!`0(1{ObMF4!z1mGkv(6-CzAr z3b^An!A($9&K$^>PWd5bAVo!;Iu)TAEim?o5f%jIoFG{%3YnV*RcPb*$${^;+~gdr zR+o|ij_H~vUs4h8RKnFq5A}o7;BA8#y($0$BWqq%Mji6awiEk+*I^uqR-s#T7xiOd zZZ>0)cT78UWC6OYIhhV;#)4gGdw>Z7J%uWoHlWS{v__bhsX~)YK0R81Lq|&@MPMPS zIKNuG+}dBhzxv|2MeUNuYf}Hl#CJ< zvF*Y*UK?dUqI!4y^bhB>p1Bwyf@}$uF2GkTdVZ1(z+fKU`k0Xj5thcwVCNk8mIfbp z$J;pREo35~U>o{e)RJA-w1h*AA)_Vo`i5x7W5Y+b0i(^s@^u@95m6XiG6se7zKi0% zei5FBE{LiMNmVzC_qFA?4zB-f#=Zlq2csOHQMQJlu}v&qexrT8$qjCIUo`2xE6N{oGn{)Cr* z{lUotx%Av9q6&^d_m9N0_oss$90CYx^_5R~maiZw4HTA7hf{G1@5Bim;GL!hfGtlN zB1q!QbY-L}k4rWEY)>*d5qpeimWC%wlY~?sIhwbthwkdH-e0eH;n-V@5RJ?}@kz)b ztm)1(s}m3PipMN0RnIyrXo1XP|7`D<$z3!5ahyYZb4lzzhwZW}JJsq0(Z_gDi6#_6 zM@;le_a6ZbvqgVp0i|mz{nd$6q-}mM6E8q4Qo6Ixp4%5Mv8AU-gv3Mw%1Sd<)!5PF zTrNTTM{X#);qeQlPjgx*Squpz#6bn?E^#3Upx=hk_X(E=M|Y*tEt~)lUR{!R8<8jx zGOEMh>S=v@HlS?wcqtsG5K#wSop*QD|7}J1cmJ8Gzzr=F==)I69b2!KE)>BL87}U;X@^u6X6j1Ym#B-)emK|LwC(jDwi^w323))K9FO zh6K4m1Y%%xAS}D7KnSI1i#ulF$pG6N5!SZUtLzUw*dGwKFb9Aju9RzBy?@FNANnr7 zMC{EhRab$GBy6x5u(8&kb63uU7j#YRA5$WJrN!@xaj%nyy=S7boV`8j0osvcn-Huc z`X6?b1EcV-R;tn118}z1AM(hD#a*V4N!upYjojozfK5w=UO(3kwICEMJPs%^zhyDtv$W!dr|Ma5-Ofq%GQv$DPA;N-%ogYhD=l7j{)baFC+#BaWWx3tmd3 z&i+5e7jm@6k}wClKx{3huf||2*az$WSC4d!%asJj=mzcMe7S$jG+=kqwcq~#z@T7s zS~-xsjb+?atq`MGWO2wcGlQ|c8izcs!5!xK0mV`euph%do<>!Y7TAfc6>DyO{n$NT zZ8{01sFwirkrqYhP*UEi{y*D;$>ARI<}0Mg1j&6}x5=@TJQ=_RS(vC~+`aJt9jJzx z4LA%Tb*%I)rTh>vUh94pNrtPn=Pb5fBGa|2+Jjbqq5LAutm{@ZcB_*O^s^@~|KX2M zHgbOpHBczZwF9F`8+LQ&0)jKKwYMEA$v+cm$ zaSIOC1^^IA6M(Vncr!WVXx+H24S>uc#PzYXyRsS)+{xN+We+f*8*Jw60;JIP^eh8H zw6dsKx(gb=k`|^t@;aEia4QbNGQz-7ZFk$HsaX=69zeYB`fcBJt8E{|ce1|sU;p{jmyn>H zCC{#0OY^1$`t>UN*~bs^e+tW?n*Y?V36T5`^R^i+kIp$ZdfK1Dad+IJddbN!`%f-7 z)5+CaJjwc||Jnv2&W7ym!nEx}Rh4yjF<`g7y=^{78^9PzDY?mho8IZ^$tnXuY_WbT zuKdN6alvPBLjI}WwZ~d<=&5}a(=G^lb$|1_XHU1D zP%nrvsygQsj1_hrLHGjF8cTkedh!5Ofmf4U%U0c_>Qqnm;x#m6d9oP`)U8^pS2!jS zo-Ll&8vmzP)Ux*X6#WB~H!f1$s)KjYK2{g)9a2a7>g0kU8A1@%Km;bj zyohrG({S3KzcgF{Fx*$;5t;OCCk@qB<_xl zvv!pO6PeA>6Kc6oQw_>RXPO}mx(W9!t5+E?7UqwR0>zljf5x$2<-#aKn{6p>DGwT(~W+5h_=pIot1?+qfNG|NhW6k?bBU&kpKbv@r*^LNJu zHwlDZhRF3y`?H%2#8aOwP;z1g)Xl-Emv0e}IP0yChq2 z-u1x<=wO(|q7ad(Xz8|2061SOra#m`4#K;)s7Saw-td*aYvmIN4)b3Q{oy>We+>5j zN=@?qRerW~Be`0wEZWL-3Q^x(1`B?50sP~izj?lK-mN^usZ$j&Slp&-Tt}L`40KgX zYz$keRH=Xre4d8GLpFaoWjZlnlge2K_l?uvbZ#w15a#@2$c|58WBAG+eH{W^&P-0nV)J<^JM+KiB`@d)Pc7olPrv?{M+1 zR-JcZ7GsQ1=_7*))UQtO864CT5<*OW@@lmjZe*?b1=Ya(=$nr7Lx4R+@X}SZM66Qh zH``vFTXz~SpP$L*{F?gL*uNeISFhzMIeQsj>(syQ z{kPTqXRn^R{W5|yDc>)tPK+oFpW$*?`cs4 z-igHM{Q7xV{r7+Q>Ur<4Vz&)uWV&YsbctR4I%Y4|bsJlHLNm85y?=c@Wf&lU)4XUW zRG97XVE($i8v)$P!wI~qOHO4(O!mY!B0wy4=C`r|XiLDx2|@DTZz)Ca&Ia@y0{>G3 zJCVf+`cR`c>0Pc>bO<(QI~6@{o!#f^{VM&y?34fijWIArGh(w1M$-99Ir+OkJ^A#> zRg^QuN-0j1G!=6t;j4+isWbO%;3Jh6E4c^OAwH^<@>MlhfM;!x`zkRkPZ@3AHT_4Y zMe4u^O5*}dJww=9h#qP3c&$F+s21WzE8+b3zVcl4@e9hHy=I3 zFV4bRdIvh^5{E|IB7VO}TVEay9N$wd8D;LAwV{{pw^uO+fa%T_85CMiZKX~vtD6XJd7B(I0hSPVMMOtubDu!rI*TJ2Bcfr5?!`B-sEr zyZXm#tB@N~Jh5B-@7QuzpiY`Z)u9;FvG^}DI%M~)AC-E?7aVV9k-Fip*!78;YZph4 z#AudixC*6d=zX|+yynM`+?wYew(7d%>|X6#k7RBv6}Ye1AdTLrHVQiZ4aNPn>pE3Y zuhDE987QXS6!4Hvq9B^6I#unQ@4OqxT;*z55+7g7ya){mYIb0&dgF` zlrpS&{_!LC(1(>>`PeJWXuZX42*zsnBr_1k8`ySVyY_eX2Hc+|hgMxfw&5Pb1fXou zEk&@tH##;HYLx)(PiPAFu?5f&UOvc(wX_z+?VxQoa)+RRQ|Y`4Oh8p1O-#I;Jo@jy z|LW^=M0aA8ZEva`pv7>lq0Lg`_j)(Qwg(vfy5@O_|D5Xm6pl1Q3m;muyK3XMmPjC6 z1JOltVRL&+8t=Cu0+zX^H5Ei5##;Wlq>Q*bZeiKKu+@t+u0GqIbu!TTLVF{m2{$Kr zt*ZT)CHo+9gQGPAbz$z!(D?v;+3WxK)AwJzkSObD3zVvGLYPWvTUjm-ZaYg0H!T7+3#|IuQHa>)*zub<=!+SsTZ}C&Zes zmIQzb1czuw7{o|nbn)_$Za#VF-s^&f3lTun%v2RAUKcY8*Mo^&dj=-ccN;ih4Bvdv zj8biFMBoG-R6t0J7R;i7fe^2~;l(AMU7!cx5Gka@KBg4iS`R{HHn3`m^>l+%yx-7f zPlj3&Fq;wL)OAK7Y_0u$z546N>w9+5aoZ_qQAE1cNgv|A&VPLI98)9iS%2i%?Tpv_ zxZZSS@;U`T8oDo3C$n8y8$I4Uj$$9wN|HFCrpu^1l>rPKeo#~+_uShtA~?Fcb584Y!KtpU#N>3%J)Q2DKpX`NRM%F+$)otEDweUCdk zly~)Tg3h^g1sD-y92Y%&CvyO1{;Fc~l_vlYdZ%}-?K{yE%rY1eViZxKkhUZEuG*Ky zOQ5X9as!g?{-^Cr{@Qt_8AAwWA<&{*fBn4w=YM^29#48IM8zw`Xwd;GNj-WMOPI-v;q7yx+hm*D(kaM^>#|HFg4*ptiEUTbd7st6kR%Lk%pv!& zUhj_EbTHALhm#l!2Z%q?>HRTfwK z&TKXh5u*U+6dthqr}EK5edMm31@BhrjZRta>Fn*%0PM$Qmuy3q5b=Xw+Ic^<)^DJs zSx1a9(o%lilOJBZINw}t1 zbbwRmL{rcqSCP6FVZR=eJ0mOb82?~u`V0vZJpCRou-GfwtR zHUhp|Zv)!k1Fg3$DATjgO)1q8A{ z^nX1YXUbS1ji~#9uuQNy$>k%F@?lkb_zRr8#QiTX@Sp$bv#p%LuL+435)kFRS5;$F zmxWvtAit7j$6;QBv)&jN%m&+&im_1$p#5pP&OfrRKw+yS#zGSC5z5ZjR<9h3jxRRyF=hB88x%xx|Styn^Q3rhr(Akx^n~P@*%QV)On<{NRkPf7vMj21d8?qCQ4C z=Tvn+9U8cA6R$#;<8UnRI}*4 zhp0F=)*O!0J(i*6BS$?4Ly`A%JL7u*zLP#|VOaUKiqK5OIan7j-#@Vr?(u#X)Otj7 z;vk5K1|tQgmirr0EMHNDkCHEya$Tj1s$N?AFVXAJ)p+wA^*T4v&IDj&AyCysqX}VS z8!$;Pkx{sKdpXzNMIF!tO6&63{4|Ur4hxVWZEFEYH0xs@VbXOg=M;$Ilx`JQ5B|UZ z^p|JUEBF90gQ`-^#DpS=`BqnQ5~FbDy5ioT%9kTQm~1{vqIR3Lo>+S|3puCah%?d1 zs`?!q;n_}Qt2NtQUvS$Fr*JN9)=D_DG?yMuvrt}Tb@=Hu0FuH01r*KpkAxT*)geSx zJrQaNB)S`M-LjUJlD1Jc&hbiUpcRWBCU~b0Fmyd&z=^sQ0n!ANTz=K$QPFZWWP5+^ zQd*bHn-`aF66uv%t3)To43V@HDyeXQM4-25LI}+w%(5r2vA zm}zeaFegzF9SOpSKnp^O(1d~3n}x_o_UzRYVY?2OKX;q|@OZU~=T3TPq@%7}%sQ?P zMuF*s?XZ&sJb|wVFk~EoG3QS|qkO18*;2@AO@hc5ikgUsQ)r^Sh{VFI6GCaC>5>Pc zTV2V?m7Zj?f&=$h;?&VU@BLGb*FszSOi-iNa2GwKN=v$r%{o(65IpCr6VyqjD;Rp?YyvcIS12hrvsidLaiDIPRH;z~LfTnn_6n7VD> z9Y6hgiAFk~qS!^(pHy76=vK< zVs-Ynzx(sk?dlI-U;h4!7aO_P!}YOG#?=n0X^T`T1^tNqKk@^u_d|RR+ zrwsmz^f#d0jO+gx{Hu;SHHNG<5)~b6b~^5_;}2H(H|PNltN`NzWj~-wOajfO7g7$( zg%WC#W4|o+r!Ji0@;`p~!1vErYEDaI%DmI7YBp|?MG5RYOs*N4mxZEvczL|`bN*P``Lhj+qu zLb%XcEZvW-B{6oee>A;!YYjXMAEZI{CNsbR*C=?uN~=n0A&KFq>4>aYX9YE~F#D>N zX2S$gVBU2>Ru?$^r_X=*`+xoJrLCzek|HXaEH#td10*c6CKb1%YT3zsJ3iCxnC&T< zUT`$cZhNnx2veaDX%({RMOEer)h%sipet42{98ZRG?U_g5zIj6NgpgdX*R5Y?EkpoS3>4V0_y3@l17;)vLjY%^jnhW&i@ii0nU?-V2P{MN zKLm?55MzDvevb0-4CZTbonIp>nj}mRS7M$T=^`}%CJ>qshydwn9_EY^1OY(wKC+9? zK75P^r?GR<7%5(*6FLX4OcWZMBmwXL6OQ5fPq6=8UeFDQH@gTrj?js|xs$bD620Hr za`tfW3a1Xx8f8raR0nY#^!>B-$M3CW`@`DNB4Hir14CeM7E^zn=pqGy69r{N5<7N< z*{vh5OQk#Z4VPn6VCQBCLqPAWLSTk@wfuzk@pkztMfPBnyY!9Hu6`KuP5>&@ajjTU zX+D_tDkg+d#G=IL{prgq_nXgN{Q3J$FAfxEotiW4quUY`IyEo!DAIUqv8lt!@-JieuVT+UV zUY}iTqd2I`4sTe#r4m*zvbd9)B%Y*Ybm^=3z<+rdvZGk_0#n-qlPjszo6s0tPrr7vqC&^T`Jt zw$Il-;S&x}g;R4%k&NOjdj2d?fN+FQ=;RFSX&Y`FCH5L?mxG3v!zEj=xdlhs z6L-9>boVwna37WYSmBNDug1ck`H z7kH|en1~5XMTO!Mv`#Pn!KY8dKY#ke%iy4E1SbK87!eX9OQ;G>O0RtS(o)Zv9&bL( zOXS9T(~;|(4hl%AD*V|W&O4m+mLK(0|C??AFc|Pvy5Zfm@vb!hZRk(Cl&OM5I}~2J zLPi3_18Xk#Eau2?jD1gIVK~Cjga}I4nVXFS!yCI4bpK z^8_ass@(9Fsb~Xt*U#xc_rKio<5IffBbIq+0(1b=+(S4C15bnU?xdunN_ukQ%U3e zO1mF0y1^`HanWliU}Q=H&PR;aU^sWjyEg$izI%K}8vrJjbfFz5xJ3j%b~|);y!PsD zxY+9ifTZdkk9ki1J4paoSZc3#BQ;FxB*A5w0Ay1jC(0OUrmBPl%F9js?AvD>IlHiv zub*87S?TJ8A_lBis}Y|*?~7?Ste*X7H@xN%3>F!q$-rbpF!+UO>kT?vR*u)2Lbqyd zwr2}3Vu=9oWXeJ^_ zwxp6FSQH!3V|eN_B`*&9X&(QE?8n-#Mb`uEoM^ZUMwSI(k9C+nT$`_$uiw({s}!dx-3!yRgX6W`X@DHp z0ghWu)&`?`3Qut7R>{yP;M<52&J8?=^=(iIHzsDodRQ4mY;*-8D(WDv=p&O+fruJB zyZc`~5C8D5-@S0-9o>8cJaf8mvZ*|&%O)pR90tKee_)yLf>p`N%)&9MMcsB zNNNdm$Jf6x&*l)ClXhQXYNCf+{bxh&nfi=%m@duJ4nnGBZtxm_{$o?UUeyQvD2oIN zDZL?pBJ^smx>XrrWQ0XTLxh-8It%Zu`j6hz6)#s}N_g!om;$0vG>9WKmHtk|sk#IF z=DC`DJ@`;KnoTg&6)yY5vbV?`YB%HYD z&2EY62>eFYoRTl|bhuDDt0h*rrl-0*U!#3 zvOW*)hfBMPngjqM;=K!DD_J<0SgNcUI*r{l8~$s7>++V_AopZt>FCJKvvLtw*teK) z0BST+_JVL8g%fiM?(`>^hQH7dp7LqZofwlaD zMQ{BHHotfvk59~_SJJBo;UxJ$MW{guWr61^UE)C2((H9QKLO(n;l@{dZ^_sHGxwMN zM-CR2#M3hNr<7J{3RTh6jT62168o!r9`|th%LlHrm&z+4X^HuhT0z9z`X@iWS~c$p z9F!yf_C1ks*L`D?9`ssQMZHXi5y1}bFzNvWqn?4IZd-Qx{0#P2`~T6O)!IX6cf(ru zXcH`v35_GGwA_lMn@)vFDpkb+Ah?aeV5$O8Rb_Sh-KG26KYn{DT`x-WLI)u=QX|xu z5=WWy|I%M(DF=qv-Z-vR@J*^4nam{9NW8g5YC<_i^X>6obyxl0(o%`2eCQ#GgRD2$ zFdXLX4+5*b?zridTB~fgTgwx6cHQ0OaVszByg`gpz|2fl&C-+>>Jeg8)wJL`R}~-- z5jF-vxgs9?f!M0%C;R9u#($)RXp84HccOs?uuiIJU6!p*pXU zr)5M^X)-~{{lM@N3XTPq`Eu;*)cCx{nWcMeSC_V@?rGBxc7MelNyFq`-lO`(oh(cWCaJ}xh z$Fjv>XQPD=BFar>-LWpZviDf-QHJ|bh8JLMaXG#Ya}O{i_BNNUmX)XEV2^qLDS^T5 z^3{+JhqcaWjv>)O0mZR|DXB3`5S_5NtBELL3@L@iDG&q1Z~epHeDVA@Up@(|)4r#J zngx>>C0GipNp^0@D3sC!&rFvZOwz%};T5|#MYif+IQ7GW92}o9rE9{X)eg3@ADExk+rM$JqDl zt_|BX``q}~F}DG$_4@hCmnJSq_w;=GY{Qqqeg86C2HBc~tWztAHp8xF2}G=+Iqe2n zDtoB`N|j1GBz%qOv%`&Ao%=Yd*K3+(Lj`8*_dkvZ*sZQ8V?ND?K}7nitA{6U9bbI%{^|sm9kvRHIEVpO8aD^YT=M~rU2ssr zvZD7$@xw9i&&>p6iy^|xRFfl3x~^*p^Cx2L%H zt6!Y1alU5YX0z@(l2GX_ra3_3g&XT&QkKP?KgFGGwg=c%-8BDf3vQ0f{b7kti%BWg zrD?dwbH%dik0UNx88zEQZ%6{JE(OCxw5*5Ow;%$MLMRk)K-c*M|3e@!Bd)A_9#?<( z=EakZ(5<4GI1LuzT(DRJSF_ryuBNZAusaNs4R~+U{c`95P|0We%c;Af>fZpW`gV@D zKmoc7t@yXs0i?}Chw8jyX2TZF%)j4-Bo`1AnR^b8Uy&EGT1x0=+91kYB3N*%b<}PH z|JirXFJjlb`=5RHVjEqwL~2d-IyF1iN%pUn>eEq^QZqc3`9DqdKUM{_iNDRDAn%cR z8!q$oQ6V?2HCbmV$XMjwewZtcOu#NWzL+Xj7zO4E9eJ zrKDfdvEFyYery)Kb{TA_|M|%Zb#O{iG0{k8P&%Ol8~~cZ2vb#67e%ko{qBnwfBf#U z_dYNhg{Bsh0*g5fzRVfS(iSx`61Y}t{puDjt$R{lwTa1gCwIi?cd4>Jv=O}J<86t6 z?`*C94YmQvZB2%~Gc9eSlu^!92F)N<_JAH^e&m5QdU0`=!qH^IK?RL~^F7`97T-SK zZshdam*LrEH1QB8B2GnMlAPw4C(}E#a?z1>PbS&w0Q|Rn*}56Xh{@A@Nu`POnyT)q z=T9pFW)+n-|E(OP>P89~9Jm*2wbzdHUw;RkFa4MIZxLu}KAGJk%}b24E*8U|3zXU7*UXs3V6^YMV*Yj2D^(tr-i*Ab6LN(rNgrLQ8le zprld+4k^OJl5e1hs5*$6uD*GR-+cP?>4v@Qf{Al$3v}x1P$z$qroMbt$Ke|XS&p)3 z+MvcnL6h9C+#UZ0%A|h_4Zz$Mz6fO89q;6Yj^g}JCMnG9>bV%QbFg-7vR#f04$E5t zQd=UL{CkK*9k~i-?&R}tpP%>c(pH~+^L%TaXy;VDsxax&%!xRNz$si7`nE2gjmO2( z{V?R_U_{DC&i%=VTAP(oRCF!jyWONSdZ%*=d};7;EM&30qFV8olJv+C%`toMVh=z{ zvUh=*FanW?Gy@?nMst9(Z5Lns^)K$N?RI0z1%jj;RuNH!Dx8B$w1hT-ZHb+~ z`^t}hCwF-@Zvr>ky#){c6*uSs_PqXC^#YbP54%4^MRGoaAT{Msp*WFF;L9DIgqC)K z@W{na-s@KOV(p_UopUJ)zzjwuT=wE(c8uSBk+13r^9HN`5!3Hzg+Tr1RB|fJOqt>f zRMwDobTHx;R#uPHp=Im&Q=`xa?qd6+bkr(n=2)uGfl45;fKm_8iTWh>hLR8%p&Ok2 z@#~8}eRqE4P9s(VFD7Z3PiPH=5sT(O``fu!Io-Sd1iR4HaCO<8A<8>@+~oksVkLBU zb-X)$ZA}5oY-!dS=z4gt9J%8j2K#qwM+_4HniQ9qR2>V&zr5_f{{98sy>FjhzPv(| z6_8?}67z>bD#WSN0yF|O@N$xMUkE=sni34O*U@*4DuA(Obm0B#SS>JA|GQRw^?U2z zeLL^C>syL03sw1(P)HG0d+!&7e9NTKf5n0+jKO|lyOlLfkIpqNh)s@aS%s! z;wBUb;HWm>b@_YF>Vs#0-EwZ%4J*-O=tg^*f$Itk4s)L%?Tr9UII%z-;1%9M70HNK zMPw~-+w-5_(_cR77|zMC?SrZZ#Uji!F#5eOvMF*2{@gi>cTPULD&YoV% zZ$EqT-AglBS)dbTNE(l1JCK#v`DGlU{mcfs9l7@%(F0)D=5C0n0q)$=?~Zq^0iXbP zK>s_`(9RB0uZv*4uI=;S%DdA8&_E`0XiH9>Fc7MN{PfFj0(^k~{OhMtR_aegv_^d; zv@nT71=_&>3ZMktunj$EqrU3qs%WzT&_v|OY^kR+_W#9-bsvXkG;P>1UAdlCXHU_2 z-Lm!7Pxlf9NJ?2}fQd$ENGBH(4FVO5_fPcWpPh7kdE%gCVg);hr&D&Ir#e%CM1gsT zgVs)M_Z{2Q1|0K79aAXZ%%p#hE&UBnf?S_1b`0%jUN*fDtXBO4ipQ1a;5~&2pq+?! z@D7@$092(qXSRy{sa$>d{^`1dS%@(*Dfvxe8V{AM*|tNTC75Aq*Z5`^x?_5+23d)e5~rAc(|z~oNv`_5vc zpnnQ5$e+L?XS+ACwu+kc!4w*%F*YhnK09Z28DT`Y<)rOq9 zLL|Ng3h!S;iu*m$81PpHzvOCOK$&%gpSByUBIDwwVELi?WFsjs!L{h3 z(-@)E`)V~0MLQGE#l2J2h6SXms*17&s$}J&iX=i(TlVQlU^nA3evFKD{}T>!wK+b} z^e`=m*gm=b)0kwtOiB-eMk{|nI^n62N~aa+q73BL3{Dkbh}#$m73mPc{_;dFJ~+Aj z@P2$C8`ocnLYxygK+G{ZLa7Q5aRx6=RjG)|)SRh^iqpNZwHQ0)i%4qB>PK=uaiWXW zo3>;H4xfx`j^@2G5z?87B^5Iu1T6-EsfVR&*6_dl`hySGo5%X>KYsKeYc?aq;Oa$^ zi1BI#qf#lZDRYywA}voeI+e=cuCKYKT<2Wa_G71OS{j>7-sI%tSp(XH;;AdBGOAjF zh^Ycm2T{l-#_nXLwz-e1zk0xrPlDUNTssLN!1^PBs)}kEX;gL_|%O6l)quT9(QM zp27Z#ujfmn^Z+_Z0#5g9St`>zt0}fO^{^?wO9M1y$|Xf927@L(rUF!$6H|?m8-H?g z8BhQG&DA$A`b+V>x(Fgh7h~D1EJaEg0Vs0-S%@`RT;2B0US-mB9s}VNJ}7H0a0DS(cisJa4@_5IJvqM&s_T1wh-D8; ze-I0Kf2gEuAlKk>4Qc%K2IrsZ4m3FTi|k@PH6*y14~*U#ZRxYEu}_nfTIIsJ5K#I? z@x=r1*uj*Cq#7A`RO3XQhfBm$$$Ev zKl#7>um9m!zj)vTA;PJ8uOcvu!#$J|a(5UB*SQ{e__>_Jq!&0;JEH@p6Ps~jie?+i zbP_Y2JT)HclatHM)ycYZwmq?nUq3#1pc@Srst9Hf5$Cqi`bbqr+nK)@M~(Gvs&jc+ zl=+Lljf2piTcZPI2Y(~cTcT4S^_G-w6|X>ybA7&TD? z%*ikpP0Jhy>4J%1)%nY-O+dHR(@&pVhVCqi57FvsqR4ij1dmBuV!J`{h$qjznH){z z65yiEwV}x(qZ#6XdrHH-=6H9`qfo-(14c9u?OTW>c}P z9Qz0cK@=CLSC^M(r}sYm)qni<+0~{u6*#4^*HTuc3A7U}wwsA&z{cNmz~PGHwaAWp z%*4)r{MhijFsOSMt>Rl+?O^O(zq%Z`I=?iGZB36~$y!YJT3y7E-c8NqXJ#UllXO_8 z3Tno!vCkGyLPkY@Vwb;q|Mb06^@yS_Qk=M<(YXGBy`f;QrOP^O_FsyLiO~}PGczL~ zDfc%71F`DRx!e^w0l+@Ql-NBkG)hveyq*Q&_-F2qL|F6&-4iMds7N5hsRJLZ}6aVeA@ZwUs)me;D5WCJbgLM{YEN^=$2&@A0+B_ly@Gq0pt%3Qv zGqSJWGFWho$M>UZb;9^Be*f4pTovsCc!W^La3DnlxU?Nm$00Vd%^Dm^V#W&|QF2zFaH+K_?#6AQ_#qwp>l}{SPsNJE<&N|)84;Cnbfuh|Y zh&=jZyjyW(qB7gCU2i79Q6Dh8>M<#{Gzmh&Oe~7gQJo2ly=OR+?O(m`Pr}nP#7@L4 z_?086BC4)M7MGfV{eCsG81~YGd!B#&5CBQWiG`Vx1;OPfsEP{U1f9ytqZ6*2u98MF zxv4lOsw8uuZZU4jC5qt49$->d&OUOj9^jxO&@ml?ia6&;u1?mZImUa=?#snrzrQ|{ zOJ`TK$V?kU%n^S=$(#{R30zribmLX=y0^oP@5feaap(k5n&x44^&XG~ohAcJ1_EeC z3Lsix(nz5_o=@%umLt3WOQSO$Vh5y9Yy{%PGt$VYot?b@-+uSy^Wa_vHAoT)rSV|# zXpp`0;ln8Yt3;R7_p0uOlfan8pM6LCxhwr|X9KWry}M%ry-Ndt>fhgFSJlmC*~Fm1 zcW;)qb3Mq7)Eo&*gB1+hBK6!>|L~{hPtHj_-S*L|dhZA;z7vJIT99}h{x%K}7g54V z2ly&8@;P_}N$U}WNkVWN2|TX;%bqu>{#)!HW1ev%?4z_?+v+1UMH#QVLhWQTzowgd zO71U}SJLM-on+ROSoU&}J|J2?QAUE{p6@?6wO`y8N4&yr{5 z!BY5`D*1Zwzf}0Y=`Do-%}7h`DGD%#ZNJ@E?8DV1V)Ux2LRw@@D&gE7myg=EAM@gI zw3*L!Lyq_SnH=6z#S#%S9=}wMMW}_s#>u z`>iCG)~LPj#;e?qlL67bU%fjAXlw2fke?M0Sq(hk6u=HsaS%z%C>ywB61O%%dDX&@ zFILydv}`t}qOGJVp-L8_SMR;wMqXO?BCh}TkKb?oJrgIp?F|nA{I9($Xw&Y;-!d2c zx9GZcHvzb718z+Nu*cQ$rghuh@sld{dFTNEkU($0G;4jcan4;KuLs=N5BxX(O=-S4 zLRe^GQOOAR-3I^lx1V2e)kk>mNvf)MK5e22N>xa$?{fx`pnW6-1Pr5U8U9%^FRRSA zC|w)cMoSrzK}lJv|H8Fx0keiRghp7*mboK@F%%O9@e!eVYw!e zEC`O2K#f!|3eAiT_IS1V^Db~FdUW*lK$a}eY{@~t?Ycr)ga zG5=c=^*=RE*?Gw+JEte>wG*X9(kSH`(_HW>lO+i<1xV~>%k=T@!_u34Z1c0-eqtIkNSvFozCVgoW#mx)^2~v_>VRXkCLS)mADq zf0%Rt*@h@TlFZ}OyLEu;-N}Fc&1c_j5!lfPGp01~6bQ!Almo{l0l%&ts^)^%xy0P% zaaZgA+o_@^{peoX<=Z&{xFPm)cl@-ge`%Pe)#Wu;*aHGIxJk&~<#c8~@P_(Bss2Bb z^Z-;!r0eDM@BZ||_k9<1MOELel1Mm)kX6Gu$R^uXB)6Zz?4phZ3I;Dj3h%JF7SkS7 zwVY-uKPPy6<8Vj;T9mdln$q*Z3ZVYD+r@nBTx|`b&pDFFU?YFAS+> z+eR1=sg@h7sO(p=d9>R8{2nxJoI;eobDPc9J8u?SlEjj<_s9vr@n!u!T%4mnY7b3r z^evRRnarTbPkeY0i7_%7%~CC*swpkChEwNoYYsn(2MXO+UH^|HMB!-S(6sj;g!I1i z&a0|85t!%pXQzCB9Xnn!TsjayA4zqE^grEvPRs=ulU1lUdxMpEFnhH%TU( z&~hrnP@2J}HVNeu-ec_nvC6~5X}!6B2#vw00swwGBnU}N(FOLb~m^3p$N(UEqe zZ6~LkGjDDw=DUOVT>?6@?~jELM8rt5xDsVx;K_IA_?zEVwg91%n zeFe6fN^R_PfuZ`(*-DbdmV+`_8?TIHAd)8)IxoOufKIsH;Bocz~+`t!FJ==Cf_156-hsns>JI5}%eeEox4 z&;E-cZ8y7CW|>-MP*su^W7l;SA%K~wsxjW7rSHr^vKG1`(skXB`+9yv8&Kkq>&xA7 z+pqRr0CIw#9oH^j?*=;_sv+RK--ceCqiBqbTwTi9|M>lv7g+bwQPqT2WVsb{8oaJ+ z=`XD%e@6Xlu-9N`QHVWb*Z*quJmTuK1zdyu4__MWS|;t+^0_z&y&r?KUW3ojP6K$8 z^SJLzS-QJhMv(nu~WYM)#I*^ut9!WU#DoN*s8EDNOc8YBIm}`L$?IM@-}E~1nzw-qo2=C$>B`;4z2YklV=MdYr> zeTQ4#e5obuTm(RjIOKM=7z%scDu4F%l%FZR5pESlBlW76=pTG_f&b(8UvKFXSd@^d z6c*-&a4w8kt)q`T2d{ceZGyns+~1*Rs0`OJ%~uAmz5MMNQ?KzbEkZvr+S|4KFNtGE z8eG1%!lI4pIuyM#d!qN9WdVSM<^clLRQ*R|G?Mgcj9V4Bc=fAC_~luD;*g4e5r}#b z*G_A8TYz1df4}u-yRz@s4Ila5?)laGI=xaORqWNw#Ho?uT!i*f3@!?;LSeax<~(WR zaOOnWgp$cMd&Og}oF(P-5?5`1G}zuzKpVlK6k(2%g$g=^pRKl^JQNKVDrD@z03SV#eQk2 z*)tQk$(fuff3$r(4Z;OuY-q9VzbQO+cl-q4jGq+Z{Uc8RT37hHNx*Hrrn%2(vhEo* zT_|O4f$g58EqCbE!T$YgcYV+Zs^3IzBDp#X-Gg(;fBDV#FYL63AFO#`fHgZ-YyUqo z^4GTdmr?a!LHc&jtKL3Zc^;E8w1fc*S-nTwQA(TOQzs8Hr~-(wdiX#w!5e-w8N>&A zfL8%HvVV8N_yGf(pC^>$=aj4eEZMZMQqyq$aBZJFTAlLJBM`BQHEQ*bafBP@$SQk^ zr)xz4Tnql+Q@YLkz(noHF#yHKQzV35RYbC$H4;>T10ARc1Oe|mHp<8f`PK_uA;_L)PaEW}PD}qjU&b-r6K1X+Vl0OD>Huhi-`tc;5;J z>gb@NBxu3@I(MyWvNj5YdKaXZW3oEOy?^-2(-$_l-NorCH5r1I~5{r3cud;Tl=s|9q)+=+}Jy>-SgpGEmJ?4G5mVSCE40v>2vKBRK>lK=dNl`C2k$7MGzy8_Tn&%z* zTDnHdgz*VNJi0g~CkoEO5c`pcV=;bW|NXdo&(3`=SPlYPngi52US+^^cHAAxmsBQ{ zl|6!@`hx2k)RKj=5=vO+0Mu3}+}H?JcQp(KpPJ@-CjKI>|Jy%*@x@ETv&S2gKK5po ze&qg4$%7~EXvAtCPb@|o6@^W=nU^LS<*xdF7mh~u$RC~f@}o5X>9$GZ^{RupJ8oYO za0DEZRy5~a{f-z3BoBsJbmSV~%JGBR*?zz%;!pna)p!5>cYpdXzxnF_`8S`PTeqb* z>7Y&_3M!(LfkUrt_~nG^I;H)Lkp9N}POy`FS&TuOJ-AK1Df@>)TF;-lv+8_}xL8U~ zF;@=u9lQ1YY+*6$O>+!8Wq0#BMiAL*d?(;*Gg-1|xlm($2jb-~ALs{X)}e<5@1Pl~ zRE0P|V4{#ln0>JB-%rK4L6q-x-BA~RY=*PjyHfyBmB>g^okSuMPoLp0pZ)NsPrrZi z3^_W?;8dNcWCJg9m~&y-&H30IfFtYpgENF9*=uv{v{n|22(uezzWL~#NDM3VKRe?u zA2{nTREEAd4wu$U{Z~k62MWaFfPWrba@!koe_K9thmO+#4mE5u!xEj!u>R7vj4^Rpd!#c0%@dIOMu zy=rTPdw0CUM?(QZj5aRguw)Cm$p zfJ#-Uiiuc;F6S8k2Mf)~yRnq;dVHb$3Yw?^{#Qw$bncYQEZHWdN!Ax%e)Huw-+l4* zcb|RvRfu^u?bMaQG)v`$o4uCfQ_pVp182EIhY$5o6*X1MoRj2Z!>A-FUgRXc{OF;( zxAxT_6@Zz=7>#Icj`P}e#N_H)kcup`^t6#!>+LQn^&sU6N%WElL zqRtz=Z(}@~ft67npYDF5+Agq#^Tr|^R)r?=8%<1<;$sl?_dk0Y|KU&HM&~zS>zz-z zj(a8m#{d&YqhzvYajR~4PSvT_#eeo?+#R>M0buq)6a~v9U-)D7a&Mynkol}A0idAE z&gU{XF5exuc^=R@$FW{!M5bGS0OC02g3NrLnu%UaHm-SBr1e}fPAr35DrNU@;+AM4 zThT9{zIeXXOP+mm&bWH8rKtA}UA2O37<@bnQq`IQY2(d5opB@o7iihISqqllf`Oq> zY=30x=D>Ei4c-zY%ive`ElEiWLGV_D4S1jFRsRiQR zAJr%{Wia$~&Z&rnl=z14o}F*7w$;6-=NmI-V)fyI0G(7bEuOIoYeW{LujqU#j!)8uG0LCc+lV)Iu4wO~~F#J^mYkx=p$lF0C_iHQmt-_}rG$fDV#*uvO z=Q_<%DIP>A{W{4y1PUU>UxO5MtCP#E1pnv{U%mX}H!pjC@BAvLsv$B1Fwzz$Y`d1_ z3wZw!V2HjPzMaEc%Jd&GK}?$m1t1K%88Re_E2sj zqh`lu(u7n}GH}aOu;+X(7=#la>-;&U;w__@MpI*r-m(mE6ATuNJs4pCm5{CR+s*bb z&o8&#;}`wO7vH>uKZ)W9DuS{nO~i?G5Qh{2CQM!yDfc%=0vG+6jy5w2s7$sP+0w2t z1|=}Iy~{>}No`Ca({D*Ff{rRM>bUN#n{Lt4<&U8l!XT1MBE0-3VDRPG{a9LsmW2c) zIRx2oyz-^MR4~;{R$uYRKP7`-gQI^bo{Xd*hy^hUlhp?;8-MqqH;2m@gK7kggu#ca zU;5|2KE1r}gT>x^M>08J0x3hZQixrP{2wDNojB9)nFFMg+Y(O7>YJU|>nHiWtN+}2 zdmB^5shwOE{-UU33|3pQq>zR|NkM*U) z^=7Na3EOQlt0^x~)4efqo`=>nS!wk=dW4js)nH6qnL?DcW!Fd-?95qUHnJ=Hwan{*b@?FsT0z1;%~YbTxlSi6^8k`9wI@? z@Ux^bPF6?-l&tH7PQj5Tb{#_sdz1(@6)H^;oCGI95c|IOC-<)8^vf6WU;gEX@9jbK zYeVSmO1rfAI3Z#mNEb~^U}CvfP5@1M^GXm&zDkox-1x!zLDCS@ZAcbdr*vj5t0|xw z1ed)z=fJ?Y={lGoWCyM^57G1zvnO?aJMVgc+gB!;N-U9euzuy#BFL=Ns_HADFl83L z;fna}QGmu*Yg&=v6`EE}A{gVH4B+@iI=8#P$* zLLTb=WxR{b^-3E|W~!-{CTY&Q5J|uO>e>0Zb-mvI;+vP$(_l(b3IwLGQk!RdUt|iB zNz=1ew+dj`nJ}c)aAep&SgcdWCNvorD${LbzRKY8sbdhXCWT>1Maq``%RLPKrAlJl z5-e&`hv*a^JdBAnh^rx{MDvc*KM}FsuS8u;t8+*-Oo<%>y>A( zWz3?^t2#yX{YO#?VoW?({2P~xuq8?5{x$rXv@0ApoJpEyvWbeQ13HC?Ac*UA)ypb~ zFTHY8n@XWv&#)u*8_-~(IXvneIOa`jFZEQ}PbLGqv1`MIH{<~1Qa4=*st!;CRK=-u z2#>n{3t>oW|Bu1FNYL~E1?(8Vs+u#vjMSvC zcEEY#u0)Z;TS7<|>TYnRR1{JuNZE&Xcu1lc9LM`LUmj5_oP zkD5KDN&EC0Gs2h8CR%pvQi^JQNF$X^3n(;+5wxfl9YgHY#b{ozvKPO2sP|7hT1*^| zdLl?xcmGz_fg^mGFh}U$-w7O9_rIwehByC>lZnuc|IGb%s|P!-r63O2bSf%BA`m3> z>GRDW{_@TD7cuCG!ZAbxsZ!z?gCb@hQOiX)XEq${8IA7t%(5q-F^l5T_>|tc${FJL zr?kMN&H2_1{>9FySsHMicw)U0}0XTsGr9JbV*SduE zAq-%n=mhUOCIxn)As&EFrYR{QmWy|iq!YCmg+c>VHo;6+UwrfIe4_zpUwrdCvWs-8 zUL{-pBnWk&t|r&O0sR_0E)*lxu;Td+=5%$#i=xXs7!ua&(; zbE=i%V`e+mgHAHQ4!+uJB?BDO2E0+x=Rq9(zyxEV*S&7Hu*)2~S(}7q(M3xE+S9g) zOojR+$L_8Mnq&XbeSN%#QDIz6(!Q$i=Rlm@E#ff) z^9w|mZ5EF%;HK3^qGK)f05@(O**Ge;<|-2hCoyVyDut=~k7hH*d1vPUkh$kw^ClyU#o(Pi-kX zZ0VCj$no&c)I6w)_fAzj`}bG<$MP!#-Fbp==XBJ3fMI|j%)+f^yug}pJURVdoV&F)GVRc%!EA?)b?eq<{#b4YHur>kVV@iIXklO}7DW zX96(8M9eOXmFFag#ye^It-iRMM6OYpS|$J$#6X{d0LE1pXEvAFYiTiUDp&tSb51de zS<>Daoj5atXm1i^^_Op+o(Fds*I#~r5wMEr#CJ&GU-pn}S)@b4ZdLs@UeqH_PQ#a- z46obi0a~|>ihijM6A>912USe&I6!(xC~Liaa5Kn%ws1KB=Px88?cK@520izXJvEs6 z=e;~>q+vh=f+1QW@GA`-?Be+^?&~ieIPG6LMyFzCFjH0UTn^eyrw~(I5euT;gFgMo zMBeUJuCG{aU)MZGUN_0|#(w{^FKMYW+20Jz&IFb+9MICvb*d$(*IK$C9m6VK{NkQ` zaB6E@TI>m^x)3cG`&ylGe9w(10LQce#}LX39REftf(Z+8Bra-vy_(=(HmwN8`2ZE* zlfl7kjN*^ciUB&A%w=|b)sQIqipEbl%jQ$?Fq8RzrCVwe;4?Z+8d^X!&|Px%*$?4Q z-&|bA6?9E9#=d4mm_?~VOt1!!x98`m;II**xpO59LlwkG%kjzR9Et$p+Tn3`$4|dZ zijirLPx*{P=v(OlI8x5M3k|?b4VP*(rx}@rs1bJ>fLn|6k5E)L+@A{Hc$ct#km#eu z`rP8;Mrq|z%N0iRl$i;;A)CWM$Vf?!KuQx4CCmf?-PccEe*bd2b!T7waQWnAZ~ioj zr@CZRA;lg<@_$jJx~i4Zli{eQtk=O+TyrARh;A(7^Z*^I|CapI?3YdT-`eL*)N(U0 zf9ta`h3a2hp>Rz7cQBZ_-7Cj^qtMFv6{%)2DR4De$pj!kV={gMAY#Ez93Hx>Up>?_ z*{E$SZq1A_rs^Mc>RRXpiCv{SlK?P_mENp>KMClu_|BNMP@YSNgoNe#B{^R?2yy}HplCTItPw6QU zu#9TAkrc9@_kYYJbLmU+R`*CYiM&OWSXZ0ei;qLThBc?GV`UC7K0#=CJ9#zJ1~e%> zSY1dJBi~-FBhE1pqhcy>>hsf;q9z&z<{&EKosZDyPM=)4KYaP}s~7RgJOD+MYDktg zk!+BhAT1d$Q%9HMDQt2WXXYy;Spy~aAOay8it)5}V}bcyRrGEhp~ln`E>#peAz*K< z$$Lu;z>c$b#!#J#3IRs5U<~o@^0>tVfH~A+fRt1-k%rJ%NgfXIjr?Vp=%uT-6su~4jpe+_S{9_s^GZLHtsN^*_S!Sa{pciDOkSh7aTY%U?x zC`O3}Bct^zXS#j)(F6C;Z@q0!yso@+A|m3QBN<~<)voI%hM$~6>t|8qJr(Lw{@0Nx z{+$8Jq|W>6`uS}~F_8i6wgfEZJVPbfCVPXFilPIU?E5}FB?7(A4R$dnq%GK^JOmt9d&N5Cuu?~<9O5GwxkJak_? z?Z0>y&TR!apOhbFX<;dp4C9a{bA9ifveXv~yUFEI_P{)1k>sK5wZzUyn?*4Ez`G&9 z?L8Vs7xRVPI{(+*?`^5P-)sYr99X16B+W?7q5<&U#TXJ1st-}`asX~!;cwOIdxS9? zDJm)9%gmfZ=kwYnqML1>_6HSBqIl!HyJz0{tPpb`+&OlOr}7mebJ%+fW`sd|%9r0g zd$HvPCtv+=@p2RCJXK5#YGe;affX0I!Oy2eST>n8!vMN$SHnJs>Rqj^KOI}E&}2S8 zbV7-Dn-H(2nQHkA9DdH67et#hJkBRR){ya4*g<rn% zA4MERwlR1Q^e^5!u}>baPG#d$dKd(tQ%!ib_nxHHFvg}*+^rp}#pJHv{A`Ui+bzuc zIWE<9yFYpI)!i@cKeNjbr}H)X>Gax?1wj`rOYBE|z|jHpk@KXWyAAIj`c# z>cr(>fGQ4=auG(_s#6zU{Oa-QgOj-8g+m}|gh95!w$Y+Es=tZ7tL3n;=>cYo z`$>qw!A7pV7>0tgH+r*I03y;BI_T-QgXyZ8Nt{o|+KKkZ#KMKqc@)o6hD zw0#&XGSJd+nv;8Kl3~9@YedcV82Q2tmjDeH7n{-m@MHy5gb?!uS)7^BZX?AT`>q1H zl@oxxHdxnbaeNvAf#0Uk`;AWkMn2Tz080T}y3c74Mx)(b&$oU6kpES49+9kh00q3$ za#6@I?P;uyWxmHa;19L1^0Mp>ByF|sHrt-s_4HqS`$N#v^WeXIc4gX8l?o^!QN&bO z@E=ZU=*FiaUAK)#P%Yvm>(X=#j8*&Ub|KHvXJuC2y2VxQlNB}PM1&V|bd-S(r$-iPy*1Pi@$ zPGx?QUMd;3@uJ7bB=&>xuUK6zJveK-x!WPUg(1Le5j2zBAG7f4f5ozln{!W_Gp_^y ztWMUO?d83d`2NMOAFt1NuC_@A-XtRsh@Oa)G1@-^{8P$>J-=$c)#IRKW#;+C&rQd^ z<$0wlF5Z>#SYXb{FC7wslX7J1AlipFUnG+%) zX|*QeOj~hx+`cM_`E=*&-|0~G1G@naZ#?ip-|nA3)Iy2X=iM+Ij4|Fd0JrXFuh1#S zybV$(1n8WX9DXi+OliNPGFzvr1sbjJQ2h`0 z%rHZkScTT;cq&E<%5_DeuQ(03ek~})0ZOU@m?gNOss0CpAgBam6xkXWMd3(OVFz>J z;=_md#eMVAJ4u&;60@!^jUr=widBv(!Drv4gN`?HBU7dcM`)J|{?@AhrP;!@{-T33 zgr&TN<0((eex@AH$J$bO*J~ak5a$ynch=#3fAy<}>g`gKRXhktF!T|DEvsh~o;It2 zF>QgqkFKfq9C-vL|Qg~NhBCNmn-QX z&DyIq&5e+{Hft1(B2cI%m{Ck52%^$lj)In``u!#U@h{(f^{l76C$1x5Mp0)uL~len z<rOf1sS>TOOp*O<4~U2TT$k$Zw?l($H85D&(0LF9{K!mhvdq!;5)<^ z$!&-UFAze7jzP9BA9eA=ht7u=9+Bi~wQ4Q@cap!Far{8XoMGC$mX2t*s67(uew7OT zHEM{D8B-hsGaq@)EdA1JjkD(MK84MV(}sfOZ0^w=ArdUQ)hfogQuyujj~{i9R;K-h zvtBF%x{=93evtp}W&_WBa-BQq2H9aZ82#>HvU9L70fOh6NEXUh^@OxZ!KIsK&>H>;dKqd>~T_nIQZ2&?< z+21=qq<%IxQj7!-UI`0Z82b--8)Hh}- z%(VK){MEB)!6sl;6Ihjt8etUnW=~(7Kfer{=$~DLmm4!(30$5pgDMnK!2~81+CM}o z%G4f+jD7CvFghh$V=xJo200s%--ewPZLaWC1l)q;#o4sA;Fvh~O~uzc)qlR>t3bIF zzI#3v_!6(JzFhLpW_$UJe~CdL+V@-1L?qG#CgI{9EAlH@0R}9u>@U0h~JF3lgHfYWm%B= ziOeUnk9vUV1uVt(rvMpk573Z;xVy|_a1ou{m^GCJTAhd3%wgNXjurw^$#T)sbf`L% zyaE+EF%=UL>iQzCe*5K%uV3;qsuAA1XuTyPVpE9<=ExDtnMFsH{`nml(g4N}$}k1m z_Ejy6&U8&N=;-l}dsTQW}!w34ly`fK)5JrBT3J2?FE%5P*btNMuS8 z>C^jica7ZQ>OWt#d2K3aE@=t6UadN0Kts0MewdPvT!c#5KS^lXyWkE8ayEz;fo7Bl zq*>zFUu?IVNYnLSzWm;wJlOOUaSobo=13>0h}XgNe<&J?$ZQx~u-&&B=aB~T*MVq0 zgaJbaNNki0&|2fk=*=Bt|Ji?NjFT@#1n9JgJvK$?pby>6dVpOC-RP6$_JCFV9HS&h zSBtRNA^iNFeDu)!aJ61r5Lw%%^h-~9R4x!=dKBEg{^Uy8kR&1iI^W5F`#?lymA-dn((OIMfONC-QySO1CIUY2>opgIM%rBv z*gMh-Obhf1vUZ)%pst{gVF9ly3=d!K4q-g9?kVC{U66YyaV+?o6&6&8yGpKedP% zoi1JSMQN0a`-<1YCD(Pdl?PGn*VuQxxnq{5ykwEIXRI*`_Fqe=ioLku()2W2z826TzvS@pLNcOGHZX07DHr+Q^wlT~a{Oa`A|Nf)TzI$f=lu#8_APEJui4PbhbESV)!~RCa zJAB??SK~b|{ka3VKR>7~Jm0c4hWWS-$aJGU(DrFW+U+J;M-yt$q3ZvT=#V$<2e{B5 zj_}58?3c{9IgASlF@S`TX<nj^8_GUdgC3lk|QPlARex_dsP-QH1d9J8n8$d2H)# z+}wWEW|nds9d+NS-``42V#vxZ_gdP~nNh&v70%%W43m}!m{%`MFUvY!ytfYTb>UQk zSV%Wd1cSwGh$e`c-61vP(h|RqGEzvDTRl~I+;d^%yM;$;K6gaV`;KFJfVm&eHoYX@ zwyd4Nh@4aYEVk?FNWYY)FKqmLritm}9GEuiV12reTe!GzxnRzhF7j5uyPOtL9BqW zs*0xK(`p((8V=+Vi9;QqvplMZZ4i>?Treq1_`s|cq--)(C~Ck#)wi+!*d{)V$tSlY zW#%w}f!)gykvCU-G?`BJXQ0PAvRGcSMrwiP$L`1YSvS98NIsN1b+$pFDNQZYqRhk$ zjOl$rHfTyviAHgo$St?hX<$dL#JIA{NBYBm_(0a-<%yC2d}n~FGSZ2w5Fx-~89!{y zwffKW+L2mdrb0@8omRJza&{((J<~Rz!iUmaz%zxyG8e1qSQa8LvRKd@%^B0x%bLL= zj8-Hu0IJRXYiElow66PZb9N=V>162jdk8F zA)Oo&V>k*6TrTVP%miBBBo$F{0xkb-vjK+8jhf^qN_7TAm1V6= z-Njl$2)*U!F^XMU+=56<6BAGk&Y+~iBw-#DSP?kY?rJcHX)ti62BHS>?kfnUD?o`> zw^^h5qw^eyIrE?LUSYUC(fIjjc@3=AWYkgbUzW183?{eD#(Pa=g8r{7o7w+%>FQ$#bP_953z4d^d}LqgFG9PB{a&js+#sc57H zi_vm<4Wqj5YRhL=_|2cc#`+$#695*az@3c}R1ybhkf7D=0Tyh{Oca2UD<@tX6Bwf~ z!$}Rc(xAq7!N9kwS_*^}DBKBzFlJ~C#dT_I3HoMF?%UGF7%XeSC z2$ar2*M6mh?s#2e#|v^|ACr9IbWHId!&Fr*j5brXB^U41Ok-E_K@~Uo4M+J%-YoI= zNO|jxv##c^88V49QWIuKbDJ~|iezS0Gtz=F0_+4`PpD(pzxepR`{2xbiBzSk0$RpN zP%QYp$Sh5KsSP;je_BKwd;DsyZC-gZ(^a83b1r(J%cKlJ8fFEHz4ejN7|kfey%m1` z$p7NO`hEu&ArVgCojT`SB@_WBh?*mmOpg64Uc-KI$O-fq@6lOm);0Jr6pv2eqeFC- zXY{fX?Ns_l_wdnuISDU2kq`;hnAB_`T8u(y2H;}`yo6;2kk$t&26#XH8gAMH>E zcUZF{=WLfdqV-p>Lq}O`tY6ig1je?3Z^Hq`nFO;Yu%iXJ_y#$Jh=vIJ`i1@dzkDyN zvuy|w-r&thi)In+AoWN$>h_R@*%Smo2mv6>0Is_E9Q3;?|J^uZ98RcrZZc7o836q@ zPXLCi9lJJ#sryCee1>U7`fykMziUlG>Fx-?Ie3?h`57!G&D?m#T*jN^;;X=d&gjqBMS%39>`%j;KA6Ab-R3&_Np=Q4iLLq9Wfbzo>r zTz#fm;R;SQn^UtPHTk20!Ix%804PSig?9gz5hhRXy#62C)SE=docj zT@?~BGDZVM=oOw8#4aDN<3|rWA1_x5kt~ju!s3uj@|dsr1~Sls?av+$pSj7298#>x z?E8NMaq#|?R!tp6nDiB6FDFrT>b#1WMPr~dXoU6r)o>774F7TWVe1mfUT)EvxF6apc=hZqzJM$Si^p7V83* zs8EqY%c4#xZ5d=a<#6uCk>jh+8(dENdZ8hc>%b4(4c;CFt_^EFCktTe0cK*?FBJB~PS!v?fg|FVPq0r0-2 zA-5EuyW^)@)*rLnOj1HgnwbDA?}T)!0Jc5iFc6&y6yD_k&491%Wj&HIv$EXcmcd(w~z|Wthyj9)tVp?k(ttr#t_Yn0w?Gg z=xo#3`LEw!-PfzmdN*(bQi`*KxH3G@N8DA z7)mAzqE}lfR$wPk$xi2y(MYE%yDH#GNBTO30M{zVaa}$V8 zWBFV~VekUy{61&jeeUxV*hQ;I~TwYW`nD(>>XFm+x@ZKHP-?zngP_ z`pLTUE-P;Ja?=xvvbchrn%f@P!JmHigZ=jN=a;sIu2nl#2T9_r zEWOosp4>w6QWF8j1lBSfXk8|xs?!?ZiRL*Y2aFmfpzT0ln)M5?L|sl(mw^T0>2-`g zZg@72cv_`9FVAi2#+vq65red0zyu-@O`=IQ;*L-Yt9bt5Lw)bmR=Dbf4n={Tt^L%g zOJ<Q3BCk~vk%)-FESB=ZqA)6~B;^?u zaCtVO`OeHEfGX%X-kRY^Z_^`tfFm=Nm%^==I=usV%oL%dU=S4*6$$}S5eIe%Cvy40 zDSvS$T{vGUEgGqW3nqPJEVysdxTL0_g2_|cc;g`~`G%3quWJ#gGJ~cEz)}y8O@Rs{ zr_}>grBlsO8Ow6mu>9HD0aZ~}Z4as%7{hCm!E#iZ$o5+F7hRT=STRQP>Wu6~uk`fq z{`~Zt3k2yZOGelS`58+=@~|B`#1rw?v9^kHGg~s(2fFBaJudsn6}Ex zO{m55 z<^~u+od%Sc^g#-R9g4r!utMQz)hbe}Vd+Em)zT4Nm{V=l_`gltkkh^fsAVVPPm2Gt zj#xktvU5%hAe?tsaNlk3{g>Z9yNq3A0qygClvGLc256K0XxtJBfN`D|Ns4GB&aXC- z@C(M%wXY{A&CK!B3;nn|ZeBhCeTW(EhIG!2k}qntP>o;ZjrRa=AqQX|Zlr*Bs)gj- zWTf34x421YDU6fiZ{?keC0W(Bk5&v}%C$0?0B{fXKk>H9AhJV_f`pp*EmkkMdeY0^ z{ps7@J?OfVxb4$&9IR)upDS#ix>XDt%qXCKwChw?>1u}EMgmuBJQ)wBGxlHIva6kc z>y2H5NFfvKzjch6-MIIVLtdrgzZP?S9D#Y@_gDYQA^L&!y_aCpM?`8ArK&M@=vQ|B z@k70*7b_pl`m&Ie!K#Q74!M)tul;?M!W6H@uXr=xn4LZ;%p7ycZj7*0!el#AK%k=P zND~EAOc-fQW~owBw1=+cW)0-h^>gC^$jk=AquPeu=44hXI$;5&Cfq|Da;~goLtasJ z7JHBF1Hb+7f#ULqQ-uH~8X!G2m>RQ_aD69f(?W0-=2(J1UZr)v!4G9`n{6*^tb>jQP_y;%Okps0w50w={kWeq(CKmGmiI%Bi@#k*iyY?`Yx7^}l?e zpS-u0?Q_^xRC^*o1GSF=I*VYm^zKWJNU$Ue-YqEeo0i-G58YyihEB)c(c|m4fkO0{ zyJJWTX*`R|*t7bsN}I680dQ$D4bzh9lKU#)bU;jYynh-i7`Dje8pnJNq;r*!;ut~sqVL(J; z8)8Tr0E=fQz9m4W{xi)1W>?@{(aT+>^bJoy;BkME9K+Uw4iP==FE#G($yH&RhL06|2!F}=M{K=Jk_8h|`9^}#70uliHnb`l&i&p7Rt6cspyI-wJYxEdw4WCgRU2RITu zKBmli6*2KOSQ!)ZTo#MT8pH&lz^{EIB&j8u_N!a1LLXzGMXIP*uOjNSoSm#w1rD$> zms%#gf*|;q=N}o-a8O%3dr%;%NcSMAWp+maoR0?QI`15}=cl^;`I$WQ!PzE;jdM!X zO&^1SZ~`Y7nxO&klifTxa!3)rc`^5Dh2S(m@CYf(5C?`K%N%tTm0{%^kocOHGU5W| zK~-rjM!sq_hjGW98O7s&_|*e^qeZNf`ilD775PI{N<5)LG)VWS@2-CPWxTM?q`TT| zy3U`R-rE+N!u{yj4oQ{GPF9B9l+@yF`jFm5CtP>eP8z;De#-UF4pM_YMoW7Zt@G6y zYUX5ff0EAanE>oyN5vnVgbGg9IR%rD0F*#$zdpnvIQ-Ri(7WSDpBT(u2B#;W1r;H% z*@h5P+6hPD7e^~VcG#8(F>E3)vHI=j-~Q&aZ~yTx-~R7^^ZB{m2fRyBn_`q8V#yjJ z1M^5yzrhPgfi_9L8i3{uSRF-Fj{aHjuu{YqZ)&X!idx5``Hcm#8tf_AP<`6!e*&7$ zXDzif+2L_HHW+CCd0ZmGHr4-py)`S^PLXd36)ip|5cPeqz#JK}Wxf-P+mw>TC@XztK zxqITUml#$pVheT8K{Yu_xg^^ZM{#g!13AQ28s9(VFYifb=bdZ?F~mT1!Q^rqM7uPM zYLPF?an~ak<6X?_kT>X2H|bKhGkXc?OkCQ&Orr6DBh|JUFB`Jevu{T3(Y zWE(cyKG5{YfSTsbCkmvM0gm!E8W9Xv+dc`y6+BtJo}KrudHBg9p&>+LwjSv`QU#Ll z{b>%;yD$N0{}PV5O&MJ3x_YBX7-?+oJZ^7s#lOqZPdmZ7L+4ag011)7s!!TsT6v4C z4CB=C=juAs?)&rp+jF~+d*7Vn&)-~_zb~SKSSn%yROUEd3`GA@@C{HEFUw2dYxp6k}alYv<32ZT2|yeFTzWCqZl>_qX!uM|hs>4F|n(={ajxvS&)( zIG^Nht5Tm6Xx)d{CrXNl12t}ZxOlh<@1OBr7gAWJgSw<<6%kd4YR3B$vZuS%|1Oq) z$iM&EF#p)C{3z3#o4xIG-&p-{he+h?;;(dTN6=`h31ig=Y$M=Q1Tc8_((WrQ5B8dW8o?&{q<1LVBiVZ25URfoQUm#WO0EmdmtbK8Eq!EBA*>%|QJmDDq-Z z!`oS7P0geM|4Y{mGK3xm=Uj+1;QR{T{?LE(tbcX|q)AHgtBhtX995k_XH8IEG0ga& zdF38n)-fgie#n2e`X7B)f{4Y5IF_cMa7*Z&6Oj-JqH}cd;%8^_vr}E8N7$syb0Z?8 zHw!jcU6t-vW>Np)bINOo{ypxlA3o+v_q4oCrU6Zv38qvk<<~b zsI?x--a%ukB+#zFvjUH@jMt~Sd_s*d0)!Gi>d99x;~&0x`Q*}ix)`Gz7X>gp$UTD{ z0dR5EQ#3vE^kjX^YVleuq3({iUk(B2`&9h{g0Axumd}_T^OiOb{ZZbH1XiURo5Xs( zmXbEJ-A0mS;o_YE);k0L*K>bzvL>_a`|@hTg-Z1(;Box&jM&os{$D@u&6%t}|L*)U zb`Te1ZyL>6+QF6T=!(t+HIr*>C^2wGvx#S6`;Q|hi!^QcQiDG=yks=9Y&4NHRSCDt zM3*6sNG1b;J(;!g6T4>ikQ}mMccX?`26!feevCf5Dz0DVx-I2EZG1@2}h`v9^lAv#H--e#|5bENpO?B z0=gw7z?2)NnIj_73A$o9ZvyK?HNgok=}goq)V8PCe)Q<%!Ac}y(CM-}l*Pgjlauc?QLS13k0^6)S(k z+xeSr00>yIHy!huEml(C+WYDi&__l{!)29Xk6P~>y)y{n>iIY;>4%X zj|^RBWGZcO{%PU@WEhtZOre?&FzkFy zs?HQC7@|Vvs(;QSwFh?Y#N4@#j^++9aoW`1i4vGOEZvPVQDdLkwc z3h5-CVDsMEes-olUL`KB7JYRc!K979SPyF5_%X-$pX~&&VBIjSEO&oYe#ds-%F*_` z_s!?)Tym2mx)iELM((L17A*#J9-{c_$%|)Kc(%p2&o4p*00W$tBC=@8yBSp780;B3;MtsX#=|C>2LTJs6U z7%lpf?=R&~-&}t4(ypSwX)^BtYRGtIE~Im6nZGJS1~ke7Z=~d$cPYx?%T1tmMiKC2 zr8>4tlRK@-90s?*SW66DM6HoCm`q}7%=lO|15Ww@jAgLlW_-}a zHUh=`!68TsyCJ5Ta@D+yd?kpb(%s5NXnCSnS4wHXWkiVq!APf$Cfhz<1xC0KRdsDK zdTt+f7r%aAPWiHnSDq9o6($y8;zYerU?LFb#4E%xD5F4C{C*dp-F_g6LlW>%KdB#@ zdyWQvlPPmzY~`wxoZzW;e8F60KW%+E?oHHG&4FrA6WUZ-p#WJp109C2OX7%CrpVc6)|;^^Oo? zRS|Kbh^A&DMu`*xqEJ;A0dWp0F$P)?p{Rq3@#4f?{PiRE%T?&Yg+nwNM2)@=x($es zpolQDm~v0p_5jQ^Uo^%h^<#n@?@vZ=%kh?de|#y?W}?m44dvqA>8#iQpDa%N9NDR5 z^UdmokR19!nzT`j>59t&mf@M&l=%4x96oep?IbueMy zbsC}%`tbK(U;XCGmskF51KDy*^e|c=VpIZj5FcpfNX^-M0x(h~MGV6k9L1m}B4%PS z#1IANTW+F*crknL%y%?_O*Yfnx_@F6ySpYF8QyYtylVBIvsF-?7g8r^h&j)bB7_<2 z|Igl^bvKe^X@cN)uZRNRVrFi>MMN&ubE^By|3C9S4?Qo_wM=DIbya3%WMo7}gfHQX ztt3G}Rpfs2AR?-wij|9*)5C$o<4z+1kkm!w-tT^kmp3=7Xy!nP;quIzf%(eJLvRW$ zv)-UEMf|xp0A&JDp%>{NPE|?)G4pBGY5>+DS|x?4wnuIN4X2Cy33UY{0D6}L9oPtG z3h&g2j?zYkIB;D!#K!eYTYZU2Y6}EVNQ_ZcL+D8BLI`wU|M2z}v!(g(->q6U(VV0N zPfcFW2}ZIZfvcYsmrUQX{nQpfgY!=hT*-hf^=Sa?y{Hv+nKndsmBdO+l)>e9C|-3s z_U;_xc{08yWFiOH$o#s~mcLP7a<>EE_ET&e;e-IBsv%Me6-!r@{|Nwy#%N6E)+p*` z?Rs_I&~@+s?u&~i-e_FUy!7dwgNb)OYq=&-5tWp`Dg%q^czG^yhv!SpW3H!^2Uo?d zACIuyYAQe=d8Q_Xd(Z>=fPe&|xFEBDc|=q6S^e0#3UElk=p(PThmXJm!;-fzLEQfS zd-Ah=zI-jO23l++hZ`6r>{mr});NjlGg<%odGpDFF5WstG$bySQGzj&Rs}@Wj>jYi zOJqzxDORC}SLWJ*{w@=PJD$4HZ^Lc6TaNq{M$@s$%9iJ!HJqQj@nIM%eGy;HiTWq^ z08JXYj-uIXQ=qa|3r3xZC{&mVFPk+Y3aIO>dEYf(zwN$$vs%%M_nMSP>I9mK?8rzd zn8^>pu!M-tkiv!=uU@E(f;&zFhOi*YAyDpmRdR zO&X|U?#O~>PbE5KBxCgE<;m0ae!nvEAzt!#effsC zP4<@7>2nT_C=e3_#$eHmFe-)Q%)_tW{Ou>rC+9OKg_(2+(cj7E-doD=q>}G_{+;v# z8(8U<2JDvr;5~|_YrlKaJyhMh_+WJ=KtjZ)Z1VC*y?~P$On~^}(tmbl3%k}Bz(jA1 zF@_KVjRK)aBskKISf4XiSIm##1yn|b_c*o(Mc%q)n1+LQ&CbpX6=(BCnTRy9T(^k?v{eBm zP!bf22+2uLs6t07At46meWbuOuih`O*X%fdchg?4Iup&IFEANgpX)uQV(iq86ZJ=C z_DN+|S0)3M7H!y&Fxs*5wLaSFMxJ*)?ls+Xw-=+xa8m6ZR56^Iy*E%$e|TU(9)@8rC> zI}dm?a5%Cyy~i)`WXt+vV$=@)A-j&%F3y z=)$T=6c>Y;#Td=fs8g-Fk1EVQmkx5Y(DR@(FLtYgCTfh=mK@B!DPquW_ zLuA`XrNde?fNDz6zgNG&j+MUk(ppBly#-c91gfK5(%YvVKqPf!X%{j`R0nl%jT7&p zHm|P3zy9U=o7XM$+_@Q?GgT&Om_#suCPpzTkruf$I_r^7j^dESM3?K<5_1W*m^JdS zl)Zg%1gFQxD*F3ES43cyJC?$TE+t8mB5eHB61O7C@S~NuA1w!e}-(C(Qk03ciGPLyXN*FuzT@L`X+7f864t%_n4E6 zIm(sPY2@xIWXhw>Nl6hR#LT)`d-dmMvYx2E~-Lh*MMUPl1W z_w@Du>)#)b9+K?G^7oI_4mJ$CE`a?3&pjJHT@RacfF4l>#H;sC5SK5S_SY};(seGb zCGWNwTaE@}_Ez1M18^`7?D&OO?$EH+W%Ryi3>iNZKb zq>iY#Sgor)*B|{vC9#Q8v~XGNv-UuSm=^+;bYBVn7Xehw&u=;V_C0_9-R-h-kuE}_ z(UM^ zsN6qY?oVj*KAx-4`{7@n&%^>40bJj%OeL?MoU*8sAhp~U89}B%MHo%RwZU5W@7^un z--ak>KfYVNyNT4fLB%N!%ZWB3{F+GH*eh``rIq<#qQ|egAn!h)&djk|DM(VE~))J z#uQI*t+)rB>8>M@U0kd?jT*Lc^Cni*dn{#3S*d2$s5XcVSD&8YvvZr-jZ2g_f|N*x zXwd-ZF^0K)rYuV-c^_z!2aT8Z-3x~WMJxf#8+-Id0OD}B49j5otj0onZ@{7in0hpi zGZs1K{|thzeq5?K0!#+`APh1CWS=LBfM%qbg=j``(Ve|-XMg^2{mrY@GB|@2yuwnl zj3l+A5rcd&t2qWgm>h&EDTMoKc`KpsI=A2^IxMXz@4XZYbpUDy)UbOJFPuJ=3 za~mV%5?+93=kQ_)N55XKBa!k@*l&3lX0!m5*_a2Q2@R1JQUPqzyj|H3SL>De+n}%B zwH;%X zig9(lrB%xahL;TA;*N5A>M_5yEZ*3;53DN_Q_X@h8QH8 z63#>-sOVn$_20knuDh9gsG5kWDmlccZAD?Ro3Mf7;-WT>-ky@NUhX%YYK{!FIz0|_ zS@#M{-qYzF*;Z|O1of93_GJj9kro=LT3BfN#d&-=YaP3sY7GsBHpZAyz74xr5@sWO zw-yB4W!0@%$j6itJJWpkzzTye!bXUSZc#u{Wi#t=aQsXVzLs?ql|{0U>8mD$PsT&#X%b9XU;jH3XO>HH?jHVZTF`i*EeD2T;qi5N|vx_ zp{kB*xvcvwe#d1LAcRK2&239UNQZc_*uK1OCPN>OwVl?J558V;{E3X*duwK04|1hD z%sXiulHrqxvRVjOy^s9-H2_r-Wx1V8f24^fmF~&Lr5jL;8e(4W$U_DHsk40=H^M=m zzW!82Gmz&C%p4SE#BCS5Wb{9Ao*&BSQW%qh!my+@-gm*o&wqTsdV6cj=-=JOtCfjA zk5q_?OPh`LK6H8JD+03epQ(6@AV6A_o?dkF5<4;n!pZ4zux&R&XoIM@FE?QCQ z0kA`~n$`{PR0uEXoqCC%p2g43V`I0D0T99&B#^f{w0#KgXq zM~cf~hl{zV1ywb;x7QX7q7F2YDr!b1o|xt0IZb3^jA^qpqY(yNE!Thk%d1uvoh-ik z?oGrjnu>2s5MxLVeX7#CMCavRd-i-ms$|SL{wS= z9gHbPcVOujMugf*&8DL=g~c_DeYaAzEmanmvD6p+!XlLh7!y^%F7okKX3OM6_p?rv z`DG4W1GCgegtzPxvZaDvRkij~7;)^lz&nO9eHLq^EWl+e5~&RrI5dOuPFqugvz*${;5f< zY0V5cq0mxGdVmg8A1PZ-fxF7arUNOqu2zw9f5 zfxS4A57fI(68q*mz0^8g7rb{NbTm8jvap-K{iK;;4FvAp9X-kzXICciJ&yJ+#reb%w1)i(OAvqx>DV>A{q+ld=GQYvM)SUD z+s=7^yIMuUm_shJ{YTx1);B+QmU?#vjJMtI$E+%wfx=r$(jEb?J}}7%?mK~c4lv{d z3F~L}N$S-xs?ymZV_d&q>IZ0loy?^1*fdI z#pM9;qa2;nW7mja7xsT}g%S~3^n%OtxiA7^;@&S;5Ja=I?ine)ArD1z&^iHAPz^#g z5vm4@v$OLq%Bs_EU*D|Iz_|q2sX&EJ*oT1j@J|JxhtkVEL*A=0DD%|q|QNtE&) zrNRC_Gp{NYX z;{mwQ;h9D2HO>&Jz@TbMz>(;ya4adL!n~M@QDhnYU*31`JHKXQ>bej}ajr>`=f=V4 zIQgEbNMfw^gS|8ed3U`E6j4VD&o35gpvCRr%yCSfO~0~7Cq|wg$MpbJ{VpIZ4V!M) zU6Qbw#k0jM&8ZUKAvFRrYWDwHCIABvD5Jlwbi-Mww3s)NW}xDhx9j@(rTL$r7Docl zr^g4}&U=2y9{R*&mYpyU2Ru8QYhsB&ua+zJWcgAyj*w%}1Z4WZ&b_8nfQaF9q9LzgS&Vm$CQ%Cu`DogVm-#V{b!2(-|v^d zAF=9=E7jp?&#rcHkNyAjiz*_@KI)qgkw!4b?H8ALHVZB;5!T*m3?}MBOaa&h?kHn4 z>&<_9_ZaMS+I`?5+PWYd!x-5*G}v_)NSV0SNi3rtpm#w)?=8@~#%{YuwASBq!%+i*>YP%F1 z0rLFJkGh1u10PlY@>k&kw4>Ag+#-OSuHKIb?LXFgV#?W7 zkYZdk(l~E~iLTnvb{Uvv;)oALWM-~ZJQGWr;TVH+-r!z*x_I^W*8Bo~28AF3QN@I& zIeEK|{zY-+XAi`W&>)q;t}gR)2Mk_D6dlyjVEsx^<_397myx&KXtbRpBYT?ccxT>K z;69uh(a!7&ur%Y)*j&1+Yy100M)JTUn*0*L`W_T$H9X z!eSZ3#117i4HQyT%rN8izG>8sbTTdZsrO)Z*=BuZoHbyzG<+@#b=ZA}-@cF~e! ztaoQ~RT_2|>qnmS`vE$q$78esTk74^0Ho_68rsev4iFX0XTx*)myBG1J{G+Fu_gf6 zy2B{|&;)22IHzgG-^CbgwD#4m>pVKr==6B>QhwJL4>k|Q;j?I77#oMhVoov=fmq(g z{(VFw<~X>7g;|aOwzSF`U|l=pGuGIdWdPV@1S(YxJ>Rne`>p6Jz`frSm^A8{f-?j$T7Ei zZrIrO0L+fwiT@KBqcK}S-~etu?OUT|hBuSq+h`JJT1Cy%R(UER?!1e;^pfL&Jc z2U#T(QuxI8@E5g1Kg1689?=1NxL(KDiSCL9+Y|jevcFVib<#&vLyHZ%PtWYjXChn) zA|Nz1N{kkw#grY}BOrMiFpkl9z;!aX(aQns|E|NFT6EOo@%=YOXN0W9NL!oa!NGG- zUDZ0kkt|TAX#f~Gvz1PuZxyN(u)_Sz>0qS?NYi62EJ<~!dH^RHLvZu+A8+Nq{_E>b znqcC@IhE9&fdezwpY%d1z{H-sdnPYT@>m4uNIQA{K{p#zmdLjZ#pgwEc)4gdE){m!(B z5M#=5j9L;S6iE>ail*(iHUr-z2!;n*L#L;H) z>Q^t^`JC#=2&c0|{SVR1G8d@tlLrsU>i0hq9zN8e6Nh;JM|N&o)YXHTA-67Q+XK0G zp8C9^>UP&o>DTR?@jiexs74B-On_m*7l?>cO<<5q45F0IoHGSf)B#D`D&OVC@r@ZQ7B9EnZ@ORkV~p1~H>t-H(aX!r6o-x-3CfSYYoGdr z#|8g)#ch&V0ANHHQ0{Itjd!W1B!wft>_I;NvFI)zyaAw)Fexe7Y5B3<`Gler2UUSr zsu(~cyO7;NL}e53CpKHI)8nJ<+R|w$DkxcZ`NIa8k7mJDeAYh zG-fGqS}BVUW*22GXaDfquWx0sG;L-JkScJ6POAO>F+{_ZJ-Yvedd5ykukGof$rG;1 zlB5jyQ=)oiMz>U66Ub(5m48LG0aTOg4Xgl_Gk2AsvA^Lx(qD2vn7`K-XbXL>54ACt zwC-|WQ&LJMKwf%j0Gv%fS?32UMk-+dh45eAIobJCRZ9_uK^;1?pl7!{|EGWZacPTnS7x1z zput#KBlLrp?1)Zvo#|~GNH~EL zPP~7A9TRv$8bx}@B5!GV`Ag~Bryk&g1D4x>UYQPZ_rPog4qUfI?k|$iu%|Em)t+0>(KSa%I0D~%NRVgTSqp}zP{D}{Kt1!{*sH!7}-G7toU&E zQS!_I@1$gCxeVS?GC_jY#$%SOg*_W#17=p?NlwU-d%{}wi%{n0FKU9nojWmcw5qMJ9 zZCHgEAW>Y17UT7qzx`s?{>>SlIguDdAYKh5;Y>W$Q$-{yqxLq52U31}qsIDZ?1BG> zJb^NBIp)Kr2N|0I3%g3m{mQ)iZPf%#%`^fgFwL%n0-#&3y{Z$jNKu3qFJ>|i?{NG5 zuRc3ltpS(R7R7HdkI*Q9rq%nAO33|xc*^*zm>!%Q)k%ji#OWrUMG1qgPt(Dv%O>)= zD>Y(Qft9lY1W}?n!l{UQah~d+PMjIN^Ahb``Rg zeodz%nU-^|P%4>v**wdsR{s57E&0e~7D>rH)&ZQ-7F;hV&N(0)? z3M1N3gBNG5Dpx?tK|E@Sh5{m-v&{j=Z}flx@}oMy14K%P3KhmJjbpo3Y2=-~ZdB)_Ai z$>EO~rOXT)U>+k3iNC!&P#JT}kS~_qCu&Bl?C|)%M_qV~RAB!zIV$~Y%7Kl+VX3nQ zie>?q2BHHi=z4NT@25K%6Cl-1kcyqI5T2+OOp*(~|M_NPsO5&|%-{db{~2VmOc z4&5Hl(7mnlW^B@fAieuc0rJd6`XCJg=a=WJ)vAk~Ya~WoEb#CD_RGKdmRuP6^0i864-U^gm3i(=s@ujZPWs@Zf6P+9$PBtEIb7XpsSbNi6|~)cLgRV3Zh> zZRMO&AgY1>1{eRo-+pKFv)d@%&tNo*>O>&jy6d_w@fXy&5CcJqbd=kGjw&JwJM)-n z`OR$4U3MyUo+fUJF$PURnFsXaDiZ@%U8FcDRN`W$4uGMb^hFD-UGiD#@()i0(vPwm zZD0MJ48?>9&d=tcC6wiM)mHcUP+p9V2u~?sKS}lfkax(AkRn3ke1`cf*}pOZ@2`TY z>uIoNk%rI)=bU;C7SceCf~d_37hk^#zyIb3_?b|g!Ku(fZ|bj7`#NLDfRV9Nwf3~o zQ8;`LGnJr#Eqhqa`yYlKd0;&a%9;8GVw-I2Mp8mA7?q6K{ZQvZ*?|MK7e`m--DXLEsA z3SXh+mxxKq-^g$Bz#8OnkJVk1eed-3UEyE*^Ci-Mop^^04qfL(*$Rt_X45Vx47gpb zGA0O|pDiZW?UwucWBmmm!v#oottMsHBB6q_S z2d3QhG9&JjeK|1zt%U)oJftVuvfgAG^`8Ki@<^ zccY>A__*^`u}#jgW7Goy9H1si62?TR-2jgz6)I!!mLpt zJ@9OS=M5Hs1|-{(Or9yb8$~P=DL!6rbKj@!jkDgJ>Toax;^15LUsO@WAXQH*iwP42 zR=t4H!5YQ|!WS3*lLp$ZoERlU2?7nRt=pi^QAlQ?JPkm-752B@V>j25)< zmJ)z8OMcm(rbOu7%m3M08Qp>jB*-!`P;M48|O&(T4 zCnhAQB8^JJZh`ibS^V|$=3F|@&JZkh$tJou2+Z!{;NbfN)D^j*vozb4%JcX6ZGiCRQtL@)@VLG! zQSOo>3^iG(`6j4x@%$gZy7}$5h|Q&`H%qRD4571NslSLZstQR$jq?8b)t8v0vL~@qCMoei z4f&S@-{j5FyK`0ogFLSg9pIwea#Y)4f3fIlI#6SMq4{`RK?o8dx0-b2u6^4o*gVCE-9ME3ot7A2AZ49SXhJ39GC|yM5_S4gZ z%G=5);c{D+(2zvdLt@9)9}`jCo?Nj0)a-K0xqC6R+aW5YSZ1<#@x6lxjf?>r;9HZ< zvas7oC-FrSetn?}yFGWbuo9(fe2gY=DbcM@->hZaJHgl8T>m38ytddBJ{bG|$UOjy zVwVz4A|wJ)Nk=3*8l}cS@6IR-d=5zuVRqDDy@ROiqC@Z<6ye*gNL_aQQQdO}p4f{4kIE`_@p zb$Q!$h6spYF>lUii6Wj;gpc2mcb(80+Kig5kD>iIP;{axwRk z`E-Op)Y9c#wGph&>W5x&KfDNd5PYzc*|Lql|LTXYU$6i8 zru~2ar{AtP59X*oQUqwc4x9#Apyq#r%A{>l*A z-HQQwbBVGRbE;iS)qhETkq4DN4=t*WuC7pr0;IERoZwY?N{~*o<}l4jVWhTn9W_8q z1Oi2vVf{%HK08ChHLX)85HSkGDYAXanC{Qyus-Pljse{dMk5cw4?p|GB$tTHMv<9q znevty^XSzq|M5mfv&a}N8VtQ1Ryut{>Hql0<*p6YW8MzD!`tq$#oXF#WXu_?s((#H zVDEj1=A3VunF?l&cv*ik4=?9-hE8G!MMri4;uZleLXi70BKbmYM+;<}1|Y{Y?T^%b z-S2HtkM&UIh9huf5(FkgJd2KUwa_o`J^547t9T36)6W5_u`otMSM=Y~VK_`3R9@vd zAk0J*CXKqLnXMvMy7({u`u%Uey?M8c5HI3lv=BRi0Z?^jBp4~nHe}mKm3gC$M{*hJ zC*B7k{B4_WPwhNaL_fib+uwlW30msLVZ^Ef#Sx;w*{t!3QBLrrxEkgFAA{ijVH<#w zejyW(3KX-bDpn2h81Ve!Tr8?cG`zoA7r0duceScVK2}V^X+*GtDZZ;WIEX;R7@c!@ zw9P2wXD^>Kw4{08{P_00sY0|3U3z}kcFk;Y)5agKR&SSF$;Efw{HrU2&V@o%169;Q z^i4y^Fa%H;`@!}5K>_&76QsCV_TO?UQ|uq28$;pV9uBlhrq;{X*z^3-b0*loj{WS0 zvG}xSNO=W!-i`0%`n=2M2N}x9$zS!&olGMq0l*3ONERj(Gguq2YS~4IZz3dwc82zo znf>NP)5L41CQjhgR3T2psW>m1Bb@V`CJl|qQF72>I?$eewSPwPjZMVj2Ue@QexD{=(=t;LyT$5K@wY&?7D6?YwELaW_^Cb2kJk!8ei-`_yQGbq*Shx zv1=mTCB4lkNwg;F~W zm16E$S$Rs15kT*!$;lj`>H$OxOGm0bqWFZCV0iY?U?{{;h(bvZL4*ZUkKo*2mi|v~ z@R#>($40avp(-&3GfS8kMB)7RuisLginO;kfAgzPVn2bna?YoNE^(UNgyJXzes&0r0XZV${)5Ft9Q{X6(1yp zTzH(%ywHri4Sc`sBH`30$T?D@&c1tf^XfXZ{_>l*>(?t;aRzllI?w?WV`i6R;=UWa zoZ&RjoQDsU$;zI;jIFA^I(>#!VnCHJP-WTl>>wRFhoM^SBgQ6sn+(0g&J?hZ*4k~w zpGpGor`lq%8JoKsbSD%6QO z&9WnkOCJzb5hr%0;pL+H)g^sg&OnBk#%sYs7tE~may2lVl=M69=!Y0b$_J)<={8V* z=v*frTm_Fuss8&E#j%^`2yl@>$~DalQPs-Yf21$cYGE%gnMB8kQ%!J=hxr^PAP%M? zE#2GJ{qc4D^P8?i<9rhhJ%^5jQLk2UxsD{1_H5D29W?C_nK7z+aQa;{oJl%0$x~tU zQE^f!@t-{gIADDw5Q*igB?L4jFBYoEo}q~wAfljbYLkTW5h$r2r2!a(zN7oStYx`k zP+&2GcLEwj*CBMF3LmKsE>9uAKZnV{E&!@PRlk=>5~@xlEvD88o-G>0U}hch=6VTD zp2{?lPTXyfKmFxRa2HqR{`~ri?mWU#HH~7GCYq9^a`35EoxtGA-*4EZj-Q4~R*1e< zx;?EFz%q=mhyAADQmhO^F#t#yvVNt4yZU$N`--ig^-tKgZ6gIur_W`-sjCwqB#GLB zNr*}HL5tl?O}pz$*ZumrpT!%8Kv=>?S*9kMI1iZ=TqXd$AD~clJ0TlK$b5H!EB6oH z`Z%2RyTdIxQLe0(Cg?0A`-vDsI+T&1_%50{1vPf&#bq-^l_-dkTDzyX(B6e=)#J^h zJ$54hI8YYv5SMT3JnJ6Si8vIQAi-j8t1N2_qcut&ufKezFK3*^l}8jBz-a6OgTW|u zg)q9;(&x-Py{+2Nr$F%7w!X1mPNnh%$|@=JLdqd6STl^$1A!&Cdh8;KLC{s0ep73> zUW8DzMN-)}7b9jZDzfYXmm-}ZN>fC@kZg*ffwboA>v!>wZ@TxLbW~BFTI}>kQ2d*# zWq_)xFg{x}J~1H3Y|i_DEjTfMs_&kpz#koY8CAADc@2HxI4|jeS%{GQx6##k@&Y>e0CF2GMZV0FDpR>AL>OtNerD@uZH-Nl(;l z6A$weUp_li1_4an+v_F7nK8x~iKxw=zkhqvdGpV{eY?ErNJ`@xibBK#9uzU?;DSHd z1_n-Nx!6jT*{|$U0q}i9d}SO_aff>2&fW~Pf44!jnr$k^xboQZXRspOsQ#bADc<8Y zy;}s*3!5cEI+HF+phS>}j&Xr-9gAT`Pp|;1|LJ3!edi?9yg$egXvo3)t(3wPACkaQx)%AG*BHH=t6^_?My|TC?cJ6 zRy>`M4Hog}_G=$2nTUIe`1&_F9z-8%$0~@r`fje(nNf(63M@!{Zdx9+^s^A9#RlEE ztpEPSe9>LaWG(E3ph+}zhL#A>>_}e^<&3@GegEIe4|Gpp-^Zx<_dDd)hMV=eU_U8cMJ9H7?+0~k3$5BMwv^)k*L|4EB*o(!<|j?0UAt?$wdEm4J{$<475`o_C; z2tVHPt9SOz`}R5rU6Zn4(;rIc>#G}6CxBXfem-vmL}ayJB`Vi3d2J`-|EE(cp(Nzx zWwOe!6rgPpA|Wc^qG_BCEo)gXw)YYr$MN#x*nncfa_-67eLkL+rvKu6Q4Xjqmmyu% z#_BCAM!IoKzc=MGGs@z<+%-G*pP!}IsI?e}l4gPz@V z`u*Ew)Fv98stnsK1tvljj_vAD8$R^mFO_>H`&mJ~wMdbRVH6HfNx?99-S<$IP76@h zaNzD@k-O4}up`Ch$j9Su4;y=u&_)8X!HFC&B2qh(XhKT*kB7N-`RjA}Y#tj~1D&b^ zd!%lUGZ4Rhk8*>Wnn~sq=fO%(b|O_& zMWX>Krg*o++cjE+%++$%6d6qm0YgYFK0+T2%YR6Tx$VTUhMBQD8f>d-d~0vH`^Lkxpd zMHd_$8ubtWX#e`NzgwQi?Az5Mg5<x^Cmu?b_6V^uiYxXI@!iBNgfG zcED%H@5mdqspRBx8IWS{SNx|BcS^}MZu+%Hku%2V8`p6sn-NPwoaxzqFcTtvFa zV7R`yO)Ikz-+uq&+H_6-AXdw`U!HS4P%7+bhfZ z&aSPdby|8>LO^aMsqd*dj-fP6*`JSX%f4%~8JGCIDUfVC^+s3(0=0``0iZ;Mi8uUMC1wjYBJ<;-Nkrosi((Oxc>NCl_U)^G`TD!>t~xg84AJ17XNV4>q>|~i z=}mqXOYmL0zTp#23Fuo<|NSRd`>{a3X7oM)lFV_TE;k7-;S8eUJRo!MoXg)l_vf=9 z(uo0dgtlfatuv!#S>e$`JWM7Ak20~jYv|q)J;1(0y>V-^wpX5twNT?YgVDmaZY`hn zW3ZI8ktF2EK?F!T?NmWg9HC-pT*Ib$wOs${$D8lot=F9;&Qf9lU0q!VA_4%<7qhdO ziUl)6Q3=!dkY@OSN`TV<;ZY&)9!kJ+c?;20$6lPDRfv1pCluZR^LK=Z`~yD1gFf$;vJJ@iW50<@s#p z6XDBW-K>MTwfSX~uV24kyV+W1-@myvYg8H$kWrF4k;UCPo9>lx_`hZr3UUK5p`b=Mv_B;QRwNZb1L9UnV8@;y%| zlZ)xOoCI zjw&DWQLSdXT8rUF^v+^K1c_|c4;k#Qb3w+&YrV_>TD^RSVt8EclamzrN}vpgiKI$B zB|ISQL|!#?F_@yc`1F&`0g%q&ljn1_wFeO8yC2?JbG~+$zx&J8jho-- z?5o!|S8I?9m{)b`00hz4D7~hnMs@0(x-1&yDEUh=*Q62$_k3yT$tPQ4BMY3zDiGde z$X80Sw$`VAt8DIADds(e0C1E$18xHp_mmf-N|%RCS+)@X^2lva;3c7_anc+})~*{<{EW*$5!}YqGz3lwUt6T97VxX`yD_r$V&m>?{P?!%h zn?4dq9-rS)eJMlTYjt;BuHoV2r`Qf=O_}tISFWF`6|6YSY?qkVm)sbLmDIb6K-JWl zx+FttoHTjZB_@vIlp;hRBGo%Ti{0&+tbR3X|K>bOyjEwCjG|HGw(CNqz?Hkta=%S8 z5~6|33k~}YeK=o}YEmev@T@QIOnKSDYI}sTa`Vop7D)=I+Lz|00>C6+di~&TY}A&{ zS9)!4>pT(`bLB`d5E*6 z&HwPj@_&7MwVJ(H#t82s=5OD(7Na6KtUr5kE+H^Nwdu^L5$GK0Ez|HaJ;eGzzpRt& zuj3Lu|&Yb0zAeB2HV8^$2JZ#FG|p)jk*pgpt9eCQ!Q0Mk5lpg zsMY_j(amv~(7qqX5otcZKni9L#!p^cSXhY}O;%Cft?|Cackgdox45N$y9^z@Z_ZLs zZ>r`J^rB_vi=y0>k_1_^|53tdfDK)535+bDeq|50vHw*KgY<&no_AD==*kfYsFQ<_ zfHoiT;~=UxeG)g%yKKJ@N{L*mh%|wR7_n}g#n;* zDnm+xP}2K25tq0Un)f|RJHPH00Y4Zl-hP56r~aN(myd{yXNP%8zUKO%qrn^~hB$Sj8TPew{qEf=k zp{mY{7kk#kFE8DTnQ6EMEqQ7Y+J)GKSWZWODz)eNOzvXd;WFRz*Yd-xOZ)HQzOtWm z4fStWI|8xN6W6SsfewVC1}^e|YKkkPJm7l2D3XJocLZo!i&RC0P@$8c5}gwx1>VrC zqJMqMuitjxzYk~@fpXp1)v5#B%sGVh^NYC@>{vu|@yFe|Pfm@h3ak1)Yuf4Yh=a(? zMd=Io@@41Txw z*%`d3OBtob?sJ2zx$Ubx`@cqTllOlQqHMB72Sd8Sr2nw)Rz~zw>Nb^IO+b(>abO?y zoE|=RW1i1Q_?ylg(|jN&0K^U!NHLQbNifW~{QOd$&s1qK7^se-W)On|6up~@mT>0U zVr3VBeitG85lhdX#GUCE`#ACl@4sUACqwU2j2wK2&3|sD3vbSU_N!x4f$GFNs4zG+ zrub~J%ej7e?$6?_SV$Zbg?2Hv$vFWkqGXvlBx^O)3An`z2zN$y@2z_|`u(?W*%QJ~ zJw&Z2J-I;MVDF6nS=xgQMekUx(VMwdnE%ul^5f z1B^;lDif8mpLEfzZ9jkciAx2gZ+>`x{g>Bo=@+-H{^f_Oh(=t~h3LI6h+1N8s0@yB zeTgrF?`L7^SD}xXhDr6#p4$fBBO1V#&2p4!Uq4MNvD)6kf*T%L$9_EeRk5M>Wf@>h z)r8q85;T&<`#%JB>!|QX2J2K~qwR}%_~O!ec53NG;wc`fu;HHi{-CMIo=#wYeX~pO z{g6)JpylY1(Z#18;7-p!@(dpNKKoD5R>Q76rT?xAwKAbsg%gU3K@2KJlEJh6{0yJY zY>rl9*Hf}Ov(6ZEy7R<0#$Z+`e)a7veNxA+WqGheE&ZD z`G@7J_aW-yhwJO03Mhkp`RPl>HkqXf3^YKEY9c0wx7|IVV0c&t96q{N>|eu@RSHp) z9-f8}W+o2T%Ls9zj%Jr<3we5kb$x0F)DahpIbcQ_ba}hZ%+0*82{T8dbOoo&_3^6z zBNvprt`W8JOmebl;TD5r6pM}E+1bKkCyLg16WNMing8)^d$SUgnYdI9bn6&4Y%q{$#VSF#eteUitl3G4(R+k>hs&#%R{P z5Qq<0lA)SR=0~Fc_f~|Gm_J>#E}9ucTqKAHTb{f1m(TFLX=mtWDl^wK;ysWuel6=G z?_iR%wV1w#Wb=Nd{QWA|dRskJ{~xDYIQZSoe(adZ(w?vH>0mb-+95;0;6xLS4}oi3 zZy3y^#%)I>qoM1S@^%)Wlpef7i5ip}erRS;?X%#oLixd&775t+ib9pRJMgHHgV zKlK22D4+=`Vic1kEfPRf)eOs38wgTVWj=HI1b_dh)=qig@@%e3L!`*fa%F^wD{=wh z5VBCdaC&^0>iZV0TH9E+I`r%_xeNDcOqsqx0r)j&*=mt7C3gGBjw2AqXCY}aFG8mIiF-Cx@z#O+P z=Iv+a@V4}bD)4Epm-fyi*xmu79-Iu|F0o&`K-s$%<&T>Jc6!_!t>2JnA3o#v9t-TL z^|wwT_Dr!hxhPIma|_KJDl7C78?0ZR@zZ&{khNMcv+M{ItqT?mgccp|XmZ$7^f-J? zhQw}EnvgtP=RrJSXRC}NN2rw3BbDlS5!>hiutytE(|a(?Y0>*E_L%?^#6m_Kp-Ksc zArnA{NXKd;AjVUIVH4^1nw$eL_L~+FnB{aZ0YvHMYb<`av9I5>fBtc~ib7FZcQ*5L zr;Q-FN2Gzb7=&u1fd=kE5RME7IR2TZivLmI|2`O~_gg4&pm=|EL#UCA@x`+lP7{Db z2mzJ2T%@dYnqawZyHJ%|NlcX!*OJQW^!QMS+Ggz6y+dS%B;bU{r_e)4L>}u%?B))i zesT_UDiWgJ2LIz#xLFHzLDjUws1)HZpr8}&y|+t1BPP|qXkE(J0RIMsR4dMCFH-MQ zCv}uAw2A%aJp(*sPst4!?4BiN_N}>3H;4(~x04~j3^XPd5Xm0Cz%qcNXX zI!}8s4_{o`nYNytiqRsXX?iE6h^V?fwb3rre=A_((2;3%81!J+0pECFQ z-_F=ug6^Q+A5lc^gY$R5?MM2U9kU+R-9lPvi?N$zw55s!&IexykF{zqC_;iEoNMGw zRBa8#|4l0sAsw6^bcmD@6>;J;JslJaDh41zgPUIk|JB>>58qu;7YZ=ke)4R#a1e`$ z;$USOE@sJ6=Fu05)3WoydjJ-fsER3Ugb_EZwWxQhD!4p@+QjYi)BtR(DQcX1s6-Kp zY8%)^1gnrz9>Ob5k3*}#PlZ_$eE^cz#(OB7K<)7tF&H@8vdox%Br zV#ZDti8@pze-%sZ0qGy-J8rr?6mq8y2otLoU@#9I(0Zmo%B(cdNf^zBu6HaCVBdc1 zXZ!HqEZ$d+4KACDSx*V#MybtscW3` z3ULsxP9!?4U!L*hEX=WPBnm)iq=d*2X^G6JBNrf6zup8(u5Du;avfF?A$Q+`*@N*T zOX)*?LG^H;|4QY|Q;dBQQiC)~>HYp|Q~%--*Dw16;b-FdFBs$pqdCB&Rgjdf?L?ix zA$kEANx;oonScGhd$V?wdF(67!Ud2$pWL{q~j&o3a+0BvS(uL4{yH3U;nuu~gwB$iW` zQ=1~N%}9~`Vx#@*#V&nPvfri{8EG*gR7No(hR(w-=2$o~L}2#Sw{LGdPo1grh6phg zBU=?4{JW)M=VP#WMuvZ~Qfpfv0Beir#3Pz|)b`ka7M}N%(2=?~-$<&piB0CMmfvs_ z?%G7d%KYGNGOXkqG29p1UOuTjrqnE(+(v@Up>vWpW&9t6M5Cw+(Fp0fZnbJfodJO+ z5?#3Y>`cBq_j6k-%*>)$g3E|x)$W`)f$NXk#P(+wcDPmdSu>uu3LN)L5;lLtt^>H| z=N^fkp2$KEugJF%3lCt=2XW}TDv2kFOM6VKCfARa$KYwBqE1B}QxJwY5hWQdHXhEF zUp&)K7qPLWgbu(jv$X?CHRT? zQlGNv%Q=2e>WI?Q&rM_qyd#Gts)Radj%X}$-7)V!+4v|1;^-v)CHsm30&%M4{j=>E z#E6XL3RIyk(;3Bq%HRdw0b=I;>$SdK>8i!t&m`P_{>hnGOzz15gqqaGfC)`l4$w9U z$7T;OD6%$;af=jO3anE>Oh*Kgoa_pYE?J92y)w*8)RgPx+LCLz#f!yE2{AiO01iC7 zbB)8rqEQ5Z(QtL!c9s_$*;1;UF2Xx+pT|6ZtL4Q(kYG>wRdAcclrJ9T1^`Bi0M?y1 zZr(W2=Izz`dIicH;zR^W5fe2P3aNw5KeN7TVg{OpS$Y4^jX0PI7(d7WM)TsLDjPDw zWK#WWU*B`gOdSRB>_q)X8AaUO4(|d*^r@rw!2UUrA&hsL;VFHZl8C4gs;&z$M1!W% z1l~Jqm(QE-i*ueya2AB{-fJ??&_ok}6Xz1yfVmVILK{-{^G37O;}{2^oGoo|y7nsA>H@XM13Wrq9Vr8H`~Q8AXw0|DU2j%R$*HP*Q0grZ5qjsJr;& zPv5`4?KB#``1D0wFTHmLCLgEtT8dFjK)tJ}iD1Y4KjC6wMOFXK8WhB?>@?TdjQwvQ6uCfULw#do2^2$W~0ck_Uf4pc-4 z)TxbeMpp-X?tL2(d zfQs(0^?7J0+jPh)9@-gkYb1`sK2dH`i;rnV~p9=b3ErVHgBm1Bz3Y;2!%Q(0Z+k@AMlD z%Y8)|8r8jpGpk$V!u`+>Aaztw7h}v#MPTs*-9*v0A~9QCaSooc!QXn{(`5e{pNhZB zSlW>6KY?OF*ahoCOnoB(Fk*fE*%>}R#~in6!HILu$7uQBXqx-vle0fw?M?{&RzaXBT4IgU1W(yQaSnvEcHGZh8_L3qz_=;*}_E4Njd(0^7kCRVmiFYoc z0fYj|>{CZdMDyLdn>A)SJ0nz7qs4v)kesQq1-ai~`|J|{JTR5uw|Pj0Odd@{UJ6@z)p{yclD7t z{jN-?T`xH{P`0quVN5bw&=p#FOlu$^2Jh$c{oC7>`6w=j#Ae$V3gDm$1^WF>NiapF=kl%RhQjJrkh;x7OJBFvJZ$5!us?2$aI(!-sJ_)hL8^T}Wf%^k0eXIhTL)++Dg(!%C60c$|u)ds*Hjzw;r_aHh#A-GHX5SAHdchq1$>kDeOJH8hxfXZUg8KgbXzN1zU3ECqz>qskBwZWd|n!5n_qlnCAgZ_V7@McP>P( z%>CuvZF4bS$8-%?pW%>V)Kkx9FznR^N9GJDq@K{?8igF2w?H<}vd* z!s0XmIO579yx`gSnWT_Wb?=vh;#aaEOOIuqdVu@i&%27kBg^_-y}`~7A${2Zx}2er z17V|p(Exw;-D~{t=9X^J8C~Nt@J|Y%6rn0yB9>HZHzav5qbL23dVq@0Q%7<2rqNP1 zk4byq%LAm2`cBj5Ns!LiQEtpW@6BsD$`vl#*Qim!REUhdU)(`ZG2XTA-#YdoNsQ!$ z#%w@NB1Q|*G6TVkWFz+389$qICZ?eGNu3Die91jkMQVFW?AmVT&wfeeJ>cGB<^%ha ztx?G(k3`5$DB1@tK^_aLJU9+IzG>Xb1;S2m&|)wzi4$psR^no$heNbk#pu(yZwpB%U#0G2Lr`^8XzOEX2K@j z?AGe+#lhqa2`j2*yp{9Ypb8i|klw<*tjwq_#KkARQi8_CjK6Thl3kQjYZ|~L=%|A zWG=~=3=oXE4EVo)`={kvs0$M?&BIfT$z*!x6kf#@8Ye`ct}pjFc59ws`aPnLexa|i zpj|ISMcg0D&TufDN~J+c_S@@@&Uwb51dS19pi*FBgvr1R z-9^iM+#$fJ%71XZimVXnX8`~O@2}S)j)V%HU!Elj*%Lg}PfrBwpbp;fY~BcxLR8=1 zELowl6$)_LUmtC|E&tcLPu)$4?#;#euP1JQRpD;5yc9%OD(fXHI+!5)0PS@CYK?#V z;}7P}AkKMj7PIb()lxp1=T_=oRIdNUf3p{F^|xxpYJPtQfdtqN2%#*hvs$$TuO*Kf%FyLW2_Fb{P|>byXN_aGd^U?O&*GWfdc{X*Ot!4v z6E7f+d;QJhz#|+?YCQffGlAVbz?Q6lz8^^2hx9`O8D}93OZp(f>Q&Lb={{>AZ{9Uf zc|-Tw--@+Z>Bp$r+lJ;K;e7A)$5+gG-v)M=|L*H|-@FSq!Kq(ZnTT^3Kg*r#!!21d z_qka&jX_TufFmEKG?-AtlF40Of0yeP&Zl6^%f-wYM4qB!<E7lPXrMS zmnasr0!7<61lU zMrXEbPvWm5?k9Wa$21AN5th&W_6ne>e%D? zGaBE>w5BU{Ksv^nIG4#fYB;Y*r+j>a)O#oQ+v-iG?xVH@WyX+;v{9B&%H+%ymMaK zzkktvK6}5=Xn~+JDz#}%)?J8ZstR#2YBY(NRzCCqef2+DZDd#wtPlAfRs(Rj`}%^D z{oh<`ld3Q7tVnCNeRc0o-!{JwIPRlRv2m&%U|7|A1P8sle`1SP5?+>MUpfV8LpV%< z_w)7vDB#NF;Ii776oW)ngIema9n{k~rmQwn4bH#->(*gqYR-Gp^HuZ3|M_44yl&2J zFoCK8n3t3 zVXZS^Fi)3=%>bg|&AXc*E&zaieko0a+!4L{MK%D)@)2MBc2XBrOZt3F!>n@D{p2!oo1GwCc&Tb9-n#2Z;H5fmK8-FO% zduS2>nx=^{Mn>1yCZdG9xwXIoLu4rcPZ#7dqkzZ4Cb!2)_AZ^HR-l)e8HyGy)s^jS z%V3lUk3et!{KnkcKl@>Y|NKv1-P{I?uMq7*Pj>p~1> zX=2_5detVr|MF5^oX;H&czSMvf4eHA?Zs0CU>CaR|d;15tc+}j;xpo~{f zr~#p&pln<-Z)P!efpJCox9{Kl$N%xW|L{Nm@DIPc`j>C6*_?}OLW~dy4U94x-&Z^0 zwC2umyVH$Yv$l4gIKE-TE*;FLIcS3W_eUiK?gs^%I94*V)4gf3TMA9?VC&zp@;FB0 zy9ME^PTa766@R+azKMWj3>KrMaR4m}=p{U#bzeSr-dY(Fc4U9WgCkOww&Q=;lAmxe zmFa`tFS`j^AN>|)al=BDPG4$~Su=A^V>G7#ak0R!KAnB>%zd(e2Xfw<0t$7mpr(Z$ zCqLsw?5^tGgJ}TAUs3xn=ADJ_wthf0JI`obe{reL{MxZg3=t8SF+|2_W(HVZ+KS6e zzL$%iSH46`#@|-G>5*P=hp+rY)&GGmn&_9)k$v;HvhNr0tn8|!UsCzPZ3e~K-gj7_QtQ)Kt)Qhq$R>rR%#+v>|L@Y47b6QEsp>)Z9rJBVII{_gv?S3JMQ z^MCl4A6ELwTIL;PKAVU2s!Hk|5OVE_Ju(#i+IvFC794KVa(kevRt9jrE&V_wEj_+q z5|ErIKog-wUh(Vde^0FPQ1^2uw|YxJ*@MP4+~EaOlmyHX8@&u5y+TDr63l2_jL`^+ znVAKL;BEOgpUf^~3JS!5B+Z274v?%7`DuHA2dWYeHiQp(^Zi%L&Q^ABhFz_V zson%$IAizRcYpWk+}pB|07em|l^(!yb{`cC|^hBW9Y*ox3+3Uxu( z{`9(ia~nGXFctAm0mc}%p)X)`%#$UUywI=T&0+@|n;|mGbls z@Y8bvN=uYNfQuOxjlhi1n{~Jih=mZo%^BeIxc^SJVd-<6MKo(upaTQt#57&Z=PGIu z>tKKU?$uJ}aq-zVZ{wS_Yu$O!xrr0fSJl6c02>Z`&5D$%^>8-pp(;H<0q?c9>l(jg zpzjw8lwq=55`Po_XYi669p~~}jjR8jiogAg95Wd|Zr3Dt{-A^X9tU8(#2=?nwjw6a z-J7v9c9BK_Bu1M#^>+R8j4u|Lp=}TwcOcw%r@D7{<#c2ne@vb$4oTl0{kHn}tLH$% zOURTI5}hG-=G3V=i&R2sjle5tmNJckb!h@CMn|};wGsJQnXNs9yLInK;Qc>nE3}V8 zBeGonrYyuF@KnYIVUG5bGx_WS&aS;M#t5iU0?|eb(fXNa67WL7^p~%e`scUZAAYG&;ERVgpf8 zW6l7kVA=jF1lQ-3=Dag_ zgEQ#Uw*EQT&h4r7kG#cpDpGa~`nI;X2XpRrF@HwQfItxy(ZgI={pN)}bGOQtmSWVk z1=hw8VNpn!k+r4oPK-v5@_yJ0G)$ko<+90Rq>ZfeEgu=MN3UU~R<_@hbg)_zT;#v3 zJBNxUG(bE$6#W?aN0WV_Ux82UGY2s5Y3t+@b7 z@tYs70%xn}UtP!R&aI<0i@BMps&}y1l_fW`eUK9artdurf6HpF#S2JlOP{elf3FGC z%0jN_dh=G1GrvZz|J?d861`m@| zHnCiUW)xt(HWH0<-Z`N$1j5v-A&SB|CCy@Fh?@P_k{{5|EN|r=Wc`PmnuO7E2hN<*;>_`xZ-4XLadkCw5QvEjkk$|k#&Y@#udinsa!XlW?+B09i{AT4 zj`pWI^*qD;qg8tJ4mlZMD8YLk+$bA3iy_id%}Nbc85R{nsn*WX)2^Tbj8OlcIrJT% zLL5XaSXdVzOyCzkEb+RV{prV>Tk{a-oTC|bcy8Vak2w0|JSaEdR9~UEYcZOrP+$ZV zSIaI?R24B?E*fXK4tbh~?8#ApELhXHXi*ih#i!3NoDe`Td4IDKht44CqM7$DgmAhF zC*AqoU3-UBV7D>iE`R~m9ALy*?7B`>LkP(XvJ0IN1iBCcWQFGIAFqSWh_kPMcpqG& zUSR7+#nH@yIsq-&qiN5%?7fZ)K{i4EPSmM5)t;H7DozK=X2Q`DrsT4kt~3=aAA`ae zTA6$1rb4Aw1@zCH0{kVU47F`&`4RO9V#A(1f0R>ay@WcAlCx3YwmHx7oR&T!VpR8& zfW%}&A%pLynE?pV2w8X587UeK5n>GC_T8_a&%QXbbF2`9b6!=Q=;rU1PS&QYiF0nE zaZC?vGfdcHrVb2|Ae)!{FENrL#Db7b+7tWE3}_n7J%O1^Ug$A0M(13N zA;xHCDSv8k{jXfb@zd>MyW&muuXP8P!8^7|xdE+=WhT6Dvc ztyC)mx;|n|#hjQ^IuR8ZwA1rHe0TlF*XuVc?V==E<1WI_F8ObL@gKRqrByw#oGO9% z>2c3T?4ox{G7?mY#MN>|XlT1d<6l0z@B%X!33-YnpeNS=sA>o%3KHJo^2{{~SXAei ztG10WKvYOZW7(@tkGuBnQVTur+U}3PGPYnYkETg}YQ`lD0F^p^2hJqtTCs% z{PE4QV``G=VP2vjI-$TSxMdv1UN36pwkmK-asnOfpR1IBECQ<~0Ww~-bqI>j*ngd7 zT;+U?hY9^Qshb0jI=T8mNOl!xy#1L6Ejxy9rD>(H<|c}0jt3s3z%US^U9`^FMOcJO zhSdz8p38IJo}q0JRFX7DA#RtJ_xOp&{ovl-Kx6cC<$<@!;||hq9XtlNRyEj7r@Y%v$FQ+3JL5IGjqRx!! zoKv8^Im7z%3%PKuGKA12z+@d_m&iXdnFDYf6JA~Fd{m(~@nH^f=>hUMqwWFftOAyx z<0`vsNb?n~b-?IL{QP@wCd8xP8rbIt_jJ1QW;_apz+_GGo2jjF~Z z)esn|>S&Ax`o)je>u+CQwR(0Fn(yD-27?GZpfr`}B<4sx8I)U-ResYPBUS$up;Ly+ zz7pV<6v+b5U{VuMtBl?%9Zd4KMv^be*ogw;q}se;>@d5$<93?=YTd{a-<;3fDF6{=H7dV*>#U5;So>q=7qGY#NQK?F_|O)0`W#sfm4dvT={YyK07zZTPM*I3`TJs zv0S%ED()f950zix7NOVXmO8BMyYGuF8Ykd^{v1Q|!wrw-Vy++q2G7v~-nR;5@8gdV z;d4BTs9J@d&|Sd$sq4RHgOcGl899qel@p&+hnX-FC+cC2QIrJK`E_((y^UXA;fL!G z-6Dz`*4`sLSoiq6?UyHQx_F-|sD~8LiPdF-04wNXU9pi!JH07IoqIZXf#6r_?J zfK<}7N(Il(W{tqi2)SCqfM`hkfpPHRsrtXeGmjkq9r5O)g`So_H#0M14x$&5Aw(0s z4f4&8S8Fyw7vH^KUA3fm6;-6sYZNgRx@v*$Rkl^N&x(#ejr*;Aflw4$RT41!{b}M1 zU1f?DX-|bbRpaJ)gjLzjwj0bq=s=!YUo02 zqeX~_I*7*3g_~zh`1H&!eCJ`poTdp$69C;>-}HjuttPEFp3by&qH-uc^Wc1Z>kr*k z6+P|*<58>s;ck?k!4Cl>S|npni8eA)A_d}9op(*6jWTg1SW>|9_3(7@w>u_d9Iqa$sxaqVKOq^LLOsts+3lVL5# zZGR&EFokwQjxPpx(oXIx7un+!yfH*&s>JJ6Y|JC7#>EBxS3#8x+@nY}2Py9zTE)QE zNKn~9QrR?w#Fy=00G_lGo~7+fMOD-#XhKq^3ba|gZ~Zs#;#Y6h*U@)$gmSxs_T8vK z4~GH|vWQQ_p>)(@qyXY15GJ@<65?T0#^>jYMu!5X$m>o?z=xI=Ri%YYs4zUgI8zIt zscYU`-I^jY8(!P#Dtx3q;l9y>gUA2mX=XO8Ap{L1)y=+pvwU^c>ipSF$M3I~D|O<$ zLWK$nL5TIxdofoYrRr9}L@ch)iGEWU^CD6*-WA36zow%0Spehee~_A?_YRVpi8S0c zl9iD?2!xR}P{#fb77eoTan~MTlXF~kNgLii83W9m*lf%+Ui2}jq{R%&wrh=Pl~b6; z)ibyL%?o#->zQ<*0h%^H3b4(*d=KQgzeqaL*7M+1da#DuuloIYjTuwzKKTnW5bDG! z$P^bPCeGBgK*x;nD^#JyOKY$c)hhDlXT99rb*ghP|7&aN+*aklp0;7vRkvkmCTgHK zry?+_IsrY~XTJN}7tK6exv*+fV+aO;Z;AQ8^ zurUV!25i5d^i}2f&=shR!%Yg%Q~yMjVT7Ce0U2wwMt#MQHn0hVZS)M(L>j`ItuBG8$gFQS2vm(01GdlUs&uf zGdxZ2$|u+WhzLTA>HcwwXXmPjPQ=Lf*ULbN%eImt`isB(c*h&{4s5?Yn?d!4?5qDY z3mf4>l|hb(biuy+;a$twZIoBn%lB=F&QToUATHI9Deh8KMCf|o<-*#mIQj#pu3vL? z?Bblq0uU!UhJVt2(69R(rp6 zl>o50&GcU}vtTihR0Wg<#xRrcavncFGtZSGW<$Nca2!`I*d6za9ez8za(s8a>Ubph z$b$Z^cDhe$3#5=@=wbhS z6$dZ5J%s)vug~oPwAI{fC_j(?e#JQ%-$^5KU`n8LOMrr5Kr|G=S&@yN;-22mwEwJ z84>XZ*EOlqVa6j}nbhlAkvRL+zIXPVz&U&N@_J%f*AS28|9B_C z=u_$easmJ(_6harmow%BH<2VD#mx==^5g2qWp{0e9^zBSo`fKk(4znE)2j}SIr95G zH}~`a2dx;7EbjNj2<*8jw*HbL$c92xCq9{@sT0Sru$$jJ_ZM?m?7TXm3r4DjV(v7F z^x9ftZhmo35ZJEjf8x-8%wa!vXuyp%a9a<6ZLUq2juzRcxo>tI)ns7We2tP}FtWwU z*#OnL=Ms$NQmlbOJk%v!M)EHaif_)odDs2<_3G8zYcuZWaNemayQ6;K1KxwbfGW!f zTrUwK%&3Az;};FQgBe7`EUGJcVW$RQFNkFTobv*;7-5)uTrL`r(LmQ+-@*uisEVDg zy`OZKrNERX%n2$Yu?mj`V+tNJV}!dk{qw8$YhA1`d$+c$Rit=zO@gxl6QNcs0Bk^$ zzpP4Pl%vP#N7X+tp8sr;`+J-|+jm6!9l=C1wm>#YS_vHt^=!F?Np zU5k5vBz7wS@+mSkiWx=Vgh?%%C|WiI888|Dvoq@$1EUxl<3hR@^Z4={E-syzs;UDt z9Tx@mIU62CJvaZ%?FE)>KWcY1?%dsF{p|18RMrp)w`YxvGUv(Sc8zadE&u6{-~Gcs z|MB1c^5$k$8Cp?PR7xykI=K89A}u@IsJN&4+|otMzUje{qJlk@=q|!r?Rh$QaSFwg zFh(f6SC@MAnHO)XXFfceg)`SlY+LiuoD z8KNN~4>Ljfw!^B6Q6*?lPwBdOw|*(NfA?H9TsI9N2#gVtN@^mNxUIaVtwniHZ`fM# z*DstlGrhNKISw2fBkjR)H(kazzH;aO;Yo>rg`!lUBbCr}>nf?FR5_q#&>4RJ{o5P& zeCWAfg4n$aQeA_1q=hi&=fj&6}+a6Xu_C*BLHuEfj8>5R&M&YsJi>>;kmqqOV zO?Gt)$B4_vL?A@0wV~HW%`4TFzg4YUNc(r6=*wo=@YW&1Xpw7%6=D~hMNNjiU?gIW z3!~8>RGJ!d9!eh`T&4!H-z_>>2Xmmpj9dqf{OFg*$;!#Gky`Th>C5Qa&cDBfd$nb` z2rPHSW@JpiX1`51L2}1clwBYv&zK6GqHGqKm#R`*M-0DpS-~hmr%_13=(VU(%0EZ5#x^zMJ zA={WaJUe$@r3;bjZf@7npw4BhlGEdeJ+h|kZ^?oj4|DH$1!WZ7lFwXWa4i;RW|0<~ zrs=xa27LSKZE%a=&%S%NTy?7c9Ht7V0zq_QiXdVlbPzXabn7bosExMha!?Q8yH1n zssloM=4{60-+y+l-TRpun1tHOJlxhSh8~}z{XFSSO!Tft?-(ZW{^D=P$ItnGFIRCH zX4UTQ{r_o#PMS{U9TpKYusFnE6b#*uwfMBxx1)!a2hRANa-i@1+wS5JZY9o*pD?(b zi69lgX?1G66YG4q`OVA4Le`#Z2UB%$z9ZUb(K5X&-}nP>y`a29`Mw2K>&LAJ(ywJV zc>e(Rq}^W`vU?}PuF~)i^=*MCkO0KIo)-Y9*!<_gmkh(S0^Uncl-Yg+iZYmWhQLS- zOmm>p1oU13ic~qg`)_zvO4dvyqfe(eKf}CHVSvbT-7ec?1a!Lm zKJ1=)&=Eo?E;>hz8cc(NVkE>UUEsQnCNWq`ao5+&uwJY2_O^Zd_9mLBdJ;|*v`qWS zynJf1PZmpYU@6%*(ap7zc~w1#4B1{&^tpI<>ZT9$_`y-sX|FCo@%+(3q3CsB)o*ei z@c2WFfcAeys1h5chXiUc4JO9IlVSwvjV|T>ng}UA`X<8h`m>jMzKAnV1)VsBD!gJQ zn5E;9&e|@4?|zBJ9>0_a2B(Ik2TyZm4%DQ-S9LyG^ePuK_xZC%x+`S|5^Q30ZERcXqA);6P10^b4n#4K6)9-X z0&*n7mz^j;hXJf)Th?>WjEGR;;%w%W5E%6B z`?j-90{1WIaisarF*p3d^?gqpAcUg|g<{kQi%JkQ5i?QOh|^#Jignv|>n;TQ;fHr2 zI_DRqmIf^r63&3oq*spJEAe1J8 zWV@`!8b_a|ypNOsX+uUG9e4+*g6!E=2R_F3{72FAD)UV#p}bRyOM#i{h_7MT+e1is zDIF%6z4mN03Bjgo^FT?JB-d7`qdGW;w3R^ID<%%#n3n6)8`k8Xf&#S^>%5JLQG6>YF-~uGVZSakINKLCum8Kct7;+K6t-U`C%n9U6rUXW(57|M(I1lB znzt!-EMIGZ*=W3sE&RiNd&=F#AWncN)zc|Oz%)2; z3McS_CT(r%j2hvCE?(WVI)4$+z$uiGG(l$;0ZSehmgdx!jk<6*z;0I!@Dqj!{Jhr_ zP?G}2;nn*ar~~0>pFCS6pYHzp$B1=0Uc?Qrj9llPu&eSzwl(K#bDHwBHz2099iX+fQcv^a3tkFT6Ma2B$8mL$y!I zQPe8FgDyb3iuGeSJa-LLKGpiC;{M@{-~K!L-aq|Fm2e@bsKSdVl+aYn_7SvV78(_e z>jhSy%2ZEUR;K_MgpZL}l?00#FilC?%;k`|AtkaWmKAN}(V+X{Cb*y(LPj2?!- z-CZi3iOW-+5Iiz@E33I~nEDsDXh<&}=oR4oZi3AVU>I4X*AClO3fYD#^QI<}lPjG- zNiQO_6n;td@bjBa{>Q(5yR>;5Xl8KQSrh?iu;lWfG#VpQ*S33W{>X*%Lp&9-Zz9KyTCQ7i*H zD0u;;a7P(@JSsf^3g-vtWnl^tvd{by8BiZB+E^|1eV-4I--IPL0{H`OhhkA?S{QmJFxy3(E*Z%a7Mh62IcC00?AA?SJIF6Ze2iy|P?=9oRTo|>QX z(+vVktDaemF$&;-XJ?Htibxdy>K(=Xay>wgu2E#0tEBG73GNmmC?G`Wgldu(CQYta zu~SG45zYsh{ipx=-IDV*ihA!F2Qfi(3Ru(($>@-!0?9cu~ zt@VBNpW`7_`XMuGg|VQTb{Ex|Y_kuM3Juyb%ii7ZKE#El?sO(6ae%*apClv##AqsP zG94)S8meE1u#O>VI%vUL@Nxa}oX_WR#xR30MvH7_vuIYlL!zjaZB{pkSAye2me}C| z`hoh}kI+J&9zVN=VZU+hF>B*PTyFLN|HD^$vK?IU-ePZ;HlH;iw2Qe{3ulfO+I=#& zxvVs<7^2XVE=0DmBtGZZLY9S107*qgF_ z@h?ATHpcq4uFaiy1d>RNk;2bOf7nCTFzdt(YE)gG7NsPw_T_P3XX zv7k^}%GM3$&jjh;G@IY4c)KgNIQdUcM#1&4o*Yp;NsEXk5b+k3k;%C(8kg&K6@rNv zD1@`tKn$UxvP){I+>(Oai|qFPSEADN=!{@Q#gx<~3Jg z7Gn&~3u(?NVmIgd*Dw5qUoG5PLR534KsA`PF-C(C5HrL?B?8op?2GVhqd&pEg#>NN zFRc&V<~DR>NjkEhwLLHABqL?y#zxXg{K<}cHm#VI9sng2Y}7*ZzN_WSHob~icO8k} z-?LSb@=-($&Y%Xh-b6@}DG=dP(vby$IVVwciTVHf>g^wYSgmoUP1AL&MnuhofrtQ1 z#3+$8&}f^<&09BXOcPOL!VR9B!L7^YF?Yu=ZOw@U72p2&hHjQ3`F{1;1w(OFCX?`& zgsQW6asj#%u31%VjpBR;kEmdT+;-MQ1jES<^ib2kM*~oU(*=9J%i*NJc@LF=P@c)< zDXUp%vFq5mv;XgZ|9zM}zl}oG%!Y(zyU!f3G8Dlo=n0dFoKsH#YI9{7Gw*@gd3X35 zb7D`OLeNM-@4I`L;vRiMSZ>SPN>rGc- zL@=ylg!3Ur8a>3v?wRjCyTnYE4O$0LxcnO_p}AwiKn9YDnbIZ@IN2w*8}02)4t_{c zxE~4o&(V)P&AuLQp9Wa-$ z!1~uO{T#~+uL!YGA3}`8ZQFK4EEs=g2||zpt;S=>$sLpPu8uy=N3Mr?8RwDNv#gN& z>8hfIx`WCuZllG@dVm4-XD=ShR&O$7(xXoU7{3cEW9Xi1l+zg!{7*58K`EMT=mgnF zR3R!9niEqoCm__Hy?EEUfB4;Bmf|~V9>m1r`I8Tog39sV|0ool2Zmt$(r7}2!09?- z9i&Yk2aHr^}<4k-=k;0nA)d|E_{vtq^hY0NQs4KH?3z%N;1qY68tb zp}@qLwA-$Wk)$-|U%kffzFl>0q4OD%LZF!aXT5LX;UxD@87x6H?Q4llnL>OM&oXHM zCQ{nk@hwwZ@;WP3ILp8Vsyhm;mi5Z_v)2O*789Ex>7x$nUM1sx^sz^>w<6`K-LWCZ zv3}2?11zzTj&NkJ(_m+84XrUbYboJkoU{A%Jia{d8d*EBWYm;N{~D1|e=qQWiZ~I0 z7$mArU4XD73Sd`DaMzM+7h<|~R&c8RPmhOdc^|T_9-|r9>6xXOUa3$ARe>myt-q8Z zXCh9jsE5s^eYvpD&c$`hIZR^k>J03RZL}^XZy5-MW_won>9>GK@!#Nhz98Iwj&@Of z`q%brvKGBW@|O@TRL|bgVH6iL5K0H%2n<#eJ^QrYDW<1M3piEnO|I7f^eT;H{h2ib zDHA|T4!sFYX+m?55T(=e-~G7${VN2Shd@>5oKFODLnJ9tg^m!*Os)g@49DmO4<7K7 zL~1JlYQXy?x(HGnxM*;(=*5Aj2H<{eRSut&{{IAom?=KFJaaG#BIMP(^~nVE;JtTb zT-5#UX93J2X~qa43@~8i^URJn%&Cd8>O&2{tX=sw+7ctO^BKfDjCU-w+W85rHY&#+F}P zx^r#4tt7SrBg914k)6?!{{jRQ0|x_yEd`}aN6K=CJ?L0Wf6MXVR=WQn`Q6b?_4Yy9 zj|E2V3q66e_nngp*PXsUuxWi-hrv(W>iR^my4Oen!<0$Zjhd>d(B%zF(VSgz{vZG8 zPixFg<C$2#A#|1u5E7l9NfxK}*nMHu_Bp(5~R1Uw98dAPRnXb4xf?=NLbGe&H1s zId%!*z*~D_$L2|D0IL5cm^YCX9r4-oOGPk?;+j`)Z%j`Oz$4W3_gf~?zf}Y0#*7bLPsX7`9WS383D&|A> z{xb+nKqCUNj$B7GC?JhMyVaStpI_=TAAGn~vg)1y%|1#ZD&iE*L5Jy$VnV$=XbHOK z>N?)ne-EI$-^cy*_$#jOA6U5G70AB_hpoP^H{WObeN+Gr3egKrhbp&HF=`joe8JKbH1$_&ARpJolcg zKJ#(VRsl$4)PWSr66`fWa#2*glVvKuPrs^dTTJ?vOv-Kr8OGYGa2d=Z97@Zk1|=mz zNfi-Eg0GznHFaecml`}j$$IK~dR9&vS zReNdx9@;1D>GBWS1Th;(7#YnXE&0hLvbc71ouB`wfBN$hvzDUH&zyI?&srYc=1{M~ zNw;L1ko=NGMn!y~mkd#h8{2IUhD-0vF!62JTATKJOuy*}WNP?O8}U`3)RDnJcS^uL zehJ`-fxs&YL z#9{Be)0V$qOo_eD=m-0RpUO(;^!R!80LR>qTM2A;HT6HDc-=0VuYqJuzA~B}E=xBq zs!rgXcvaW0n5xpiTv&c~sV^^tVd!n6ULZkOC?+6(V)hJsR%)M1 zZ9tL-r0PGb+9(P&ixh#Io4fe0|NQL@g?&cwhO13pfZ7PYuA~6}RS6_eT&(1~6}Mc|KP~q#4}X_or>{p10*5 z()p2N!~_YM1zH4?Ntsa8$hK{TFwB1UZT#cwb)3yiEQX-T)|1(IQjskYL{wd(0;OzW zO40`p9Q~XCFs}Zm{O`$csJpk-t=s%i(Uu|dj$NF0GXLIVi21m+OFyHZ9Epl+o0cI1 zX~r&c9oZ346yiWi43~3#`AipX?HGK|am}TNBU6f{6XuML+{h92`PuVFP249Q7^=Ff zaoPpJ9<;$ewGDs8J;1}Su}8UE4@Cs-R?Ywp>Qz$)Y0fUmH>avP5vRqshU!GU2O8@< zuRnX)EM`z)Bq>UfXb6F!Bh8RS0NiztY}*v%AuQ)nc;fDIv9t$UdH?{MrT-3aXPYhQ z&<~8^e3i;(TGAwWOYPUo$%^_~b?}&WxerM2zt>{h>N4*i03~^YYQN=Z$$UU)JId@& zKdyiOovjUBY!eciby^aDfJ!I12?^~X@NBMrQ?sd4eSdU6_2yknLmU`iTwXSAa!O=c z+nySL{T&s-ZN%Q{^GCFJ*(@; z8x%m|g=T&s#$G$p`{`uXX>nUighU5*LG(J{)e7HS**p6G&wu;<%026%ifH4V3Kgb< zmw)AeNh^Ws$gVq5gi~4@EMN#)m#NQlZ;3et=u=pez_k6UjY3x9ops`29%yfCTO z&t$SSny02)LUQW82arMt#i6}CF7Y7#J-q9bGg@2mmieyq~Uh4C3xJG|aq5z6D#o#8?ugk*v zR;Ylg^50%nJPNZH)bq@odD#n>)6vhv>O=z)5Pl`+|KT71^vzXV=|#}SQj|b1#-O1R zV;mJ*AqVRCgZXzK0=Ifn^=DZ>b0+CnDhLWKlhRZ7h99qP%r$^`*e91~9#GPvm8;N7 zbyT=Orv_mEDKIq?lboA@WP2bKl4j-wzy9pZbzKA3!GCvky;ig-BRlU>R8oveArRG~ zTGlZB47V?CJns71-HY|K`cI3L!3;4IK+`_Ll*pXd*ED@(nmz*|cA^r4(tH{OvLMGl**7Ha`f@({EL&ifsuTE6S`liTc5x0w3( zhdo6u^q*|R0*u_{%wp12Pf!^WqiK0*ZAn_c6AbMEQvL`E&zK@c5NKmG)d;<9!%Y`D zs?bR!LN~M37w6&2^X|fKeOP(4hobjaf2uI^|9K*d&rraiRmpD(_}vVImyF{HOru%JTX|Igl^HMx;(>7n4a z)^bNooXH%{sVY@nnbc<8YU_vo|4-NYsb#lx`}Q@dN-b5@8FC_%a}0p{-s|g!J@|G^ zfe11)NoK%s@&qFg2*BaK#&3vFalj*vIiC1sKfdX)BoNb4p^Cd@Z5VN76tb#wQRH*( z0k(d!>wxe1^}Fk|X*H&*nI5KTLUuRLR)!V2vv%L>G`uDNn*Pb6i(DrEYAzi$Uma

      wrV@M0ad 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 diff --git a/mobile/assets/splash-icon.png b/mobile/assets/splash-icon.png index 03d6f6b6c6727954aec1d8206222769afd178d8d..52502da10fb26ece6096647d7d7ccf54a8783fbd 100644 GIT binary patch literal 19781 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.0.4", + "react": "*", + "react-native": "*" + } + }, "node_modules/@expo/xcpretty": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.5.tgz", diff --git a/mobile/package.json b/mobile/package.json index 46f9a51..2533f01 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -6,6 +6,7 @@ "@expo-google-fonts/dm-mono": "^0.4.2", "@expo-google-fonts/dm-sans": "^0.4.2", "@expo-google-fonts/space-grotesk": "^0.4.1", + "@expo/vector-icons": "^15.0.2", "@react-native-async-storage/async-storage": "2.2.0", "@react-navigation/bottom-tabs": "^7.19.1", "@react-navigation/native": "^7.4.1", diff --git a/mobile/src/components/Identicon.tsx b/mobile/src/components/Identicon.tsx new file mode 100644 index 0000000..b05efc6 --- /dev/null +++ b/mobile/src/components/Identicon.tsx @@ -0,0 +1,34 @@ +import { useMemo } from "react"; +import { Text, View } from "react-native"; +import { keccak256, stringToHex } from "viem"; +import { C, F } from "../theme"; + +/** Same deterministic blocky avatar as the web interface (web/src/components/Identicon.tsx), drawn with views. */ +export function Identicon({ address, size = 40, badge }: { address: string; size?: number; badge?: string }) { + const { cells, fg, bg } = useMemo(() => { + const hash = keccak256(stringToHex(address.toLowerCase())).slice(2); + const hue = parseInt(hash.slice(0, 4), 16) % 360; + const hue2 = (hue + 140) % 360; + const bits = hash.slice(4); + const cells: boolean[] = []; + for (let y = 0; y < 5; y++) { + const row: boolean[] = []; + for (let x = 0; x < 3; x++) row.push(parseInt(bits[(y * 3 + x) % bits.length], 16) % 3 !== 0); + cells.push(row[0], row[1], row[2], row[1], row[0]); + } + return { cells, fg: `hsl(${hue}, 70%, 45%)`, bg: `hsl(${hue2}, 60%, 88%)` }; + }, [address]); + const unit = size / 5; + return ( + + + {cells.map((on, i) => )} + + {badge ? ( + + {badge} + + ) : null} + + ); +} diff --git a/mobile/src/components/VaultSheet.tsx b/mobile/src/components/VaultSheet.tsx new file mode 100644 index 0000000..f98fee2 --- /dev/null +++ b/mobile/src/components/VaultSheet.tsx @@ -0,0 +1,47 @@ +import { useEffect, useState } from "react"; +import { Text, View } from "react-native"; +import { isAddress } from "viem"; +import { SkurFactoryAbi } from "@web/abi/SkurFactory"; +import { DEPLOYMENTS } from "@web/config/chain"; +import { short } from "@web/lib/format"; +import { publicClient } from "../lib/client"; +import { useStore } from "../state/store"; +import { Identicon } from "./Identicon"; +import { Button, CircleIcon, Icon, Input, Logo, Row, Sheet, s } from "./ui"; +import { C, F } from "../theme"; + +/** Safe's "My accounts" switcher: the open vault, vaults the device signer belongs to, and a way to add one by address. */ +export function VaultSheet({ open, onClose }: { open: boolean; onClose: () => void }) { + const { vaultAddress, setVaultAddress, labels, signer } = useStore(); + const [mine, setMine] = useState<`0x${string}`[]>([]); + const [adding, setAdding] = useState(false); + const [addr, setAddr] = useState(""); + useEffect(() => { + if (!open || !signer) return; + publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }).then((v) => setMine([...v])).catch(() => setMine([])); + }, [open, signer]); + const list = Array.from(new Set([...(vaultAddress ? [vaultAddress] : []), ...mine, DEPLOYMENTS.demoVault].map((a) => a.toLowerCase()))) as `0x${string}`[]; + const pick = (a: `0x${string}`) => { void setVaultAddress(a); onClose(); }; + return ( + }> + + {list.map((a, i) => { + const current = vaultAddress?.toLowerCase() === a; + return ( + } title={labels[a] ?? (a === DEPLOYMENTS.demoVault.toLowerCase() ? "Demo vault" : "Treasury vault")} subtitle={short(a, 6)} onPress={() => pick(a)} last={i === list.length - 1} + trailing={current ? : mine.some((m) => m.toLowerCase() === a) ? member : null} /> + ); + })} + + {adding ? ( + + setAddr(t.trim())} placeholder="0x… vault address" mono autoFocus /> + + + ) : ( + } title="Add existing vault" subtitle="Open any vault by its address" onPress={() => setAdding(true)} last /> + )} + {!signer && Add a signer key under Settings and the vaults it belongs to appear here.} + + ); +} diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx index 1e0b866..4ea94ce 100644 --- a/mobile/src/components/ui.tsx +++ b/mobile/src/components/ui.tsx @@ -1,42 +1,88 @@ +import { Feather } from "@expo/vector-icons"; import * as Clipboard from "expo-clipboard"; -import { useState, type ReactNode } from "react"; -import { ActivityIndicator, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; +import { useState, type ComponentProps, type ReactNode } from "react"; +import { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { short } from "@web/lib/format"; import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; import type { TxState } from "../hooks/useTx"; import { C, F, R } from "../theme"; -export function Screen({ children, title, sub, right, refreshControl, scroll = true }: { children: ReactNode; title?: string; sub?: string; right?: ReactNode; refreshControl?: ReactNode; scroll?: boolean }) { +export type IconName = ComponentProps["name"]; +export const Icon = ({ name, size = 18, color = C.text }: { name: IconName; size?: number; color?: string }) => ; + +/** Screen shell: optional top bar, scrolling body, optional sticky footer above the home indicator. */ +export function Screen({ children, top, footer, refreshControl, padded = true }: { children: ReactNode; top?: ReactNode; footer?: ReactNode; refreshControl?: ReactNode; padded?: boolean }) { const insets = useSafeAreaInsets(); - const head = title ? ( - - - {title} - {sub ? {sub} : null} - - {right} - - ) : null; - if (!scroll) return {head}{children}; return ( - {head} - {children} + {top ? {top} : null} + {children} + {footer ? {footer} : null} ); } -export function Card({ children, title, action, style }: { children: ReactNode; title?: string; action?: ReactNode; style?: StyleProp }) { +export function TopBar({ left, center, right, title }: { left?: ReactNode; center?: ReactNode; right?: ReactNode; title?: string }) { return ( - - {(title || action) && ( - - {title ? {title} : } - {action} - - )} - {children} + + {left}{title ? {title} : null} + {center ? {center} : null} + {right} + + ); +} + +export function IconButton({ name, onPress, dot, tone = "dark" }: { name: IconName; onPress?: () => void; dot?: boolean; tone?: "dark" | "accent" }) { + return ( + [s.iconBtn, tone === "accent" && { backgroundColor: C.accent }, pressed && { opacity: 0.7 }]}> + + {dot ? : null} + + ); +} + +export function BackButton({ onPress }: { onPress: () => void }) { return ; } + +/** The web logo: yellow square with an S, then the wordmark. */ +export function Logo({ size = 28, wordmark = true }: { size?: number; wordmark?: boolean }) { + return ( + + + S + + {wordmark ? Skur : null} + + ); +} + +export function Card({ children, style, flush = false }: { children: ReactNode; style?: StyleProp; flush?: boolean }) { + return {children}; +} +export function SectionLabel({ children }: { children: ReactNode }) { return {children}; } + +/** Safe-style list row: leading icon or avatar, title, subtitle, trailing content, optional chevron. */ +export function Row({ leading, title, subtitle, trailing, onPress, chevron = false, last = false }: { leading?: ReactNode; title: ReactNode; subtitle?: ReactNode; trailing?: ReactNode; onPress?: () => void; chevron?: boolean; last?: boolean }) { + const body = ( + + {leading ? {leading} : null} + + {typeof title === "string" ? {title} : title} + {subtitle ? (typeof subtitle === "string" ? {subtitle} : subtitle) : null} + + {trailing} + {chevron ? : null} + + ); + return onPress ? pressed && { opacity: 0.7 }}>{body} : body; +} + +export function CircleIcon({ name, size = 40, tone = "dark", text }: { name?: IconName; size?: number; tone?: "dark" | "accent" | "success" | "error" | "warn"; text?: string }) { + const bg = tone === "accent" ? C.accent : tone === "success" ? C.successBg : tone === "error" ? C.errorBg : tone === "warn" ? C.warningBg : C.card2; + const fg = tone === "accent" ? C.onAccent : tone === "success" ? C.success : tone === "error" ? C.error : tone === "warn" ? C.warning : C.text; + return ( + + {text ? {text} : name ? : null} ); } @@ -52,32 +98,43 @@ export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNo type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent"; const TONES: Record = { - ok: { bg: C.successBg, fg: C.success }, - warn: { bg: C.warningBg, fg: C.warning }, - bad: { bg: C.errorBg, fg: C.error }, - info: { bg: C.infoBg, fg: C.info }, - neutral: { bg: C.panel2, fg: C.text2 }, - accent: { bg: C.accent, fg: C.onAccent }, + ok: { bg: C.successBg, fg: C.success }, warn: { bg: C.warningBg, fg: C.warning }, bad: { bg: C.errorBg, fg: C.error }, + info: { bg: C.infoBg, fg: C.info }, neutral: { bg: C.card2, fg: C.text2 }, accent: { bg: C.accent, fg: C.onAccent }, }; -export function Badge({ tone = "neutral", children }: { tone?: Tone; children: ReactNode }) { +export function Badge({ tone = "neutral", children, icon }: { tone?: Tone; children: ReactNode; icon?: IconName }) { const t = TONES[tone]; - return {children}; + return {icon ? : null}{children}; } export const TierBadge = ({ tier }: { tier: Tier }) => {TIER_LABEL[tier]}; -export const ModeBadge = ({ mode }: { mode: Mode }) => {MODE_LABEL[mode]}; +export const ModeBadge = ({ mode }: { mode: Mode }) => {MODE_LABEL[mode]}; export const StatusBadge = ({ status }: { status: Status }) => {STATUS_LABEL[status]}; export const TrustBadge = ({ trust }: { trust: Trust }) => {TRUST_LABEL[trust]}; -export function Button({ children, onPress, kind = "primary", disabled, loading, style }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; style?: StyleProp }) { - const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.panel2 : "transparent"; +export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md" }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm" }) { + const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.card2 : "transparent"; const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; return ( - [s.btn, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, kind === "secondary" && { borderWidth: 1, borderColor: C.border }, style]}> - {loading ? : {children}} + [s.btn, size === "sm" && { height: 36, paddingHorizontal: 14 }, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, style]}> + {loading ? : <>{icon ? : null}{children}} ); } +/** Safe's sticky "Sign with ‹signer›" bar, used for the primary action of a screen. */ +export function SignBar({ label, signerAddress, onPress, disabled, loading, hint }: { label: string; signerAddress?: string | null; onPress?: () => void; disabled?: boolean; loading?: boolean; hint?: string }) { + return ( + + {hint ? {hint} : null} + [s.signbar, { opacity: disabled ? 0.45 : pressed ? 0.85 : 1 }]}> + {loading ? : } + {label} + {signerAddress ? {short(signerAddress)} : null} + + + + ); +} + export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { return ( @@ -87,25 +144,27 @@ export function Field({ label, hint, children }: { label: string; hint?: string; ); } -export function Input(props: TextInputProps & { mono?: boolean }) { - return ; +export function Input(props: TextInputProps & { mono?: boolean; big?: boolean }) { + return ; } -export function Segmented({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { +/** Underlined text tabs, as on Safe's Tokens / NFTs switch. */ +export function Tabs({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { return ( - + {options.map(([v, label]) => ( - onChange(v)} style={[s.segItem, value === v && s.segOn]}>{label} + onChange(v)} style={[s.tab, value === v && s.tabOn]}>{label} ))} ); } -export function Address({ value, full = false }: { value: string; full?: boolean }) { +export function Address({ value, full = false, style }: { value: string; full?: boolean; style?: object }) { const [copied, setCopied] = useState(false); return ( - { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8}> - {full ? value : short(value)}{copied ? " ✓ copied" : ""} + { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8} style={{ flexDirection: "row", alignItems: "center", gap: 6 }}> + {full ? value : short(value)} + ); } @@ -123,41 +182,71 @@ export function TxStatus({ state }: { state: TxState }) { return {msg}; } -export function Empty({ children }: { children: ReactNode }) { - return {children}; +export function Empty({ icon = "inbox", children }: { icon?: IconName; children: ReactNode }) { + return {children}; } -export function Tape({ running = false }: { running?: boolean }) { - // Caution-tape band: the brand's signature, drawn as alternating blocks. Static on native; `running` is reserved for Lockdown. +/** Caution-tape band: the brand's signature. */ +export function Tape({ height = 8 }: { height?: number }) { return ( - - {Array.from({ length: 30 }).map((_, i) => )} + + {Array.from({ length: 34 }).map((_, i) => )} ); } +/** Bottom sheet like Safe's account and network switchers. */ +export function Sheet({ open, onClose, title, children, action }: { open: boolean; onClose: () => void; title: string; children: ReactNode; action?: ReactNode }) { + const insets = useSafeAreaInsets(); + return ( + + + + + + {title} + {action ? {action} : null} + + {children} + + + ); +} + export const s = StyleSheet.create({ screen: { flex: 1, backgroundColor: C.canvas }, - head: { paddingHorizontal: 16, paddingBottom: 10, flexDirection: "row", alignItems: "flex-end", gap: 12 }, - h1: { fontFamily: F.display, fontSize: 28, color: C.text, letterSpacing: -0.5 }, - sub: { fontFamily: F.body, fontSize: 14, color: C.text2, marginTop: 2 }, - card: { backgroundColor: C.panel, borderRadius: R.lg, padding: 16, marginBottom: 14 }, - cardHead: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }, - cardTitle: { fontFamily: F.displayMedium, fontSize: 17, color: C.text }, - kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 10, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + topbar: { height: 52, paddingHorizontal: 16, flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, + topTitle: { fontFamily: F.display, fontSize: 22, color: C.text, letterSpacing: -0.3 }, + iconBtn: { width: 40, height: 40, borderRadius: 20, backgroundColor: C.card, alignItems: "center", justifyContent: "center" }, + dot: { position: "absolute", top: 8, right: 8, width: 8, height: 8, borderRadius: 4, backgroundColor: C.accent, borderWidth: 1.5, borderColor: C.canvas }, + footer: { position: "absolute", left: 0, right: 0, bottom: 0, padding: 16, backgroundColor: C.canvas, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: C.border }, + card: { backgroundColor: C.card, borderRadius: R.lg, padding: 16, marginBottom: 12 }, + sectionLabel: { fontFamily: F.mono, fontSize: 11, letterSpacing: 1.2, textTransform: "uppercase", color: C.text3, marginBottom: 8, marginTop: 6 }, + row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + rowTitle: { fontFamily: F.bodyBold, fontSize: 15, color: C.text }, + rowSub: { fontFamily: F.body, fontSize: 13, color: C.text2 }, + kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 11, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, kvK: { fontFamily: F.body, fontSize: 14, color: C.text2 }, kvV: { fontFamily: F.bodyMedium, fontSize: 14, color: C.text, textAlign: "right", flexShrink: 1 }, - badge: { paddingHorizontal: 8, paddingVertical: 3, borderRadius: R.sm, alignSelf: "flex-start" }, + badge: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 9, paddingVertical: 4, borderRadius: R.pill, alignSelf: "flex-start" }, badgeText: { fontFamily: F.bodyBold, fontSize: 12 }, - btn: { height: 46, borderRadius: R.md, alignItems: "center", justifyContent: "center", paddingHorizontal: 18 }, + btn: { height: 48, borderRadius: R.md, alignItems: "center", justifyContent: "center", paddingHorizontal: 18, flexDirection: "row", gap: 8 }, btnText: { fontFamily: F.bodyBold, fontSize: 15 }, + signbar: { height: 56, borderRadius: R.lg, backgroundColor: C.accent, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 18 }, + signbarText: { fontFamily: F.bodyBold, fontSize: 16, color: C.onAccent, flex: 1 }, + signerChip: { backgroundColor: "rgba(33,37,41,0.15)", borderRadius: R.pill, paddingHorizontal: 10, height: 28, justifyContent: "center" }, + signerChipText: { fontFamily: F.monoMedium, fontSize: 12, color: C.onAccent }, label: { fontFamily: F.bodyMedium, fontSize: 13, color: C.text2, marginBottom: 6 }, hint: { fontFamily: F.body, fontSize: 12, color: C.text3, marginTop: 6, lineHeight: 16 }, - input: { backgroundColor: C.panel2, borderRadius: R.md, paddingHorizontal: 12, height: 46, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, - seg: { flexDirection: "row", backgroundColor: C.panel2, borderRadius: R.md, padding: 3, marginBottom: 14 }, - segItem: { flex: 1, height: 36, alignItems: "center", justifyContent: "center", borderRadius: R.sm }, - segOn: { backgroundColor: C.accent }, - segText: { fontFamily: F.bodyBold, fontSize: 13, color: C.text2 }, - addr: { fontFamily: F.mono, fontSize: 13, color: C.text }, + input: { backgroundColor: C.card2, borderRadius: R.md, paddingHorizontal: 14, height: 48, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, + tabs: { flexDirection: "row", borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border, marginBottom: 4 }, + tab: { paddingVertical: 10, paddingHorizontal: 4, marginRight: 22, borderBottomWidth: 2, borderBottomColor: "transparent" }, + tabOn: { borderBottomColor: C.accent }, + tabText: { fontFamily: F.bodyBold, fontSize: 15, color: C.text3 }, + addr: { fontFamily: F.mono, fontSize: 13, color: C.text2 }, notice: { padding: 12, borderRadius: R.md, marginTop: 10 }, + sheetBackdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.55)" }, + sheet: { backgroundColor: C.card, borderTopLeftRadius: 22, borderTopRightRadius: 22, paddingHorizontal: 16, paddingTop: 8 }, + grabber: { width: 40, height: 4, borderRadius: 2, backgroundColor: C.border, alignSelf: "center", marginBottom: 14 }, + sheetTitle: { fontFamily: F.display, fontSize: 18, color: C.text }, }); diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index 89fa105..c6ab3d4 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -1,73 +1,116 @@ import { useNavigation } from "@react-navigation/native"; +import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { NATIVE_ASSET } from "@web/config/chain"; import { fmtAmount, fmtDuration, short } from "@web/lib/format"; -import { Mode, ROLE_APPROVER, ROLE_OWNER, Status } from "@web/lib/types"; +import { Mode, ROLE_APPROVER, ROLE_OWNER, roleNames, Status } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; -import { describeProposal, statusText } from "../lib/describe"; import { useMyRoles } from "../hooks/useVault"; import { useStore } from "../state/store"; -import { Address, Badge, Button, Card, Empty, KV, ModeBadge, Screen, Tape, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { VaultSheet } from "../components/VaultSheet"; +import { Address, Badge, Card, CircleIcon, Icon, IconButton, KV, Row, Screen, Tabs, Tape, TopBar, s } from "../components/ui"; import { C, F } from "../theme"; export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const { labels, signer } = useStore(); const roles = useMyRoles(vault); + const [sheet, setSheet] = useState(false); + const [tab, setTab] = useState<"tokens" | "policy" | "members">("tokens"); const label = labels[vault.address.toLowerCase()] ?? "Treasury vault"; const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; - const native = vault.assets.find((a) => a.address === NATIVE_ASSET); - const pending = vault.proposals.filter((p) => p.status === Status.PENDING); + const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; const canPropose = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)) && vault.mode !== Mode.LOCKDOWN; + const [whole, frac] = stable ? fmtAmount(stable.balance, stable.decimals, undefined, 2).split(".") : ["—", undefined]; return ( - } refreshControl={}> - {vault.mode !== Mode.NORMAL && } - - Total balance - {stable ? fmtAmount(stable.balance, stable.decimals, stable.symbol) : "—"} - {native ? `+ ${fmtAmount(native.balance, native.decimals, native.symbol)}` : ""} · policy v{vault.policyVersion} · {vault.members.length} members + } + top={ + <> + setSheet(true)} style={{ flexDirection: "row", alignItems: "center", gap: 10 }}> + + {label} + + + } + right={<> nav.navigate("Receive")} /> nav.navigate("Security")} />} + /> + {vault.mode !== Mode.NORMAL && } + + }> + + {pending > 0 && ( + nav.navigate("Main", { screen: "Transactions" })} style={h.pending}> + {pending} + Pending transactions + + + )} + {vault.mode !== Mode.NORMAL && ( + nav.navigate("Security")} style={[h.pending, { backgroundColor: vault.mode === Mode.LOCKDOWN ? C.errorBg : C.warningBg }]}> + + {vault.mode === Mode.LOCKDOWN ? "Lockdown: outgoing payments are frozen" : "Elevated: every payment scored one tier higher"} + + + )} + + A + Ark devnet +

      + + + {whole} + {frac ? .{frac} : null} + {stable?.symbol} + + policy v{vault.policyVersion} · {vault.members.length} members · {roleNames(roles).join(", ") || (signer ? "not a member" : "read-only")} - - + nav.navigate("Send")} /> + nav.navigate("Receive")} /> + nav.navigate("Security")} /> + + + + + + {tab === "tokens" && vault.assets.map((a, i) => ( + } title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(a.balance, a.decimals)} ${a.symbol}`} last={i === vault.assets.length - 1} + trailing={{fmtAmount(a.balance, a.decimals)}{fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of {a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today} /> + ))} + {tab === "policy" && ( + + + + + + + {stable && } - {!signer && Read-only: add a signer key under Settings to confirm or propose.} - {signer && roles === 0 && Read-only: {short(signer.address)} is not a member of this vault.} - - - {vault.mode !== Mode.NORMAL && ( - - {vault.mode === Mode.LOCKDOWN ? "LOCKDOWN" : "ELEVATED"} - {vault.mode === Mode.LOCKDOWN ? "Outgoing payments are frozen" : "Every payment is scored one tier higher"} - {vault.mode === Mode.LOCKDOWN ? "Deposits, tightening changes, recovery and guardian actions still work." : "Per-transaction and daily caps are halved until owners and guardians lower the mode."} - )} - - 0 ? nav.navigate("Transactions")}>View all › : undefined}> - {vault.activityLoading ? Reading the queue from the chain… : pending.length === 0 ? Nothing waiting for a signature : pending.slice(0, 4).map((p) => { - const d = describeProposal(p, vault); - return ( - nav.navigate("TxDetail", { id: String(p.id) })} style={s.kv}> - {d.title} · {d.detail} - {statusText(p)} - - ); - })} - - - - {vault.assets.map((a, i) => ( - - ))} - - - nav.navigate("Security")}>Security ›}> - - - - - - Vault
      + {tab === "members" && vault.members.map((m, i) => ( + } title={short(m.address, 6)} subtitle={m.address.toLowerCase() === signer?.address.toLowerCase() ? "this phone" : undefined} last={i === vault.members.length - 1} + trailing={{roleNames(m.roles).map((r) => {r})}} /> + ))} + setSheet(false)} /> ); } + +function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arrow-up-right" | "arrow-down-left" | "shield"; label: string; onPress: () => void; tone?: "dark" | "accent"; disabled?: boolean }) { + return ( + [h.action, tone === "accent" && { backgroundColor: C.accent }, { opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }]}> + + {label} + + ); +} + +const h = { + pending: { flexDirection: "row" as const, alignItems: "center" as const, gap: 10, backgroundColor: C.accentBg, borderRadius: 14, paddingHorizontal: 14, height: 48, marginBottom: 12 }, + count: { minWidth: 22, height: 22, borderRadius: 11, backgroundColor: C.accent, alignItems: "center" as const, justifyContent: "center" as const, paddingHorizontal: 6 }, + balance: { fontFamily: F.display, fontSize: 40, color: C.text, letterSpacing: -1.2 }, + action: { flex: 1, height: 44, borderRadius: 12, backgroundColor: C.card, flexDirection: "row" as const, alignItems: "center" as const, justifyContent: "center" as const, gap: 6 }, +}; diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx index 3f02587..434ff37 100644 --- a/mobile/src/screens/Onboard.tsx +++ b/mobile/src/screens/Onboard.tsx @@ -6,55 +6,46 @@ import { DEPLOYMENTS } from "@web/config/chain"; import { short } from "@web/lib/format"; import { publicClient } from "../lib/client"; import { useStore } from "../state/store"; -import { Button, Card, Field, Input, Notice, Screen, Tape, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, Tape, TopBar, s } from "../components/ui"; import { C, F } from "../theme"; -/** First screen: open a vault by address, the demo vault, or one the device signer belongs to. */ +/** First screen: the web logo, then open a vault by address, the demo vault, or one the device signer belongs to. */ export function Onboard() { const { setVaultAddress, signer, createSigner } = useStore(); const [addr, setAddr] = useState(""); const [mine, setMine] = useState<`0x${string}`[] | null>(null); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); - const findMine = async () => { if (!signer) return; setBusy(true); setErr(null); try { const v = await publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }); setMine([...v]); } - catch (e) { setErr((e as Error).message); } - finally { setBusy(false); } + catch (e) { setErr((e as Error).message); } finally { setBusy(false); } }; - return ( - - - S - Skur - Treasury security that assumes compromise. Open a vault to see its balances, queue and policy, and sign from this phone. + } />}> + + Treasury security{"\n"}that assumes{"\n"}compromise + Open a vault to read its balances, queue and policy, and sign from this phone. Every rule is enforced by the vault contract, not by a server. - - - setAddr(t.trim())} placeholder="0x…" mono /> - - - + + setAddr(t.trim())} placeholder="0x…" mono /> + - + + } title="Demo vault" subtitle={short(DEPLOYMENTS.demoVault, 6)} onPress={() => setVaultAddress(DEPLOYMENTS.demoVault)} chevron /> {signer ? ( - <> - Signer on this phone: {short(signer.address)} - {mine === null ? : mine.length === 0 ? This signer is not a member of any vault yet. You can still open any vault by address. : mine.map((v) => )} - {err ? {err} : null} - + mine === null ? } title="Vaults this device belongs to" subtitle={`Signer ${short(signer.address)}`} onPress={findMine} trailing={busy ? looking… : undefined} chevron last /> + : mine.length === 0 ? } title="No vault has this signer yet" subtitle={`Add ${short(signer.address)} as a member to sign for one`} last /> + : mine.map((v, i) => } title="Member vault" subtitle={short(v, 6)} onPress={() => setVaultAddress(v)} chevron last={i === mine.length - 1} />) ) : ( - <> - No signer key on this phone yet. Create one to be added as a member, or import an existing key under Settings later. - - + } title="Create a signer key" subtitle="Kept in this phone's keychain" onPress={() => void createSigner()} chevron last /> )} - You interact directly with verified contracts on the Ark Constellation devnet. Skur never holds keys or funds. + {err ? {err} : null} + Verified contracts on the Ark Constellation devnet. Skur never holds keys or funds. ); } diff --git a/mobile/src/screens/Receive.tsx b/mobile/src/screens/Receive.tsx index 7c40c4d..250380a 100644 --- a/mobile/src/screens/Receive.tsx +++ b/mobile/src/screens/Receive.tsx @@ -1,17 +1,22 @@ import { useNavigation } from "@react-navigation/native"; -import { Text } from "react-native"; +import { Text, View } from "react-native"; import type { VaultData } from "@web/lib/vaultReads"; -import { Address, Button, Card, Screen, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { Address, BackButton, Card, Screen, Tape, TopBar, s } from "../components/ui"; +import { C, F } from "../theme"; export function Receive({ vault }: { vault: VaultData }) { const nav = useNavigation<{ goBack: () => void }>(); return ( - - -
      - Tap the address to copy it. Send KASH or any approved token to this address on the Ark Constellation devnet, chain 9000. + nav.goBack()} />} center={Receive} />}> + + + Vault address + Ark Constellation devnet · chain 9000 +
      + Tap to copy. Deposits are accepted in every mode, including Lockdown. - + ); } diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx index eda5bbc..f98e59c 100644 --- a/mobile/src/screens/Security.tsx +++ b/mobile/src/screens/Security.tsx @@ -1,3 +1,4 @@ +import { useNavigation } from "@react-navigation/native"; import { useState } from "react"; import { RefreshControl, Text, View } from "react-native"; import { stringToHex } from "viem"; @@ -10,10 +11,12 @@ import { Mode, MODE_LABEL, ROLE_GUARDIAN, ROLE_OWNER } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; -import { Badge, Button, Card, Field, Input, KV, ModeBadge, Notice, Screen, TxStatus, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { BackButton, Badge, Button, Card, CircleIcon, Field, Input, KV, ModeBadge, Notice, Row, Screen, SectionLabel, Tape, TopBar, TxStatus, s } from "../components/ui"; import { C, F } from "../theme"; export function Security({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const nav = useNavigation<{ goBack: () => void; canGoBack: () => boolean }>(); const roles = useMyRoles(vault); const invalidate = useInvalidateVault(vault.address); const tx = useTx(invalidate); @@ -26,51 +29,64 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; const loss = stable ? computeMaxLoss(vault.policy, stable.limits, stable.balance, vault.mode) : null; const canRaise = Boolean(roles & (ROLE_OWNER | ROLE_GUARDIAN)); - return ( - } refreshControl={}> - {okCount} of {posture.length} confirmed}> - {posture.map((i) => ( - - {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} - {i.text} + } + top={<> nav.goBack()} /> : undefined} title="Security" right={} />{vault.mode !== Mode.NORMAL && }}> + + + } title="Security posture" subtitle={`${okCount} of ${posture.length} controls confirmed`} last /> + + {posture.map((i) => ( + + {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} + {i.text} + + ))} - ))} - - - - Any owner or guardian can raise the mode at once. Lowering it needs owners and guardians together, and leaving Lockdown also waits out the policy-change delay. - - - {vault.mode < Mode.ELEVATED && } - {vault.mode < Mode.LOCKDOWN && } - {vault.mode > Mode.NORMAL && } - - {!canRaise && Only an owner or guardian signer can change the mode.} - - + - - {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => Guardian} />)} - - - - + Security mode + + Any owner or guardian can raise the mode at once. Lowering it needs owners and guardians together, and leaving Lockdown also waits out the policy-change delay. + + + {vault.mode < Mode.ELEVATED && } + {vault.mode < Mode.LOCKDOWN && } + {vault.mode > Mode.NORMAL && } + + {!canRaise && Only an owner or guardian signer can change the mode.} + + - {loss && stable && ( - - - - - A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. + Guardians + + {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => } title={short(g.address, 6)} subtitle="freeze · veto · confirm · recover" trailing={Guardian} />)} + + + + + - )} - - {vault.modeHistory.length === 0 ? The mode has never changed. : [...vault.modeHistory].reverse().slice(0, 8).map((h, i) => ( - - ))} - + {loss && stable && ( + <> + Maximum possible loss + + + + + A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. + + + )} + + Mode history + + {vault.modeHistory.length === 0 ? The mode has never changed. : [...vault.modeHistory].reverse().slice(0, 8).map((h, i, arr) => ( + + ))} + + ); } diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index 5d142b7..a6e32bf 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -10,14 +10,17 @@ import type { VaultData } from "@web/lib/vaultReads"; import { publicClient } from "../lib/client"; import { useInvalidateVault } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; -import { Button, Card, Field, Input, KV, Notice, Screen, TierBadge, TxStatus, s } from "../components/ui"; +import { useStore } from "../state/store"; +import { Identicon } from "../components/Identicon"; +import { BackButton, Badge, Button, Card, CircleIcon, Field, Input, KV, Notice, Row, Screen, SignBar, TierBadge, TopBar, TxStatus, s } from "../components/ui"; import { C, F } from "../theme"; -type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust; activatesAt: bigint }; +type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust }; -/** Send flow: the vault itself classifies the payment before anything is signed. */ +/** Send: big amount, asset chips, recipient and purpose; the vault's own review card; sticky sign bar to propose. */ export function Send({ vault }: { vault: VaultData }) { const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); + const { signer } = useStore(); const invalidate = useInvalidateVault(vault.address); const tx = useTx(() => { invalidate(); }); const [to, setTo] = useState(""); @@ -27,14 +30,14 @@ export function Send({ vault }: { vault: VaultData }) { const [preview, setPreview] = useState(null); const [previewError, setPreviewError] = useState(null); const [loading, setLoading] = useState(false); + const [showWhy, setShowWhy] = useState(true); const asset = vault.assets.find((a) => a.address === assetAddr) ?? vault.assets[0]; const amount = asset ? parseAmount(amountText, asset.decimals) : null; const ok = isAddress(to) && amount !== null && amount > 0n && Boolean(asset); useEffect(() => { if (!ok || !asset || amount === null) { setPreview(null); setPreviewError(null); return; } - let live = true; - setLoading(true); + let live = true; setLoading(true); (async () => { try { const [r, rec] = await Promise.all([ @@ -42,7 +45,7 @@ export function Send({ vault }: { vault: VaultData }) { publicClient.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "getRecipient", args: [to as `0x${string}`] }), ]); if (!live) return; - setPreview({ tier: Number(r.tier) as Tier, reasons: Number(r.reasons), exposureBps: Number(r.exposureBps), requiredApprovals: Number(r.requiredApprovals), requiredGuardians: Number(r.requiredGuardians), delay: Number(r.delay), trust: Number(rec.trust) as Trust, activatesAt: rec.activatesAt }); + setPreview({ tier: Number(r.tier) as Tier, reasons: Number(r.reasons), exposureBps: Number(r.exposureBps), requiredApprovals: Number(r.requiredApprovals), requiredGuardians: Number(r.requiredGuardians), delay: Number(r.delay), trust: Number(rec.trust) as Trust }); setPreviewError(null); } catch (e) { if (live) { setPreview(null); setPreviewError(describeError(e)); } } finally { if (live) setLoading(false); } @@ -52,23 +55,39 @@ export function Send({ vault }: { vault: VaultData }) { const submit = () => { if (!asset || amount === null) return; void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [asset.address, to as `0x${string}`, amount, memo] }); }; const remaining = asset && amount !== null ? asset.balance - amount : 0n; + const reasons = preview ? explainReasons(preview.reasons) : []; + const done = tx.state.phase === "done"; return ( - + nav.goBack()} />} center={Send} />} + footer={ + + + + {done ? + : } + + }> + + + {vault.assets.map((a) => ( + setAssetAddr(a.address)} style={[{ flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: 12, height: 34, borderRadius: 17, backgroundColor: C.card2 }, a.address === assetAddr && { backgroundColor: C.accent }]}> + + {a.symbol} + + ))} + + + {asset ? `Vault holds ${fmtAmount(asset.balance, asset.decimals, asset.symbol)}` : ""} + - setTo(t.trim())} placeholder="0x…" mono /> - - - - {vault.assets.map((a) => ( - setAssetAddr(a.address)} style={[s.segItem, { flex: 0, paddingHorizontal: 14, backgroundColor: a.address === assetAddr ? C.accent : C.panel2 }]}>{a.symbol} - ))} + + {isAddress(to) ? : } + setTo(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> - - - @@ -76,24 +95,20 @@ export function Send({ vault }: { vault: VaultData }) { {loading && Asking the vault how it scores this payment…} {previewError && {previewError}} {preview && asset && amount !== null && ( - - - - - } /> - - {explainReasons(preview.reasons).length > 0 && ( - - Why this tier - {explainReasons(preview.reasons).map((t) => ▪ {t})} - - )} - + <> + + } title="Transaction checks" subtitle={`${TIER_LABEL[preview.tier]} · ${preview.requiredApprovals} approval${preview.requiredApprovals === 1 ? "" : "s"}${preview.requiredGuardians ? ` + ${preview.requiredGuardians} guardian` : ""}${preview.delay ? ` · after ${fmtDuration(preview.delay)}` : " · no delay"}`} trailing={} chevron onPress={() => setShowWhy((v) => !v)} last={!showWhy} /> + {showWhy && ( + + + + {TRUST_LABEL[preview.trust]}{preview.trust === Trust.UNKNOWN ? " · registered as New" : ""}} last={reasons.length === 0} /> + {reasons.length > 0 && Why this tier{reasons.map((t) => ▪ {t})}} + + )} + + )} - - - {tx.state.phase === "done" && } - ); } diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index 59a601c..b877f3f 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -1,4 +1,5 @@ import * as LocalAuthentication from "expo-local-authentication"; +import { useNavigation } from "@react-navigation/native"; import { useEffect, useState } from "react"; import { Alert, Linking, Switch, Text, View } from "react-native"; import { ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC, DEPLOYMENTS } from "@web/config/chain"; @@ -7,70 +8,71 @@ import { roleNames } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; import { useMyRoles } from "../hooks/useVault"; import { useStore } from "../state/store"; -import { Address, Badge, Button, Card, Field, Input, KV, Notice, Screen, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { Address, Badge, Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; import { C } from "../theme"; export function Settings({ vault }: { vault: VaultData | undefined }) { + const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const { vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics } = useStore(); const roles = useMyRoles(vault); const [name, setName] = useState(vaultAddress ? labels[vaultAddress.toLowerCase()] ?? "" : ""); + const [importing, setImporting] = useState(false); const [importKey, setImportKey] = useState(""); const [importErr, setImportErr] = useState(null); const [bioAvailable, setBioAvailable] = useState(false); useEffect(() => { void (async () => setBioAvailable((await LocalAuthentication.hasHardwareAsync()) && (await LocalAuthentication.isEnrolledAsync())))(); }, []); return ( - - - {vaultAddress ? ( - <> - - { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} /> - - } /> - - - - - - - - ) : } - + } />}> + + Vault + + {vaultAddress ? ( + <> + } title={ { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} style={{ height: 36, paddingHorizontal: 10, backgroundColor: "transparent", borderWidth: 0, fontFamily: "DMSans_700Bold" }} />} subtitle={
      } /> + } title="Policy" subtitle={vault ? `v${vault.policyVersion} · ${vault.members.length} members` : "…"} /> + } title="Security" subtitle="Mode, guardians, posture, maximum loss" onPress={() => nav.navigate("Security")} chevron /> + } title="View on Blockscout" onPress={() => void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vaultAddress}`)} chevron /> + } title="Switch vault" onPress={() => void setVaultAddress(null)} chevron last /> + + ) : } title="Open a vault" onPress={() => void setVaultAddress(null)} chevron last />} + - - {signer ? ( - <> - } /> - - - Require Face ID / biometrics to sign{!bioAvailable && No biometrics enrolled on this device; signing proceeds without a prompt.} - void setBiometrics(v)} trackColor={{ true: C.accent }} /> - - The private key is stored in the device keychain and never leaves the phone. Only signed transactions do. Give this address a role in a vault to sign for it. - - - ) : ( - <> - No signer yet. Create a fresh key on this phone, then add its address as a member of your vault, or import a key you already use. - - - - - - {importErr && {importErr}} - - )} - + Signer on this phone + + {signer ? ( + <> + } title="Device signer" subtitle={
      } trailing={roles ? {roleNames(roles).join(" · ")} : no role here} /> + } title="Require Face ID to sign" subtitle={bioAvailable ? "Prompted before every signature" : "No biometrics enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} /> + } title={Remove signer key} subtitle="Deletes the key from this phone" onPress={() => Alert.alert("Remove signer key?", "The key is deleted from this phone. Anything it can sign for becomes unreachable from here unless you have it backed up.", [{ text: "Keep", style: "cancel" }, { text: "Remove", style: "destructive", onPress: () => void removeSigner() }])} chevron last /> + + ) : ( + <> + } title="Create a signer key" subtitle="Generated and kept in the device keychain" onPress={() => void createSigner()} chevron /> + } title="Import a private key" subtitle="A key you already use as a member" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> + {importing && ( + + + + {importErr && {importErr}} + + )} + + )} + + The private key never leaves the phone. Only signed transactions do. Give this address a role in a vault to sign for it. - - - - } /> - } /> - } last /> - If this app ever disappears, the vault stays reachable through these endpoints and the verified contracts on the explorer. Skur V1 · {short(DEPLOYMENTS.demoVault)} - + Environment + + } title="Ark Constellation devnet" subtitle="chain 9000" /> + } title="RPC" subtitle={ARK_DEVNET_RPC.replace("https://", "")} /> + } title="Factory" subtitle={
      } /> + } title="Vault implementation" subtitle={
      } /> + } title="Skur V1" subtitle={`demo vault ${short(DEPLOYMENTS.demoVault)}`} last /> + + If this app ever disappears, the vault stays reachable through these endpoints and the verified contracts on the explorer. + ); } diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx index f35dfad..e239db6 100644 --- a/mobile/src/screens/Transactions.tsx +++ b/mobile/src/screens/Transactions.tsx @@ -1,42 +1,44 @@ import { useNavigation } from "@react-navigation/native"; import { useState } from "react"; -import { Pressable, RefreshControl, Text, View } from "react-native"; +import { RefreshControl, Text, View } from "react-native"; import { fmtDate } from "@web/lib/format"; -import { Status } from "@web/lib/types"; +import { Kind, Status } from "@web/lib/types"; import type { ProposalView, VaultData } from "@web/lib/vaultReads"; import { describeProposal, statusText } from "../lib/describe"; -import { Badge, Card, Empty, Notice, Screen, Segmented, StatusBadge, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Badge, Card, CircleIcon, Empty, IconButton, Notice, Row, Screen, StatusBadge, Tabs, TopBar, type IconName, s } from "../components/ui"; +import { C } from "../theme"; + +export const KIND_ICON: Record = { [Kind.TRANSFER]: "arrow-up-right", [Kind.POLICY_UPDATE]: "sliders", [Kind.ASSET_LIMITS]: "sliders", [Kind.MEMBER_SET]: "users", [Kind.RECIPIENT_TRUST]: "book", [Kind.MODE_RELAX]: "shield", [Kind.RECOVERY]: "life-buoy" }; export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const [tab, setTab] = useState<"queue" | "history">("queue"); + const pendingCount = vault.proposals.filter((p) => p.status === Status.PENDING).length; const items = vault.proposals.filter((p) => (tab === "queue" ? p.status === Status.PENDING : p.status !== Status.PENDING)); + const groups = new Map(); + for (const p of items) { const d = fmtDate(p.createdAt).split(" at ")[0]; groups.set(d, [...(groups.get(d) ?? []), p]); } return ( - }> - p.status === Status.PENDING).length ? ` · ${vault.proposals.filter((p) => p.status === Status.PENDING).length}` : ""}`], ["history", "History"]]} onChange={setTab} /> - {vault.logsFailed && The chain's event log could not be read, so purposes and history details are missing. Proposals below come straight from contract state.} - {vault.activityLoading ? Reading proposals and history from the chain… : items.length === 0 ? {tab === "queue" ? "Proposals waiting for confirmation or execution will appear here" : "Executed, cancelled and vetoed proposals will appear here"} : ( - - {items.map((p, i) => nav.navigate("TxDetail", { id: String(p.id) })} />)} - - )} - Governance proposals need owner confirmations. Security-reducing ones also wait out their timelock, and any guardian can veto them. - - ); -} - -function Row({ p, vault, last, onPress }: { p: ProposalView; vault: VaultData; last: boolean; onPress: () => void }) { - const d = describeProposal(p, vault); - return ( - - {d.icon} - - {d.title} #{String(p.id)} - {d.detail} - {fmtDate(p.createdAt)} + } + top={ nav.navigate("Send")} />} />}> + + + {vault.logsFailed && The chain's event log could not be read, so purposes and history details are missing.} - {p.status === Status.PENDING ? {statusText(p)} : } - + {vault.activityLoading ? Reading proposals and history from the chain… : items.length === 0 ? ( + {tab === "queue" ? "Proposals waiting for confirmation or execution will appear here" : "Executed, cancelled and vetoed proposals will appear here"} + ) : [...groups.entries()].map(([date, ps]) => ( + + {date} + + {ps.map((p, i) => { + const d = describeProposal(p, vault); + return } title={d.title} subtitle={d.detail} onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} chevron last={i === ps.length - 1} + trailing={p.status === Status.PENDING ? {statusText(p)} : } />; + })} + + + ))} + Governance proposals need owner confirmations. Security-reducing ones also wait out their timelock, and any guardian can veto them. + ); } diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx index 05b25c0..9b647a4 100644 --- a/mobile/src/screens/TxDetail.tsx +++ b/mobile/src/screens/TxDetail.tsx @@ -1,28 +1,36 @@ import { useNavigation, useRoute } from "@react-navigation/native"; -import { Linking, Text, View } from "react-native"; +import { useState } from "react"; +import { Linking, Pressable, Text, View } from "react-native"; import { stringToHex } from "viem"; import { SkurVaultAbi } from "@web/abi/SkurVault"; import { ARK_DEVNET_EXPLORER } from "@web/config/chain"; -import { fmtDate, fmtDuration, nowSec, short } from "@web/lib/format"; +import { fmtAmount, fmtDate, fmtDuration, nowSec, short } from "@web/lib/format"; import { explainReasons, Kind, Mode, ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, Status } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; import { describeProposal, memoText, statusText } from "../lib/describe"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; -import { Address, Badge, Button, Card, KV, Notice, Screen, StatusBadge, TierBadge, TxStatus, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { Address, BackButton, Badge, Button, Card, CircleIcon, Icon, IconButton, KV, Notice, Row, Screen, SignBar, StatusBadge, TierBadge, TopBar, TxStatus, s } from "../components/ui"; +import { KIND_ICON } from "./Transactions"; import { C, F } from "../theme"; +/** Safe's "Confirm transaction": hero amount, To card with advanced details, checks and confirmations rows, sticky sign bar. */ export function TxDetail({ vault }: { vault: VaultData }) { const route = useRoute<{ key: string; name: string; params: { id: string } }>(); - const nav = useNavigation<{ goBack: () => void }>(); + const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); const { signer } = useStore(); const roles = useMyRoles(vault); const invalidate = useInvalidateVault(vault.address); const tx = useTx(invalidate); + const [advanced, setAdvanced] = useState(false); + const [showChecks, setShowChecks] = useState(false); + const [showConf, setShowConf] = useState(false); const p = vault.proposals.find((x) => String(x.id) === route.params.id); - if (!p) return This proposal is not in the loaded range.; + if (!p) return nav.goBack()} />} />}>This proposal is not in the loaded range.; const d = describeProposal(p, vault); + const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); const now = nowSec(); const pending = p.status === Status.PENDING; const expired = pending && Number(p.expiresAt) <= now; @@ -30,58 +38,87 @@ export function TxDetail({ vault }: { vault: VaultData }) { const approvalsMet = p.liveApprovals >= p.requiredApprovals && p.liveGuardians >= p.requiredGuardians; const me = signer?.address.toLowerCase(); const alreadyApproved = Boolean(me && (p.approvers.some((a) => a.toLowerCase() === me) || p.guardianConfirmers.some((a) => a.toLowerCase() === me))); - const canApprove = pending && !expired && !alreadyApproved && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER | ROLE_GUARDIAN : ROLE_OWNER | ROLE_GUARDIAN)) && (roles & ROLE_GUARDIAN ? p.requiredGuardians > 0 : true); + const isGuardian = Boolean(roles & ROLE_GUARDIAN); + const canApprove = pending && !expired && !alreadyApproved && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER | ROLE_GUARDIAN : ROLE_OWNER | ROLE_GUARDIAN)) && (isGuardian ? p.requiredGuardians > 0 : true); const lockedOut = vault.mode === Mode.LOCKDOWN && (p.kind === Kind.TRANSFER || p.securityReducing); const canExecute = pending && !expired && approvalsMet && !timelocked && !lockedOut && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_EXECUTOR | ROLE_OWNER : ROLE_OWNER)); - const canVeto = pending && p.vetoable && Boolean(roles & ROLE_GUARDIAN); + const canVeto = pending && p.vetoable && isGuardian; const canCancel = pending && Boolean(me && (p.proposer.toLowerCase() === me || roles & ROLE_OWNER)); const call = (fn: string, args: readonly unknown[] = [p.id]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); const memo = memoText(p); + const reasons = p.kind === Kind.TRANSFER ? explainReasons(p.riskReasons) : []; + + const primary = !signer ? { label: "Add a signer to sign", onPress: () => nav.navigate("Main", { screen: "Settings" }), disabled: false, hint: undefined as string | undefined } + : roles === 0 ? { label: "Not a member of this vault", onPress: undefined, disabled: true, hint: `${short(signer.address)} holds no role here` } + : canApprove ? { label: isGuardian ? "Confirm as guardian" : "Confirm", onPress: () => call("approve"), disabled: false, hint: undefined } + : canExecute ? { label: "Execute", onPress: () => call("execute"), disabled: false, hint: undefined } + : pending && Boolean(roles & (ROLE_EXECUTOR | ROLE_OWNER)) ? { label: "Execute", onPress: undefined, disabled: true, hint: lockedOut ? "The vault is in Lockdown" : timelocked ? `Executable after ${fmtDate(p.executableAfter)}` : !approvalsMet ? "Waiting for more confirmations" : expired ? "This proposal has expired" : undefined } + : null; return ( - {statusText(p)} : }> + nav.goBack()} />} center={{pending ? "Confirm transaction" : "Transaction"}} right={ void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vault.address}`)} />} />} + footer={pending && primary ? ( + + + + + + ) : undefined}> + + + + {p.kind === Kind.TRANSFER && } + + {p.kind === Kind.TRANSFER && asset ? `-${fmtAmount(p.amount, asset.decimals, asset.symbol)}` : d.title} + {p.kind === Kind.TRANSFER ? d.title : d.detail} · {fmtDate(p.createdAt)} + {pending ? {statusText(p)} : } + + - + {p.kind === Kind.TRANSFER &&
      } />} {memo ? : null} - } /> - - {p.kind === Kind.TRANSFER && } />} - - Number(p.createdAt) ? fmtDuration(Number(p.executableAfter - p.createdAt)) : "none"} /> - - - - {p.kind === Kind.TRANSFER && explainReasons(p.riskReasons).length > 0 && ( - - {explainReasons(p.riskReasons).map((t) => ▪ {t})} - - )} - - Signers ({p.liveApprovals} of {p.requiredApprovals}) - {p.approvers.length === 0 ? None yet : p.approvers.map((a) => ✓ {short(a, 6)})} - {p.requiredGuardians > 0 && ( + + + {advanced && ( <> - Guardians ({p.liveGuardians} of {p.requiredGuardians}) - {p.guardianConfirmers.length === 0 ? Independent sign-off required : p.guardianConfirmers.map((a) => ✓ {short(a, 6)})} + } /> + + Number(p.createdAt) ? fmtDuration(Number(p.executableAfter - p.createdAt)) : "none"} /> + + + )} + - {pending && ( - - {!signer && Add a signer key under Settings to act on this proposal.} - {signer && roles === 0 && {short(signer.address)} is not a member of this vault.} - - {canApprove && } - {Boolean(roles & (ROLE_EXECUTOR | ROLE_OWNER)) && !(roles & ROLE_GUARDIAN) && } - {canVeto && } - {canCancel && !expired && } - {expired && } - - + + {p.kind === Kind.TRANSFER && ( + + } title="Risk review" trailing={} chevron onPress={() => setShowChecks((v) => !v)} last={!showChecks} /> + {showChecks && {reasons.length === 0 ? No elevated risk signal. Routine tier. : reasons.map((t) => ▪ {t})}} )} - - + + } title="Confirmations" trailing={{p.liveApprovals}/{p.requiredApprovals}{p.requiredGuardians ? ` · ${p.liveGuardians}/${p.requiredGuardians} guardian` : ""}} chevron onPress={() => setShowConf((v) => !v)} last={!showConf} /> + {showConf && ( + + {p.approvers.length === 0 && p.guardianConfirmers.length === 0 ? None yet : null} + {p.approvers.map((a) => {short(a, 6)}signer)} + {p.guardianConfirmers.map((a) => {short(a, 6)}guardian)} + + )} + + + {pending && (canVeto || canCancel || expired) && ( + + {canVeto && } + {canCancel && !expired && } + {expired && } + + )} + {!pending && } + void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vault.address}`)} style={{ alignItems: "center", marginTop: 14 }}>View vault on Blockscout ); } diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx new file mode 100644 index 0000000..5721399 --- /dev/null +++ b/mobile/src/screens/Welcome.tsx @@ -0,0 +1,89 @@ +import { useRef, useState } from "react"; +import { Dimensions, ScrollView, Text, View, type NativeScrollEvent, type NativeSyntheticEvent } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { Identicon } from "../components/Identicon"; +import { Badge, Button, CircleIcon, Icon, Logo, Tape, s } from "../components/ui"; +import { C, F } from "../theme"; + +const W = Dimensions.get("window").width; + +/** First-launch carousel, after Safe{Mobile}'s: illustration, headline, dots, one button. Three pages, Skur's pattern. */ +export function Welcome({ onDone }: { onDone: () => void }) { + const insets = useSafeAreaInsets(); + const [page, setPage] = useState(0); + const ref = useRef(null); + const onScroll = (e: NativeSyntheticEvent) => setPage(Math.round(e.nativeEvent.contentOffset.x / W)); + const pages = [ + { title: "Watch your\ntreasury. Anywhere.", sub: "Balances, the queue and the policy, read straight from the vault contract. No server in between.", art: }, + { title: "Sign from\nyour phone", sub: "A key kept in this phone's keychain, behind Face ID. Every payment is scored by the vault before you sign.", art: }, + { title: "Every payment,\nscored first", sub: "Amount, recipient trust, today's outflow and the security mode set how many approvals it needs and how long it waits.", art: }, + ]; + return ( + + + + {pages.map((p, i) => ( + + {p.art} + {p.title} + {p.sub} + + ))} + + + {pages.map((_, i) => )} + + + + Skip + + + ); +} + +const A1 = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; +const A2 = "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0"; +const A3 = "0xCec10C48B8d37b6A083000173e3415Cc6f86974F"; + +function ArtTreasury() { + return ( + + + + + + Normal + + + + ); +} + +function ArtSign() { + return ( + + + + Select signer + Device signer + + + Policy check passed + + ); +} + +function ArtTiers() { + const rows: Array<[string, string, "ok" | "warn" | "bad"]> = [["1,000 sUSD · known supplier", "Low · 1 approval · now", "ok"], ["12,000 sUSD · new address", "High · 2 approvals · 1 day", "warn"], ["60,000 sUSD · 24% of holdings", "Critical · 2 + guardian", "bad"]]; + return ( + + {rows.map(([a, b, t], i) => ( + + + {a}{b} + {t === "ok" ? "Low" : t === "warn" ? "High" : "Critical"} + + ))} + + ); +} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx index 5943e0f..946f673 100644 --- a/mobile/src/state/store.tsx +++ b/mobile/src/state/store.tsx @@ -16,10 +16,12 @@ type Store = { removeSigner: () => Promise; biometrics: boolean; setBiometrics: (on: boolean) => Promise; + onboarded: boolean; + setOnboarded: () => Promise; }; const Ctx = createContext(null); -const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer" }; +const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer", onboarded: "skur.onboarded" }; /** App state. The signer's private key lives only in the device keychain (expo-secure-store); nothing leaves the phone but signed transactions. */ export function StoreProvider({ children }: { children: ReactNode }) { @@ -28,11 +30,13 @@ export function StoreProvider({ children }: { children: ReactNode }) { const [labels, setLabels] = useState>({}); const [signer, setSigner] = useState(null); const [biometrics, setBio] = useState(true); + const [onboarded, setOnb] = useState(false); useEffect(() => { (async () => { try { - const [v, l, b, key] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer)]); + const [v, l, b, key, o] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer), AsyncStorage.getItem(K.onboarded)]); + if (o === "1") setOnb(true); if (v) setVault(v as `0x${string}`); if (l) setLabels(JSON.parse(l)); if (b !== null) setBio(b === "1"); @@ -50,8 +54,9 @@ export function StoreProvider({ children }: { children: ReactNode }) { const importSigner = useCallback((raw: string) => { const k = (raw.trim().startsWith("0x") ? raw.trim() : `0x${raw.trim()}`) as `0x${string}`; if (!/^0x[0-9a-fA-F]{64}$/.test(k)) throw new Error("A private key is 64 hex characters."); return persistSigner(k); }, [persistSigner]); const removeSigner = useCallback(async () => { await SecureStore.deleteItemAsync(K.signer); setSigner(null); }, []); const setBiometrics = useCallback(async (on: boolean) => { setBio(on); await AsyncStorage.setItem(K.bio, on ? "1" : "0"); }, []); + const setOnboarded = useCallback(async () => { setOnb(true); await AsyncStorage.setItem(K.onboarded, "1"); }, []); - const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics }), [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics]); + const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics, onboarded, setOnboarded }), [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics, onboarded, setOnboarded]); return {children}; } diff --git a/mobile/src/theme.ts b/mobile/src/theme.ts index 8186d99..bf6395a 100644 --- a/mobile/src/theme.ts +++ b/mobile/src/theme.ts @@ -1,8 +1,8 @@ -/** Skur mobile: charcoal ground, #FFD000 used the way hazard tape is used. Mirrors web/src/styles.css dark tokens. */ +/** Skur mobile: Safe{Mobile}'s skeleton in Skur's clothes. Charcoal ground instead of black, #FFD000 as hazard tape and highlighter. */ export const C = { canvas: "#212529", - panel: "#2b3035", - panel2: "#343a40", + card: "#2b3035", + card2: "#343a40", border: "#495057", text: "#f8f9fa", text2: "#adb5bd", @@ -30,4 +30,4 @@ export const F = { monoMedium: "DMMono_500Medium", } as const; -export const R = { sm: 6, md: 10, lg: 14 } as const; +export const R = { sm: 8, md: 12, lg: 16, pill: 999 } as const; From 253c52e66e176a780ad0a3f9809874d63fe09fde Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 15:05:01 +0100 Subject: [PATCH 04/44] feat(mobile): address book, members, policy editor, simulator, vault creation, signers, notifications and QR Brings the phone app level with the web interface and with what a Safe mobile companion offers. New screens: Address book (register a recipient, propose a trust change), Members (roles, thresholds, add, change, remove), Policy editor (templates, every control grouped, security-reducing detection, per-asset limits with history), Simulator (the attack scenarios, live policy or any template), Create vault (name, template, members, one signature), Signers (several keys on one phone, which one signs), Updates (what needs your signature, recent activity, notification switch), and a QR scanner used by every address field. Also: local notifications when a proposal newly needs the active signer, recovery on the Security screen, Send accepts a preset asset, a known-recipient picker and QR, Transactions gains the type filter, tapping a token sends that asset, and the vault error screen offers a retry. Deep links now run through a navigation ref that queues links arriving before the navigator mounts, so a notification tapped on a cold start still opens its transaction; opening a different vault returns Home. The wizard's address rows chain focus with the Return key, since three address fields do not fit above the keyboard. The policy field definitions move into web/src/lib/policyFields.ts and are shared by both editors. app.json pins Expo modules to source builds: the precompiled frameworks expect a prebuilt React.framework and crash at launch when it is absent. --- mobile/App.tsx | 118 ++++++++++++++++----- mobile/README.md | 14 +++ mobile/app.json | 47 +++++++-- mobile/package-lock.json | 149 ++++++++++++++++++++++----- mobile/package.json | 2 + mobile/src/components/ui.tsx | 8 +- mobile/src/hooks/useAlerts.ts | 49 +++++++++ mobile/src/lib/scanBus.ts | 8 ++ mobile/src/screens/AddressBook.tsx | 71 +++++++++++++ mobile/src/screens/CreateVault.tsx | 95 +++++++++++++++++ mobile/src/screens/Home.tsx | 12 ++- mobile/src/screens/Members.tsx | 79 ++++++++++++++ mobile/src/screens/Notifications.tsx | 42 ++++++++ mobile/src/screens/Policy.tsx | 128 +++++++++++++++++++++++ mobile/src/screens/Scan.tsx | 39 +++++++ mobile/src/screens/Security.tsx | 13 +++ mobile/src/screens/Send.tsx | 22 ++-- mobile/src/screens/Settings.tsx | 41 +++----- mobile/src/screens/Signers.tsx | 60 +++++++++++ mobile/src/screens/Simulator.tsx | 70 +++++++++++++ mobile/src/screens/Transactions.tsx | 12 ++- mobile/src/screens/Welcome.tsx | 123 ++++++++++++++-------- mobile/src/state/store.tsx | 61 ++++++++--- mobile/tsconfig.json | 24 ++++- web/src/lib/policyFields.ts | 51 +++++++++ web/src/pages/Policies.tsx | 49 +-------- 26 files changed, 1173 insertions(+), 214 deletions(-) create mode 100644 mobile/src/hooks/useAlerts.ts create mode 100644 mobile/src/lib/scanBus.ts create mode 100644 mobile/src/screens/AddressBook.tsx create mode 100644 mobile/src/screens/CreateVault.tsx create mode 100644 mobile/src/screens/Members.tsx create mode 100644 mobile/src/screens/Notifications.tsx create mode 100644 mobile/src/screens/Policy.tsx create mode 100644 mobile/src/screens/Scan.tsx create mode 100644 mobile/src/screens/Signers.tsx create mode 100644 mobile/src/screens/Simulator.tsx create mode 100644 web/src/lib/policyFields.ts diff --git a/mobile/App.tsx b/mobile/App.tsx index 0f88879..d9c5708 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -2,23 +2,34 @@ import { DMMono_400Regular, DMMono_500Medium } from "@expo-google-fonts/dm-mono" import { DMSans_400Regular, DMSans_500Medium, DMSans_700Bold } from "@expo-google-fonts/dm-sans"; import { SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold } from "@expo-google-fonts/space-grotesk"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; -import { DarkTheme, NavigationContainer, type LinkingOptions, type NavigatorScreenParams } from "@react-navigation/native"; +import { createNavigationContainerRef, DarkTheme, NavigationContainer, type NavigatorScreenParams } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useFonts } from "expo-font"; import * as Linking from "expo-linking"; -import { useEffect } from "react"; +import * as Notifications from "expo-notifications"; +import { useCallback, useEffect, useRef } from "react"; import { isAddress } from "viem"; import { StatusBar } from "expo-status-bar"; +import { useState } from "react"; import { ActivityIndicator, Text, View } from "react-native"; import { Feather } from "@expo/vector-icons"; import { SafeAreaProvider } from "react-native-safe-area-context"; import { Status } from "@web/lib/types"; -import { Notice, Screen } from "./src/components/ui"; +import { Button, Notice, Screen, TopBar } from "./src/components/ui"; import { useVault } from "./src/hooks/useVault"; import { Home } from "./src/screens/Home"; import { Onboard } from "./src/screens/Onboard"; import { Welcome } from "./src/screens/Welcome"; +import { AddressBook } from "./src/screens/AddressBook"; +import { Members } from "./src/screens/Members"; +import { Policy } from "./src/screens/Policy"; +import { Simulator } from "./src/screens/Simulator"; +import { CreateVault } from "./src/screens/CreateVault"; +import { Signers } from "./src/screens/Signers"; +import { NotificationsScreen } from "./src/screens/Notifications"; +import { Scan } from "./src/screens/Scan"; +import { useAlerts } from "./src/hooks/useAlerts"; import { Logo } from "./src/components/ui"; import { Receive } from "./src/screens/Receive"; import { Security } from "./src/screens/Security"; @@ -37,10 +48,26 @@ const navTheme = { ...DarkTheme, colors: { ...DarkTheme.colors, background: C.ca function VaultApp() { - const { vaultAddress } = useStore(); + const { vaultAddress, setVaultAddress } = useStore(); const { data: vault, error, isLoading, refetch, refreshing } = useVault(vaultAddress); - if (!vaultAddress) return ; - if (error && !vault) return Could not read the vault: {(error as Error).message}; + useAlerts(vault); + if (!vaultAddress) return ( + + + + {() => } + {() => } + + + ); + if (error && !vault) return ( + } />}> + Could not read the vault. {(error as Error).message} + + + + + ); if (isLoading || !vault) return Reading the vault from the chain…; const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; const TabsScreen = () => ( @@ -57,50 +84,87 @@ function VaultApp() { {() => } {() => } {() => } + {() => } + {() => } + {() => } + {() => } + + {() => } + {() => } + ); } -/** Deep links: skur://vault/
      opens a vault; skur://dev/signer/ loads a signer in development builds only. */ -function useDeepLinks() { - const { setVaultAddress, importSigner } = useStore(); +export const navigationRef = createNavigationContainerRef(); +const ROUTES: Record = { + home: ["Main", "Home"], transactions: ["Main", "Transactions"], settings: ["Main", "Settings"], + send: "Send", receive: "Receive", security: "Security", addressbook: "AddressBook", members: "Members", + policy: "Policy", simulator: "Simulator", create: "CreateVault", signers: "Signers", updates: "Notifications", scan: "Scan", +}; + +/** + * Deep links, including the ones notifications carry: skur://tx/, skur://vault/
      , and one per screen. + * Links that arrive before the navigator is mounted (cold start, vault still loading) are queued, not dropped. + */ +function useDeepLinks(ready: boolean) { + const { setVaultAddress, importSigner, setOnboarded } = useStore(); + const queued = useRef(null); + const go = useCallback((target: keyof RootParams | [keyof RootParams, string], params?: object) => { + if (!navigationRef.isReady()) return false; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const nav = navigationRef.navigate as unknown as (name: string, params?: object) => void; + if (Array.isArray(target)) nav(target[0], { screen: target[1], ...(params ?? {}) }); + else nav(target, params); + return true; + }, []); + const handle = useCallback((url: string | null): void => { + if (!url) return; + const { hostname, path } = Linking.parse(url); + const segs = [hostname ?? "", ...(path ?? "").split("/")].filter(Boolean); + const [head, ...rest] = segs; + // Opening a different vault returns to Home: a pushed screen belongs to the vault you left. + if (head === "vault" && rest[0] && isAddress(rest[0])) { void setVaultAddress(rest[0] as `0x${string}`); go(["Main", "Home"]); return; } + if (__DEV__ && head === "dev" && rest[0] === "signer" && rest[1]) { void importSigner(rest[1]).catch(() => undefined); return; } + if (__DEV__ && head === "dev" && rest[0] === "onboarding") { void setOnboarded(false); void setVaultAddress(null); return; } + if (head === "tx" && rest[0]) { if (!go("TxDetail", { id: rest[0] })) queued.current = url; return; } + const route = ROUTES[head ?? ""]; + if (route && !go(route)) queued.current = url; + }, [setVaultAddress, importSigner, setOnboarded, go]); useEffect(() => { - const handle = (url: string | null) => { - if (!url) return; - const { hostname, path } = Linking.parse(url); - const segs = (path ?? "").split("/").filter(Boolean); - if (hostname === "vault" && segs[0] && isAddress(segs[0])) void setVaultAddress(segs[0] as `0x${string}`); - if (__DEV__ && hostname === "dev" && segs[0] === "signer" && segs[1]) void importSigner(segs[1]).catch(() => undefined); - }; void Linking.getInitialURL().then(handle); const sub = Linking.addEventListener("url", (e) => handle(e.url)); - return () => sub.remove(); - }, [setVaultAddress, importSigner]); + const nsub = Notifications.addNotificationResponseReceivedListener((r) => { + const u = (r.notification.request.content.data as { url?: string } | undefined)?.url; + if (u) handle(u); + }); + return () => { sub.remove(); nsub.remove(); }; + }, [handle]); + // Replay a link that arrived before the navigator existed. + useEffect(() => { if (ready && queued.current) { const u = queued.current; queued.current = null; setTimeout(() => handle(u), 60); } }, [ready, handle]); } function Gate() { const { ready, onboarded, setOnboarded, vaultAddress } = useStore(); - useDeepLinks(); - if (!ready) return ; + const [navReady, setNavReady] = useState(false); + useDeepLinks(navReady); + useEffect(() => { const t = setInterval(() => { if (navigationRef.isReady()) { setNavReady(true); clearInterval(t); } }, 120); return () => clearInterval(t); }, []); + if (!ready) return ; if (!onboarded && !vaultAddress) return void setOnboarded()} />; return ; } type TabParams = { Home: undefined; Transactions: undefined; Settings: undefined }; -type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined; Security: undefined }; -const linking: LinkingOptions = { - prefixes: [Linking.createURL("/"), "skur://"], - config: { screens: { Main: { screens: { Home: "home", Transactions: "transactions", Settings: "settings" } }, TxDetail: "tx/:id", Send: "send", Receive: "receive", Security: "security" } }, -}; +type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined; Security: undefined; AddressBook: undefined; Members: undefined; Policy: undefined; Simulator: undefined; CreateVault: undefined; Signers: undefined; Notifications: undefined; Scan: undefined }; export default function App() { const [fontsLoaded] = useFonts({ SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold, DMSans_400Regular, DMSans_500Medium, DMSans_700Bold, DMMono_400Regular, DMMono_500Medium }); - if (!fontsLoaded) return ; + if (!fontsLoaded) return ; return ( - + diff --git a/mobile/README.md b/mobile/README.md index 8c802d9..0743699 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -2,6 +2,10 @@ The phone companion to the Skur web interface, built after Safe{Mobile}'s structure in Skur's own pattern: a splash with the logo, a three-page onboarding carousel, a Home with the vault switcher, chain row, big balance and Tokens, Policy and Members tabs, Transactions grouped by date, a Confirm-transaction screen with a sticky sign bar, Send with the vault's own review, Security, and Settings as grouped rows. Charcoal ground, #FFD000 as hazard tape and highlighter, Space Grotesk for display, the same identicons as the web. Built with Expo and React Native for iOS and Android. +## Screens + +Onboarding carousel and splash, Home (vault switcher sheet, balance, Tokens/Policy/Members tabs), Transactions (queue, history, type filter), Confirm transaction, Send, Receive, Security (posture, mode, guardians, recovery, maximum loss, mode history), Policy editor (templates, every control, per-asset limits), Members (roles, thresholds), Address book (register, trust), Simulator (attack scenarios), Updates (what needs you, recent activity, notification switch), Signers (several keys on one phone), Create vault, and a QR scanner for vault and recipient addresses. + ## What it shares with the web app Everything that decides something is imported from `web/src` through the `@web/*` alias configured in `metro.config.js` and `tsconfig.json`: the contract ABI, chain configuration, types, the risk engine, policy rules, the max-loss and posture calculators, the contract reads (`lib/vaultReads.ts`) and the error texts. The mobile code holds only screens, navigation, storage and signing. @@ -20,3 +24,13 @@ npx tsc --noEmit # type-check, including the shared web modules ``` The app reads the Ark Constellation devnet (chain 9000) through the endpoints in `web/src/config/chain.ts`. It ships no key and no backend. + +Deep links: `skur://vault/
      `, `skur://tx/`, and one per screen (`home`, `transactions`, `settings`, `send`, `receive`, `security`, `addressbook`, `members`, `policy`, `simulator`, `create`, `signers`, `updates`, `scan`). Notifications carry the transaction link. + +## Notifications + +Local, not push. While the app reads the vault it raises a notification for any proposal that newly needs the active signer, and the Updates screen lists those alongside recent activity. Nothing is sent to a server. + +## Building natively + +`npx expo run:ios` needs CocoaPods and `cmake` on PATH (hermes builds from source). This project sets `ios.usePrecompiledModules: false` in `app.json`: the precompiled Expo module frameworks link against a prebuilt `React.framework` that is not always fetchable, and mixing the two crashes the app at launch with `Library not loaded: @rpath/React.framework/React`. diff --git a/mobile/app.json b/mobile/app.json index 1636f64..bab9179 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -7,14 +7,49 @@ "orientation": "portrait", "icon": "./assets/icon.png", "userInterfaceStyle": "dark", - "backgroundColor": "#212529", - "splash": { "image": "./assets/splash-icon.png", "resizeMode": "contain", "backgroundColor": "#212529" }, - "ios": { "supportsTablet": false, "bundleIdentifier": "io.skur.vault", "infoPlist": { "NSFaceIDUsageDescription": "Skur uses Face ID to approve signatures from this device." } }, + "backgroundColor": "#ffffff", + "splash": { + "image": "./assets/splash-icon.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff", + "imageWidth": 120 + }, + "ios": { + "supportsTablet": false, + "bundleIdentifier": "io.skur.vault", + "infoPlist": { + "NSFaceIDUsageDescription": "Skur uses Face ID to approve signatures from this device.", + "NSCameraUsageDescription": "Skur uses the camera only to read a vault or recipient address from a QR code." + }, + "usePrecompiledModules": false + }, "android": { "package": "io.skur.vault", - "adaptiveIcon": { "backgroundColor": "#212529", "foregroundImage": "./assets/android-icon-foreground.png", "backgroundImage": "./assets/android-icon-background.png", "monochromeImage": "./assets/android-icon-monochrome.png" }, + "adaptiveIcon": { + "backgroundColor": "#212529", + "foregroundImage": "./assets/android-icon-foreground.png", + "backgroundImage": "./assets/android-icon-background.png", + "monochromeImage": "./assets/android-icon-monochrome.png" + }, "predictiveBackGestureEnabled": false }, - "plugins": ["expo-secure-store", "expo-local-authentication", "expo-font"] + "plugins": [ + "expo-secure-store", + "expo-local-authentication", + "expo-font", + [ + "expo-camera", + { + "cameraPermission": "Skur uses the camera only to read a vault or recipient address from a QR code." + } + ], + [ + "expo-notifications", + { + "icon": "./assets/android-icon-monochrome.png", + "color": "#ffd000" + } + ] + ] } -} +} \ No newline at end of file diff --git a/mobile/package-lock.json b/mobile/package-lock.json index a4b67ae..d7ff9bd 100644 --- a/mobile/package-lock.json +++ b/mobile/package-lock.json @@ -18,10 +18,12 @@ "@react-navigation/native-stack": "^7.19.1", "@tanstack/react-query": "^5.102.8", "expo": "~57.0.23", + "expo-camera": "~57.0.5", "expo-clipboard": "~57.0.2", "expo-font": "~57.0.4", "expo-linking": "~57.0.10", "expo-local-authentication": "~57.0.3", + "expo-notifications": "~57.0.19", "expo-secure-store": "~57.0.4", "expo-status-bar": "~57.0.1", "react": "19.2.3", @@ -1954,6 +1956,12 @@ "react": "^18 || ^19" } }, + "node_modules/@types/emscripten": { + "version": "1.41.6", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.6.tgz", + "integrity": "sha512-uN+9i8bFT5CUcZfyIEYDrSueACEyKGbUs5kC/72DGlZZoinh84sJfVV0i8UOJD1asdzkvLPBRrKs41kZ8MdEXg==", + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2277,6 +2285,12 @@ "@babel/plugin-syntax-flow": "^7.12.1" } }, + "node_modules/badgin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz", + "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2286,6 +2300,15 @@ "node": "18 || 20 || >=22" } }, + "node_modules/barcode-detector": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.2.2.tgz", + "integrity": "sha512-/4QOrrNrCRmDSBWiiP4aC72dnkuXUEdcFRidHgbPRXUpy82XcCMvJssI6fEs6JT42LS7DvBVZO70qasJbYKyrA==", + "license": "MIT", + "dependencies": { + "zxing-wasm": "3.1.3" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2986,6 +3009,35 @@ } } }, + "node_modules/expo-application": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-57.0.3.tgz", + "integrity": "sha512-t/CxeLio0NjY9/cOak1tQp62/hAUjzJxmhR4rVUR7K5bb9YoEtfl1ZekTn+Iuh+dYOMYzF0l72ODMSmY3CR1NA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-camera": { + "version": "57.0.5", + "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-57.0.5.tgz", + "integrity": "sha512-0JaUXfDWMytmqm4pVKesZfLTSjAumfS2UGhnc1M4tqJ0qATCS0jxc7KjaoyKEzWJY+FEc8GlPCAGprS/7tNWZQ==", + "license": "MIT", + "dependencies": { + "barcode-detector": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, "node_modules/expo-clipboard": { "version": "57.0.2", "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.2.tgz", @@ -2997,6 +3049,19 @@ "react-native": "*" } }, + "node_modules/expo-constants": { + "version": "57.0.18", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", + "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", + "license": "MIT", + "dependencies": { + "@expo/env": "~2.4.3" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, "node_modules/expo-font": { "version": "57.0.4", "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.4.tgz", @@ -3025,19 +3090,6 @@ "react-native": "*" } }, - "node_modules/expo-linking/node_modules/expo-constants": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", - "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", - "license": "MIT", - "dependencies": { - "@expo/env": "~2.4.3" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, "node_modules/expo-local-authentication": { "version": "57.0.3", "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-57.0.3.tgz", @@ -3095,6 +3147,24 @@ "react-native": "*" } }, + "node_modules/expo-notifications": { + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-57.0.19.tgz", + "integrity": "sha512-JW/usGEwOxWzN8s0L7+j3FAoB39GtaZtpUGye2lPvcqYSkvewpZYkrC16P1JaCP09YRx0Q+qXPx5NUoUU8NsBA==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "abort-controller": "^3.0.0", + "badgin": "^1.1.5", + "expo-application": "~57.0.3", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-secure-store": { "version": "57.0.4", "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-57.0.4.tgz", @@ -3427,19 +3497,6 @@ "react-native": "*" } }, - "node_modules/expo/node_modules/expo-constants": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", - "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", - "license": "MIT", - "dependencies": { - "@expo/env": "~2.4.3" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, "node_modules/expo/node_modules/expo-file-system": { "version": "57.0.7", "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.7.tgz", @@ -6085,6 +6142,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -6627,6 +6696,34 @@ "funding": { "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zxing-wasm": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-3.1.3.tgz", + "integrity": "sha512-3lC9BJk4fR5ZJxcGjb0hVnDFOW7KpLXHIebiBmVd4FDRQZVeObztoTKxRUPxlWwSgxrMRONK0u50hBD1aTYEKg==", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.41.5", + "type-fest": "^5.8.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } + }, + "node_modules/zxing-wasm/node_modules/type-fest": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.9.0.tgz", + "integrity": "sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/mobile/package.json b/mobile/package.json index 2533f01..6df8b1d 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -13,10 +13,12 @@ "@react-navigation/native-stack": "^7.19.1", "@tanstack/react-query": "^5.102.8", "expo": "~57.0.23", + "expo-camera": "~57.0.5", "expo-clipboard": "~57.0.2", "expo-font": "~57.0.4", "expo-linking": "~57.0.10", "expo-local-authentication": "~57.0.3", + "expo-notifications": "~57.0.19", "expo-secure-store": "~57.0.4", "expo-status-bar": "~57.0.1", "react": "19.2.3", diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx index 4ea94ce..ed1f834 100644 --- a/mobile/src/components/ui.tsx +++ b/mobile/src/components/ui.tsx @@ -1,6 +1,6 @@ import { Feather } from "@expo/vector-icons"; import * as Clipboard from "expo-clipboard"; -import { useState, type ComponentProps, type ReactNode } from "react"; +import { forwardRef, useState, type ComponentProps, type ReactNode } from "react"; import { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { short } from "@web/lib/format"; @@ -144,9 +144,9 @@ export function Field({ label, hint, children }: { label: string; hint?: string; ); } -export function Input(props: TextInputProps & { mono?: boolean; big?: boolean }) { - return ; -} +export const Input = forwardRef(function Input(props, ref) { + return ; +}); /** Underlined text tabs, as on Safe's Tokens / NFTs switch. */ export function Tabs({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { diff --git a/mobile/src/hooks/useAlerts.ts b/mobile/src/hooks/useAlerts.ts new file mode 100644 index 0000000..c133dd1 --- /dev/null +++ b/mobile/src/hooks/useAlerts.ts @@ -0,0 +1,49 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import * as Notifications from "expo-notifications"; +import { useEffect, useRef } from "react"; +import { Kind, ROLE_APPROVER, ROLE_GUARDIAN, ROLE_OWNER, Status } from "@web/lib/types"; +import type { ProposalView, VaultData } from "@web/lib/vaultReads"; +import { describeProposal } from "../lib/describe"; +import { useStore } from "../state/store"; +import { useMyRoles } from "./useVault"; + +Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowBanner: true, shouldShowList: true, shouldPlaySound: false, shouldSetBadge: true }) }); + +/** Proposals the active signer can still act on: not yet confirmed by them and within their role. */ +export function needsMe(vault: VaultData, roles: number, me: string | null): ProposalView[] { + if (!me || !roles) return []; + return vault.proposals.filter((p) => { + if (p.status !== Status.PENDING) return false; + const mine = p.approvers.some((a) => a.toLowerCase() === me) || p.guardianConfirmers.some((a) => a.toLowerCase() === me); + if (mine) return false; + if (roles & ROLE_GUARDIAN) return p.requiredGuardians > 0 || p.vetoable; + return Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER : ROLE_OWNER)); + }); +} + +/** + * Local notifications, as Safe's "Get personalized updates": while the app polls the vault, a proposal that newly + * needs this signer raises a notification. There is no push backend; the phone learns of it on its next read. + */ +export function useAlerts(vault: VaultData | undefined) { + const { signer, notifications } = useStore(); + const roles = useMyRoles(vault); + const seen = useRef | null>(null); + useEffect(() => { + if (!vault || !notifications) return; + const key = `skur.seen.${vault.address.toLowerCase()}`; + (async () => { + if (!seen.current) { try { seen.current = new Set(JSON.parse((await AsyncStorage.getItem(key)) ?? "[]")); } catch { seen.current = new Set(); } } + const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null).filter((p) => !seen.current!.has(String(p.id))); + if (due.length === 0) return; + const perm = await Notifications.getPermissionsAsync(); + const granted = perm.granted || (await Notifications.requestPermissionsAsync()).granted; + for (const p of due) { + seen.current!.add(String(p.id)); + if (granted) { const d = describeProposal(p, vault); await Notifications.scheduleNotificationAsync({ content: { title: "A transaction requires your confirmation", body: `${d.title} · ${d.detail}`, data: { url: `skur://tx/${String(p.id)}` } }, trigger: null }).catch(() => undefined); } + } + await AsyncStorage.setItem(key, JSON.stringify([...seen.current!])); + await Notifications.setBadgeCountAsync(due.length).catch(() => undefined); + })(); + }, [vault, roles, signer, notifications]); +} diff --git a/mobile/src/lib/scanBus.ts b/mobile/src/lib/scanBus.ts new file mode 100644 index 0000000..34b645a --- /dev/null +++ b/mobile/src/lib/scanBus.ts @@ -0,0 +1,8 @@ +/** Hands a scanned address from the Scan screen back to whichever screen asked for it. */ +type Listener = (value: string) => void; +let listener: Listener | null = null; +export const scanBus = { + request(fn: Listener) { listener = fn; }, + deliver(value: string) { const fn = listener; listener = null; fn?.(value); }, + clear() { listener = null; }, +}; diff --git a/mobile/src/screens/AddressBook.tsx b/mobile/src/screens/AddressBook.tsx new file mode 100644 index 0000000..949185f --- /dev/null +++ b/mobile/src/screens/AddressBook.tsx @@ -0,0 +1,71 @@ +import { useNavigation } from "@react-navigation/native"; +import { useState } from "react"; +import { Pressable, RefreshControl, Text, View } from "react-native"; +import { isAddress } from "viem"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { fmtAmount, fmtDate, fmtDuration, fmtRelative, nowSec, short } from "@web/lib/format"; +import { ROLE_APPROVER, ROLE_OWNER, Trust, TRUST_LABEL } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { scanBus } from "../lib/scanBus"; +import { Identicon } from "../components/Identicon"; +import { Address, BackButton, Badge, Button, Card, Empty, Field, IconButton, Input, Notice, Row, Screen, Sheet, TopBar, TrustBadge, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +/** Recipients are security objects: register early, verify, restrict or block. */ +export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); + const roles = useMyRoles(vault); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(invalidate); + const [dialog, setDialog] = useState<"register" | "trust" | null>(null); + const [target, setTarget] = useState(""); + const [trust, setTrust] = useState(Trust.VERIFIED); + const now = nowSec(); + const stable = vault.assets[0]; + const canRegister = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)); + const isOwner = Boolean(roles & ROLE_OWNER); + const scan = () => { scanBus.request((a) => setTarget(a)); nav.navigate("Scan"); }; + return ( + } + top={ nav.goBack()} />} center={Address book} right={ { setTarget(""); setDialog("register"); }} />} />}> + + A new recipient waits {fmtDuration(vault.policy.recipientActivationDelay)} before normal policy applies to it. Registering a supplier early means its first payment later does not wait. + {vault.activityLoading ? Reading recipients from the chain… : vault.recipients.length === 0 ? No recipients yet. Register one to start its activation clock. : ( + + {vault.recipients.map((r, i) => { + const active = Number(r.activatesAt) <= now; + return ( + } title={short(r.address, 6)} subtitle={`${r.paymentCount.toString()} payment${r.paymentCount === 1n ? "" : "s"}${stable ? ` · ${fmtAmount(r.totalPaid, stable.decimals, stable.symbol)} paid` : ""} · ${active ? "active" : `activates ${fmtRelative(r.activatesAt)}`}`} + trailing={} chevron={isOwner} onPress={isOwner ? () => { setTarget(r.address); setTrust(r.trust === Trust.VERIFIED ? Trust.TRUSTED : Trust.VERIFIED); setDialog("trust"); } : undefined} last={i === vault.recipients.length - 1} /> + ); + })} + + )} + + + + setDialog(null)} title="New entry"> + + setTarget(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> + + {!canRegister && Only an owner or approver signer can register a recipient.} + + + + setDialog(null)} title="Propose a trust change"> + setTarget(t.trim())} placeholder="0x…" mono /> + + + {[Trust.VERIFIED, Trust.TRUSTED, Trust.RESTRICTED, Trust.BLOCKED].map((t) => ( + setTrust(t)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: trust === t ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{TRUST_LABEL[t]} + ))} + + + + Recorded {fmtDate(BigInt(now))} by {short(vault.address)} + + + ); +} diff --git a/mobile/src/screens/CreateVault.tsx b/mobile/src/screens/CreateVault.tsx new file mode 100644 index 0000000..6d171db --- /dev/null +++ b/mobile/src/screens/CreateVault.tsx @@ -0,0 +1,95 @@ +import { useNavigation } from "@react-navigation/native"; +import { useMemo, useRef, useState } from "react"; +import { Pressable, Text, View, type TextInput } from "react-native"; +import { isAddress, keccak256, stringToHex } from "viem"; +import { SkurFactoryAbi } from "@web/abi/SkurFactory"; +import { DEPLOYMENTS, NATIVE_ASSET } from "@web/config/chain"; +import { fmtAmount, fmtDuration, short } from "@web/lib/format"; +import { policyToContract, validateCounts, validatePolicy } from "@web/lib/policy"; +import { TEMPLATES, templateById, type TemplateId } from "@web/lib/templates"; +import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER } from "@web/lib/types"; +import { publicClient } from "../lib/client"; +import { scanBus } from "../lib/scanBus"; +import { useTx } from "../hooks/useTx"; +import { useStore } from "../state/store"; +import { Identicon } from "../components/Identicon"; +import { BackButton, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Screen, SectionLabel, SignBar, TopBar, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +type Row = { address: string; roles: number }; +const ROLE_CHIPS: Array<[number, string]> = [[ROLE_OWNER, "Owner"], [ROLE_APPROVER, "Approver"], [ROLE_EXECUTOR, "Executor"], [ROLE_GUARDIAN, "Guardian"]]; + +/** Create a vault from the phone: name, template, members, review, one signature. */ +export function CreateVault() { + const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); + const { signer, setVaultAddress, setLabel } = useStore(); + const [name, setName] = useState(""); + const [templateId, setTemplateId] = useState("startup"); + const template = templateById(templateId); + const [members, setMembers] = useState([{ address: signer?.address ?? "", roles: ROLE_OWNER | ROLE_APPROVER | ROLE_EXECUTOR }, { address: "", roles: ROLE_OWNER | ROLE_APPROVER }, { address: "", roles: ROLE_GUARDIAN }]); + // A three-row address form does not fit above the keyboard, so Return moves to the next member. + const rowRefs = useRef>([]); + const salt = useMemo(() => keccak256(stringToHex(`vault-${Date.now()}`)), []); + const counts = members.reduce((a, m) => ({ owners: a.owners + (m.roles & 1 ? 1 : 0), approvers: a.approvers + (m.roles & 2 ? 1 : 0), executors: a.executors + (m.roles & 4 ? 1 : 0), guardians: a.guardians + (m.roles & 8 ? 1 : 0) }), { owners: 0, approvers: 0, executors: 0, guardians: 0 }); + const errors = useMemo(() => { + const e = [...validatePolicy(template.policy), ...validateCounts(template.policy, counts.owners, counts.approvers, counts.executors, counts.guardians)]; + const addrs = members.map((m) => m.address.toLowerCase()); + if (members.some((m) => !isAddress(m.address))) e.push("Every member needs a valid address."); + if (new Set(addrs).size !== addrs.length) e.push("Duplicate member address."); + if (members.some((m) => m.roles === 0)) e.push("Every member needs at least one role."); + return e; + }, [template, counts, members]); + const tx = useTx(async () => { + if (!signer) return; + const v = await publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "predictVaultAddress", args: [signer.address, salt] }); + await setLabel(v, name || "Treasury vault"); + await setVaultAddress(v); + }); + const setRow = (i: number, patch: Partial) => setMembers((ms) => ms.map((m, j) => (j === i ? { ...m, ...patch } : m))); + const toggle = (i: number, b: number) => setRow(i, { roles: b === ROLE_GUARDIAN ? (members[i].roles & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((members[i].roles & b ? members[i].roles & ~b : members[i].roles | b) & ~ROLE_GUARDIAN) }); + const create = () => void tx.send({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "createVault", args: [salt, members.map((m) => m.address as `0x${string}`), members.map((m) => m.roles), policyToContract(template.policy), [DEPLOYMENTS.testUsd, NATIVE_ASSET], [template.stable, template.native]] }); + return ( + nav.goBack()} />} center={Create vault} />} + footer={ 0 || tx.busy} loading={tx.busy} hint={!signer ? "Add a signer key first; it pays for the creation" : errors[0]} />}> + + 1 · Name and template + + + + {TEMPLATES.map((t) => setTemplateId(t.id)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: templateId === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name})} + + {template.tagline} Needs {template.minSigners}+ signers and {template.minGuardians}+ guardian{template.minGuardians === 1 ? "" : "s"}. + + 2 · Signers and guardians + Owners govern, approvers confirm payments, executors execute. Guardians can only freeze, veto and recover; the contract will not let them hold a treasury role. + {members.map((m, i) => ( + + + {isAddress(m.address) ? : } + { rowRefs.current[i] = r; }} value={m.address} onChangeText={(t) => setRow(i, { address: t.trim() })} placeholder="0x…" mono style={{ flex: 1 }} returnKeyType={i < members.length - 1 ? "next" : "done"} submitBehavior={i < members.length - 1 ? "submit" : "blurAndSubmit"} onSubmitEditing={() => rowRefs.current[i + 1]?.focus()} /> + { scanBus.request((a) => setRow(i, { address: a })); nav.navigate("Scan"); }} /> + setMembers((ms) => ms.filter((_, j) => j !== i))} /> + + + {ROLE_CHIPS.map(([b, label]) => toggle(i, b)} style={{ paddingHorizontal: 12, height: 30, borderRadius: 15, backgroundColor: m.roles & b ? (b === ROLE_GUARDIAN ? C.accent : C.accentBg) : C.card2, borderWidth: 1, borderColor: m.roles & b ? C.accent : "transparent", alignItems: "center", justifyContent: "center" }}>{label})} + + + ))} + + 3 · Review + + + + + + + + + + {errors.length > 0 && {errors.join(" ")}} + The vault is a minimal proxy over the verified implementation. The factory that creates it keeps no authority over it; only the members listed above can act. + + + ); +} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index c6ab3d4..985cfff 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -8,6 +8,8 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useMyRoles } from "../hooks/useVault"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; +import { needsMe } from "../hooks/useAlerts"; +import { scanBus } from "../lib/scanBus"; import { VaultSheet } from "../components/VaultSheet"; import { Address, Badge, Card, CircleIcon, Icon, IconButton, KV, Row, Screen, Tabs, Tape, TopBar, s } from "../components/ui"; import { C, F } from "../theme"; @@ -22,6 +24,9 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; const canPropose = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)) && vault.mode !== Mode.LOCKDOWN; + const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null).length; + const { setVaultAddress } = useStore(); + const scanVault = () => { scanBus.request((a) => void setVaultAddress(a as `0x${string}`)); nav.navigate("Scan"); }; const [whole, frac] = stable ? fmtAmount(stable.balance, stable.decimals, undefined, 2).split(".") : ["—", undefined]; return ( @@ -36,7 +41,7 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch } - right={<> nav.navigate("Receive")} /> nav.navigate("Security")} />} + right={<> 0 || vault.mode !== Mode.NORMAL} onPress={() => nav.navigate("Notifications")} />} /> {vault.mode !== Mode.NORMAL && } @@ -77,11 +82,12 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch {tab === "tokens" && vault.assets.map((a, i) => ( - } title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(a.balance, a.decimals)} ${a.symbol}`} last={i === vault.assets.length - 1} + } title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(a.balance, a.decimals)} ${a.symbol}`} onPress={canPropose ? () => nav.navigate("Send", { asset: a.address }) : undefined} last={i === vault.assets.length - 1} trailing={{fmtAmount(a.balance, a.decimals)}{fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of {a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today} /> ))} {tab === "policy" && ( + nav.navigate("Policy")} style={{ flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 10 }}>Edit policy · v{vault.policyVersion} @@ -91,7 +97,7 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch )} {tab === "members" && vault.members.map((m, i) => ( - } title={short(m.address, 6)} subtitle={m.address.toLowerCase() === signer?.address.toLowerCase() ? "this phone" : undefined} last={i === vault.members.length - 1} + } title={short(m.address, 6)} subtitle={m.address.toLowerCase() === signer?.address.toLowerCase() ? "this phone" : undefined} onPress={() => nav.navigate("Members")} chevron last={i === vault.members.length - 1} trailing={{roleNames(m.roles).map((r) => {r})}} /> ))} setSheet(false)} /> diff --git a/mobile/src/screens/Members.tsx b/mobile/src/screens/Members.tsx new file mode 100644 index 0000000..5bc2ee8 --- /dev/null +++ b/mobile/src/screens/Members.tsx @@ -0,0 +1,79 @@ +import { useNavigation } from "@react-navigation/native"; +import { useState } from "react"; +import { Pressable, RefreshControl, Text, View } from "react-native"; +import { isAddress } from "viem"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { fmtDuration, short } from "@web/lib/format"; +import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, roleNames } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { useStore } from "../state/store"; +import { scanBus } from "../lib/scanBus"; +import { Address, BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Row, Screen, SectionLabel, Sheet, TopBar, TxStatus, s } from "../components/ui"; +import { Identicon } from "../components/Identicon"; +import { C, F } from "../theme"; + +const ROLE_BITS: Array<[number, string, string]> = [[ROLE_OWNER, "Owner", "governs"], [ROLE_APPROVER, "Approver", "confirms payments"], [ROLE_EXECUTOR, "Executor", "executes"], [ROLE_GUARDIAN, "Guardian", "freeze · veto · recover"]]; + +export function Members({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); + const { signer } = useStore(); + const roles = useMyRoles(vault); + const isOwner = Boolean(roles & ROLE_OWNER); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(invalidate); + const [open, setOpen] = useState(false); + const [target, setTarget] = useState(""); + const [bits, setBits] = useState(ROLE_APPROVER); + const existing = vault.members.find((m) => m.address.toLowerCase() === target.toLowerCase()); + const adds = existing ? bits & ~existing.roles : bits; + const reducing = adds !== 0 || Boolean(existing && existing.roles & ROLE_GUARDIAN && !(bits & ROLE_GUARDIAN)); + const toggle = (b: number) => setBits((x) => (b === ROLE_GUARDIAN ? (x & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((x & b ? x & ~b : x | b) & ~ROLE_GUARDIAN))); + const edit = (address: string, r: number) => { setTarget(address); setBits(r); setOpen(true); }; + const signers = vault.members.filter((m) => !(m.roles & ROLE_GUARDIAN)); + const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); + const List = ({ items }: { items: typeof vault.members }) => ( + + {items.map((m, i) => ( + } title={m.address.toLowerCase() === signer?.address.toLowerCase() ? "This phone" : short(m.address, 6)} subtitle={
      } chevron={isOwner} onPress={isOwner ? () => edit(m.address, m.roles) : undefined} last={i === items.length - 1} + trailing={{roleNames(m.roles).map((r) => {r})}} /> + ))} + + ); + return ( + } + top={ nav.goBack()} />} center={Members} right={isOwner ? { setTarget(""); setBits(ROLE_APPROVER); setOpen(true); }} /> : undefined} />}> + + Treasury signers · {signers.length} + Owners govern, approvers confirm payments, executors execute once every condition holds. A member may hold several of these roles. + + Guardians · {guardians.length} + Guardians can freeze the vault, veto risky or security-reducing proposals, confirm critical transfers and start a recovery. The contract will not let them hold a treasury role. + {guardians.length ? : No guardian configured. Nobody independent can veto a proposal or freeze the vault.} + Thresholds + + Routine {vault.policy.approvalsLow} · High {vault.policy.approvalsHigh} · Critical {vault.policy.approvalsCritical}{vault.policy.guardianRequiredCritical ? ` + ${vault.policy.guardianThreshold} guardian` : ""} · Governance {vault.policy.governanceThreshold} owner{vault.policy.governanceThreshold === 1 ? "" : "s"} + Thresholds are part of the policy. Lowering any of them waits {fmtDuration(vault.policy.policyChangeDelay)}, and any guardian can veto the change. + + + + setOpen(false)} title={existing ? (bits === 0 ? "Remove member" : "Change roles") : "Add member"}> + setTarget(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} editable={!existing} /> { scanBus.request((a) => setTarget(a)); nav.navigate("Scan"); }} /> + + + {ROLE_BITS.map(([b, name, desc]) => ( + toggle(b)} style={{ flexDirection: "row", alignItems: "center", gap: 12, padding: 12, borderRadius: 12, backgroundColor: bits & b ? C.accentBg : C.card2, borderWidth: 1, borderColor: bits & b ? C.accent : "transparent" }}> + + {name}{desc} + + ))} + + + {bits === 0 ? "Removing a member takes effect as soon as owners approve." : reducing ? `Adding authority or weakening the guardian layer loosens security: it waits ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto it.` : "Reducing a member's authority takes effect as soon as owners approve."} + + {existing && bits !== 0 && } + + + ); +} diff --git a/mobile/src/screens/Notifications.tsx b/mobile/src/screens/Notifications.tsx new file mode 100644 index 0000000..55c9a8b --- /dev/null +++ b/mobile/src/screens/Notifications.tsx @@ -0,0 +1,42 @@ +import { useNavigation } from "@react-navigation/native"; +import { Switch, Text, View } from "react-native"; +import { fmtRelative, short } from "@web/lib/format"; +import { Status } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { describeProposal } from "../lib/describe"; +import { needsMe } from "../hooks/useAlerts"; +import { useMyRoles } from "../hooks/useVault"; +import { useStore } from "../state/store"; +import { BackButton, Badge, Card, CircleIcon, Empty, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; +import { C } from "../theme"; + +/** Safe's notification centre: what needs this signer, then what happened recently. */ +export function NotificationsScreen({ vault }: { vault: VaultData }) { + const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); + const { signer, notifications, setNotifications } = useStore(); + const roles = useMyRoles(vault); + const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null); + const recent = [...vault.proposals].sort((a, b) => Number(b.createdAt - a.createdAt)).slice(0, 12); + return ( + nav.goBack()} />} center={Updates} />}> + + + } title="Notify me on this phone" subtitle="When a proposal newly needs your confirmation" trailing={ void setNotifications(v)} trackColor={{ true: C.accent }} />} last /> + + Needs you · {due.length} + {due.length === 0 ? Nothing needs your signature right now. : ( + + {due.map((p, i) => { const d = describeProposal(p, vault); return } title={`${d.title} requires your confirmation`} subtitle={`${d.detail} · ${fmtRelative(p.createdAt)}`} chevron onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} last={i === due.length - 1} />; })} + + )} + Recent activity + {recent.length === 0 ? No proposals yet. : ( + + {recent.map((p, i) => { const d = describeProposal(p, vault); const tone = p.status === Status.EXECUTED ? "success" : p.status === Status.VETOED ? "error" : p.status === Status.PENDING ? "warn" : "dark"; return } title={`${d.title} · ${["", "pending", "executed", "cancelled", "vetoed"][p.status]}`} subtitle={`${d.detail} · by ${short(p.proposer)} · ${fmtRelative(p.createdAt)}`} trailing={p.status === Status.PENDING ? {p.liveApprovals}/{p.requiredApprovals} : undefined} chevron onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} last={i === recent.length - 1} />; })} + + )} + Notifications are raised on this phone when the app reads the vault and finds a proposal that newly needs you. There is no server between you and the chain. + + + ); +} diff --git a/mobile/src/screens/Policy.tsx b/mobile/src/screens/Policy.tsx new file mode 100644 index 0000000..b65fd4a --- /dev/null +++ b/mobile/src/screens/Policy.tsx @@ -0,0 +1,128 @@ +import { useNavigation } from "@react-navigation/native"; +import { useRef, useState } from "react"; +import { Pressable, Switch, Text, View } from "react-native"; +import { SkurVaultAbi } from "@web/abi/SkurVault"; +import { fmtAmount, fmtDuration, parseAmount } from "@web/lib/format"; +import { limitReductions, policyReductions, policyToContract, validateLimits, validatePolicy } from "@web/lib/policy"; +import { H, POLICY_GROUPS, type PolicyField } from "@web/lib/policyFields"; +import { TEMPLATES, type TemplateId } from "@web/lib/templates"; +import { ROLE_OWNER, type AssetLimits, type Policy } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; +import { useTx } from "../hooks/useTx"; +import { useStore } from "../state/store"; +import { BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Screen, SectionLabel, SignBar, Tabs, TopBar, TxStatus, s } from "../components/ui"; +import { C, F } from "../theme"; + +/** The policy editor: templates, every control in groups, security-reducing detection, and per-asset limits. */ +export function Policy({ vault }: { vault: VaultData }) { + const nav = useNavigation<{ goBack: () => void }>(); + const { signer } = useStore(); + const roles = useMyRoles(vault); + const isOwner = Boolean(roles & ROLE_OWNER); + const invalidate = useInvalidateVault(vault.address); + const tx = useTx(invalidate); + const [tab, setTab] = useState<"policy" | "limits">("policy"); + const [draft, setDraft] = useState(vault.policy); + const [template, setTemplate] = useState(null); + const seen = useRef(vault.policyVersion); + if (seen.current !== vault.policyVersion) { seen.current = vault.policyVersion; if (JSON.stringify(draft) !== JSON.stringify(vault.policy)) setDraft(vault.policy); } + const changed = JSON.stringify(draft) !== JSON.stringify(vault.policy); + const errors = validatePolicy(draft); + const reductions = policyReductions(vault.policy, draft); + const set = (k: keyof Policy, v: number | boolean) => setDraft((d) => ({ ...d, [k]: v })); + + // asset limits + const [assetAddr, setAssetAddr] = useState(vault.assets[0]?.address); + const asset = vault.assets.find((a) => a.address === assetAddr) ?? vault.assets[0]; + const toText = (l: AssetLimits, d: number) => ({ approved: l.approved, lowMax: fmtAmount(l.lowMax, d, undefined, 6).replace(/,/g, ""), highMax: fmtAmount(l.highMax, d, undefined, 6).replace(/,/g, ""), perTxMax: fmtAmount(l.perTxMax, d, undefined, 6).replace(/,/g, ""), dailyMax: fmtAmount(l.dailyMax, d, undefined, 6).replace(/,/g, "") }); + const [text, setText] = useState(asset ? toText(asset.limits, asset.decimals) : null); + const [textFor, setTextFor] = useState(assetAddr); + if (asset && textFor !== asset.address) { setTextFor(asset.address); setText(toText(asset.limits, asset.decimals)); } + const parsed: AssetLimits | null = asset && text ? (() => { const p = (t: string) => parseAmount(t || "0", asset.decimals); const a = [p(text.lowMax), p(text.highMax), p(text.perTxMax), p(text.dailyMax)]; return a.every((x) => x !== null) ? { approved: text.approved, lowMax: a[0]!, highMax: a[1]!, perTxMax: a[2]!, dailyMax: a[3]! } : null; })() : null; + const limitErrors = parsed ? validateLimits(parsed) : ["Enter valid amounts."]; + const limitReds = asset && parsed ? limitReductions(asset.limits, parsed) : []; + const limitsChanged = asset && parsed ? JSON.stringify(parsed, (_, v) => (typeof v === "bigint" ? v.toString() : v)) !== JSON.stringify(asset.limits, (_, v) => (typeof v === "bigint" ? v.toString() : v)) : false; + + const proposePolicy = () => void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposePolicy", args: [policyToContract(draft)] }); + const proposeLimits = () => parsed && asset && void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeAssetLimits", args: [asset.address, parsed] }); + + return ( + nav.goBack()} />} center={Policy} right={v{vault.policyVersion}} />} + footer={ + + + + {tab === "policy" + ? 0 || tx.busy} loading={tx.busy} hint={!isOwner ? "Only an owner signer can propose a policy" : !changed ? "Nothing has changed yet" : errors.length ? errors[0] : reductions.length ? `Waits ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto` : "Applies as soon as owners approve"} /> + : 0 || tx.busy} loading={tx.busy} hint={!isOwner ? "Only an owner signer can propose limits" : !limitsChanged ? "Nothing has changed yet" : limitErrors.length ? limitErrors[0] : limitReds.length ? `Security-reducing: ${limitReds.join("; ")}` : "Applies as soon as owners approve"} />} + + }> + + + + {tab === "policy" && ( + + Templates + Start from a profile instead of designing a policy from scratch. Choosing one only fills the editor; nothing is proposed until you sign. + + {TEMPLATES.map((t) => ( + { setTemplate(t.id); setDraft(t.policy); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: template === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name} + ))} + {changed && { setDraft(vault.policy); setTemplate(null); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, borderWidth: 1, borderColor: C.border, alignItems: "center", justifyContent: "center" }}>Reset} + + {POLICY_GROUPS.map((g) => ( + + {g.title} + {g.sub} + + {g.fields.map((f, i) => set(f.key, v)} last={i === g.fields.length - 1} />)} + + + ))} + {errors.length > 0 && {errors.join(" ")}} + {changed && errors.length === 0 && {reductions.length ? `Security-reducing: ${reductions.join("; ")}. Delayed ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto.` : "Tightens or keeps every control. Applies as soon as owners approve."}} + History + + {vault.policyHistory.length === 0 ? No policy versions recorded yet. : [...vault.policyHistory].reverse().map((h, i, arr) => v{h.version} · activated {new Date(Number(h.activatedAt) * 1000).toLocaleString()})} + + + )} + {tab === "limits" && asset && text && ( + + Tiers and caps for each asset, in that asset's own units. Approving a new asset loosens security and goes through the delayed path. + + {vault.assets.map((a) => setAssetAddr(a.address)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: a.address === assetAddr ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{a.symbol})} + + + ApprovedUnapproved assets cannot be paid out. setText({ ...text, approved: v })} trackColor={{ true: C.accent }} /> + {([["lowMax", "Routine up to", "At or below this amount a payment is Low tier."], ["highMax", "High up to", "Above this a payment is Critical."], ["perTxMax", "Per-transaction cap", "0 = no cap."], ["dailyMax", "Daily cap", "Cumulative per 24h bucket. 0 = no cap."]] as Array<[keyof typeof text, string, string]>).map(([k, label, hint]) => ( + setText({ ...text, [k]: v })} keyboardType="decimal-pad" /> + ))} + + {limitErrors.length > 0 && limitsChanged && {limitErrors.join(" ")}} + Current: routine ≤ {fmtAmount(asset.limits.lowMax, asset.decimals)} · high ≤ {fmtAmount(asset.limits.highMax, asset.decimals)} · per tx ≤ {asset.limits.perTxMax ? fmtAmount(asset.limits.perTxMax, asset.decimals) : "∞"} · daily ≤ {asset.limits.dailyMax ? fmtAmount(asset.limits.dailyMax, asset.decimals) : "∞"} + + )} + + ); +} + +function Control({ f, value, live, onChange, last }: { f: PolicyField; value: number | boolean; live: number | boolean; onChange: (v: number | boolean) => void; last: boolean }) { + const changed = value !== live; + const label = {f.label}{f.hint ? {f.hint} : null}; + const wrap = (control: React.ReactNode) => {label}{control}; + if (f.unit === "bool") return wrap( onChange(v)} trackColor={{ true: C.accent }} />); + const n = Number(value); + if (f.unit === "count") return wrap( onChange(Math.max(0, v))} />); + if (f.unit === "hours") return wrap( onChange(Math.round(Number(t || 0) * H))} />); + return wrap( onChange(Math.min((f.max ?? 100) * 100, Math.round(Number(t || 0) * 100)))} />); +} +function Stepper({ value, onChange }: { value: number; onChange: (v: number) => void }) { + const B = ({ t, onPress }: { t: string; onPress: () => void }) => {t}; + return onChange(value - 1)} />{value} onChange(value + 1)} />; +} +function Unit({ value, unit, onChange }: { value: string; unit: string; onChange: (t: string) => void }) { + return {unit}; +} diff --git a/mobile/src/screens/Scan.tsx b/mobile/src/screens/Scan.tsx new file mode 100644 index 0000000..8eeefff --- /dev/null +++ b/mobile/src/screens/Scan.tsx @@ -0,0 +1,39 @@ +import { useNavigation } from "@react-navigation/native"; +import { CameraView, useCameraPermissions } from "expo-camera"; +import { useRef, useState } from "react"; +import { Text, View } from "react-native"; +import { isAddress } from "viem"; +import { scanBus } from "../lib/scanBus"; +import { BackButton, Button, Notice, Screen, Tape, TopBar, s } from "../components/ui"; +import { C, F } from "../theme"; + +/** QR scanner for vault and recipient addresses, as Safe's scan button. Accepts a bare address or an EIP-681 "ethereum:0x…" URI. */ +export function Scan() { + const nav = useNavigation<{ goBack: () => void }>(); + const [permission, requestPermission] = useCameraPermissions(); + const [err, setErr] = useState(null); + const done = useRef(false); + const onScanned = ({ data }: { data: string }) => { + if (done.current) return; + const m = data.match(/0x[0-9a-fA-F]{40}/); + if (!m || !isAddress(m[0])) { setErr("That code does not contain an address."); return; } + done.current = true; scanBus.deliver(m[0]); nav.goBack(); + }; + return ( + { scanBus.clear(); nav.goBack(); }} />} center={Scan} />}> + + {permission?.granted ? ( + + ) : ( + + Skur needs the camera to read a QR code. Nothing is recorded. + + + )} + + + Point at a vault or recipient address QR code. + {err ? {err} : null} + + ); +} diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx index f98e59c..635c48b 100644 --- a/mobile/src/screens/Security.tsx +++ b/mobile/src/screens/Security.tsx @@ -12,6 +12,7 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { Identicon } from "../components/Identicon"; +import { isAddress } from "viem"; import { BackButton, Badge, Button, Card, CircleIcon, Field, Input, KV, ModeBadge, Notice, Row, Screen, SectionLabel, Tape, TopBar, TxStatus, s } from "../components/ui"; import { C, F } from "../theme"; @@ -21,6 +22,9 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref const invalidate = useInvalidateVault(vault.address); const tx = useTx(invalidate); const [reason, setReason] = useState(""); + const [oldSigner, setOldSigner] = useState(""); + const [newSigner, setNewSigner] = useState(""); + const isGuardian = Boolean(roles & ROLE_GUARDIAN); const r32 = stringToHex(reason.slice(0, 31), { size: 32 }); const call = (fn: string, args: readonly unknown[]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); @@ -68,6 +72,15 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref + Recovery + + Replace a lost or compromised signer with a new address holding the same roles. It executes after {fmtDuration(vault.policy.recoveryDelay)}, any owner can cancel it, and the vault moves to Elevated when it completes. + setOldSigner(t.trim())} placeholder="0x…" mono /> + setNewSigner(t.trim())} placeholder="0x…" mono /> + + {!isGuardian && Only a guardian signer can start a recovery.} + + {loss && stable && ( <> Maximum possible loss diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index a6e32bf..aa556ef 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -1,6 +1,8 @@ -import { useNavigation } from "@react-navigation/native"; +import { useNavigation, useRoute } from "@react-navigation/native"; import { useEffect, useState } from "react"; import { Pressable, Text, View } from "react-native"; +import { scanBus } from "../lib/scanBus"; +import { Identicon } from "../components/Identicon"; import { isAddress } from "viem"; import { SkurVaultAbi } from "@web/abi/SkurVault"; import { fmtAmount, fmtBps, fmtDuration, parseAmount, short } from "@web/lib/format"; @@ -11,8 +13,7 @@ import { publicClient } from "../lib/client"; import { useInvalidateVault } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { BackButton, Badge, Button, Card, CircleIcon, Field, Input, KV, Notice, Row, Screen, SignBar, TierBadge, TopBar, TxStatus, s } from "../components/ui"; +import { BackButton, Badge, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Row, Screen, Sheet, SignBar, TierBadge, TopBar, TrustBadge, TxStatus, s } from "../components/ui"; import { C, F } from "../theme"; type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust }; @@ -20,11 +21,13 @@ type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredAppro /** Send: big amount, asset chips, recipient and purpose; the vault's own review card; sticky sign bar to propose. */ export function Send({ vault }: { vault: VaultData }) { const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); + const route = useRoute<{ key: string; name: string; params?: { asset?: `0x${string}`; to?: `0x${string}` } }>(); const { signer } = useStore(); const invalidate = useInvalidateVault(vault.address); const tx = useTx(() => { invalidate(); }); - const [to, setTo] = useState(""); - const [assetAddr, setAssetAddr] = useState(vault.assets[0]?.address); + const [to, setTo] = useState(route.params?.to ?? ""); + const [assetAddr, setAssetAddr] = useState(route.params?.asset ?? vault.assets[0]?.address); + const [pickRecipient, setPickRecipient] = useState(false); const [amountText, setAmountText] = useState(""); const [memo, setMemo] = useState(""); const [preview, setPreview] = useState(null); @@ -83,9 +86,11 @@ export function Send({ vault }: { vault: VaultData }) { - + {isAddress(to) ? : } setTo(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> + {vault.recipients.length > 0 && setPickRecipient(true)} />} + { scanBus.request((a) => setTo(a)); nav.navigate("Scan"); }} /> @@ -109,6 +114,11 @@ export function Send({ vault }: { vault: VaultData }) { )} + setPickRecipient(false)} title="Known recipients"> + {vault.recipients.map((r, i) => ( + } title={short(r.address, 6)} subtitle={`${r.paymentCount.toString()} payment${r.paymentCount === 1n ? "" : "s"}`} trailing={} onPress={() => { setTo(r.address); setPickRecipient(false); }} last={i === vault.recipients.length - 1} /> + ))} + ); } diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index b877f3f..e0a72bb 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -1,7 +1,7 @@ import * as LocalAuthentication from "expo-local-authentication"; import { useNavigation } from "@react-navigation/native"; import { useEffect, useState } from "react"; -import { Alert, Linking, Switch, Text, View } from "react-native"; +import { Linking, Switch, Text, View } from "react-native"; import { ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC, DEPLOYMENTS } from "@web/config/chain"; import { short } from "@web/lib/format"; import { roleNames } from "@web/lib/types"; @@ -14,12 +14,9 @@ import { C } from "../theme"; export function Settings({ vault }: { vault: VaultData | undefined }) { const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); - const { vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics } = useStore(); + const { vaultAddress, setVaultAddress, labels, setLabel, signer, biometrics, setBiometrics } = useStore(); const roles = useMyRoles(vault); const [name, setName] = useState(vaultAddress ? labels[vaultAddress.toLowerCase()] ?? "" : ""); - const [importing, setImporting] = useState(false); - const [importKey, setImportKey] = useState(""); - const [importErr, setImportErr] = useState(null); const [bioAvailable, setBioAvailable] = useState(false); useEffect(() => { void (async () => setBioAvailable((await LocalAuthentication.hasHardwareAsync()) && (await LocalAuthentication.isEnrolledAsync())))(); }, []); @@ -31,35 +28,23 @@ export function Settings({ vault }: { vault: VaultData | undefined }) { {vaultAddress ? ( <> } title={ { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} style={{ height: 36, paddingHorizontal: 10, backgroundColor: "transparent", borderWidth: 0, fontFamily: "DMSans_700Bold" }} />} subtitle={
      } /> - } title="Policy" subtitle={vault ? `v${vault.policyVersion} · ${vault.members.length} members` : "…"} /> + } title="Policy" subtitle={vault ? `v${vault.policyVersion} · templates, tiers, delays, caps` : "…"} onPress={() => nav.navigate("Policy")} chevron /> + } title="Members" subtitle={vault ? `${vault.members.length} members · roles and thresholds` : "…"} onPress={() => nav.navigate("Members")} chevron /> + } title="Address book" subtitle="Recipients, activation and trust" onPress={() => nav.navigate("AddressBook")} chevron /> + } title="Simulator" subtitle="Run attacks against the policy" onPress={() => nav.navigate("Simulator")} chevron /> + } title="Updates" subtitle="What needs you, recent activity" onPress={() => nav.navigate("Notifications")} chevron /> } title="Security" subtitle="Mode, guardians, posture, maximum loss" onPress={() => nav.navigate("Security")} chevron /> } title="View on Blockscout" onPress={() => void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vaultAddress}`)} chevron /> - } title="Switch vault" onPress={() => void setVaultAddress(null)} chevron last /> + } title="Switch vault" onPress={() => void setVaultAddress(null)} chevron /> + } title="Create a new vault" subtitle="Name, template, members, one signature" onPress={() => nav.navigate("CreateVault")} chevron last /> - ) : } title="Open a vault" onPress={() => void setVaultAddress(null)} chevron last />} + ) : <>} title="Open a vault" onPress={() => void setVaultAddress(null)} chevron />} title="Create a new vault" onPress={() => nav.navigate("CreateVault")} chevron last />} - Signer on this phone + Signers on this phone - {signer ? ( - <> - } title="Device signer" subtitle={
      } trailing={roles ? {roleNames(roles).join(" · ")} : no role here} /> - } title="Require Face ID to sign" subtitle={bioAvailable ? "Prompted before every signature" : "No biometrics enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} /> - } title={Remove signer key} subtitle="Deletes the key from this phone" onPress={() => Alert.alert("Remove signer key?", "The key is deleted from this phone. Anything it can sign for becomes unreachable from here unless you have it backed up.", [{ text: "Keep", style: "cancel" }, { text: "Remove", style: "destructive", onPress: () => void removeSigner() }])} chevron last /> - - ) : ( - <> - } title="Create a signer key" subtitle="Generated and kept in the device keychain" onPress={() => void createSigner()} chevron /> - } title="Import a private key" subtitle="A key you already use as a member" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> - {importing && ( - - - - {importErr && {importErr}} - - )} - - )} + : } title={signer ? signer.label : "No signer yet"} subtitle={signer ?
      : "Create or import a key to sign from this phone"} trailing={roles ? {roleNames(roles).join(" · ")} : signer ? no role here : undefined} onPress={() => nav.navigate("Signers")} chevron /> + } title="Require Face ID to sign" subtitle={bioAvailable ? "Prompted before every signature" : "No biometrics enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} last /> The private key never leaves the phone. Only signed transactions do. Give this address a role in a vault to sign for it. diff --git a/mobile/src/screens/Signers.tsx b/mobile/src/screens/Signers.tsx new file mode 100644 index 0000000..c93ca38 --- /dev/null +++ b/mobile/src/screens/Signers.tsx @@ -0,0 +1,60 @@ +import { useNavigation } from "@react-navigation/native"; +import { useState } from "react"; +import { Alert, Text, View } from "react-native"; +import { roleNames } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { useStore } from "../state/store"; +import { Identicon } from "../components/Identicon"; +import { Address, BackButton, Badge, Button, Card, CircleIcon, Field, Icon, Input, Notice, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; +import { C, F } from "../theme"; + +/** Safe's "Select signer": every key on this phone, which one signs, and how to add or remove one. */ +export function Signers({ vault }: { vault: VaultData | undefined }) { + const nav = useNavigation<{ goBack: () => void }>(); + const { signers, signer, setActiveSigner, createSigner, importSigner, removeSigner } = useStore(); + const [importing, setImporting] = useState(false); + const [key, setKey] = useState(""); + const [err, setErr] = useState(null); + const rolesOf = (a: string) => vault?.members.find((m) => m.address.toLowerCase() === a.toLowerCase())?.roles ?? 0; + return ( + nav.goBack()} />} center={Select signer} />}> + + {signers.length === 0 && No signer on this phone yet. Create a key here, then add its address as a member of your vault, or import a key you already use.} + {signers.length > 0 && ( + + {signers.map((sg, i) => { + const r = rolesOf(sg.address); + return ( + } title={sg.label} subtitle={
      } onPress={() => void setActiveSigner(sg.address)} last={i === signers.length - 1} + trailing={{r ? {roleNames(r).join(" · ")} : vault ? no role : null}{signer?.address === sg.address ? : null}} /> + ); + })} + + )} + Add a signer + + } title="Create a signer key" subtitle="Generated and kept in the device keychain" onPress={() => void createSigner()} chevron /> + } title="Import a private key" subtitle="A key you already use as a member" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> + {importing && ( + + + + {err && {err}} + + )} + + {signer && ( + <> + Active signer + + } title={Remove {signer.label}} subtitle="Deletes the key from this phone" chevron last + onPress={() => Alert.alert("Remove signer key?", "The key is deleted from this phone. Anything it can sign for becomes unreachable from here unless you have it backed up.", [{ text: "Keep", style: "cancel" }, { text: "Remove", style: "destructive", onPress: () => void removeSigner(signer.address) }])} /> + + + )} + Keys never leave the phone. Only signed transactions do. The active signer is the one the Sign bar uses. + {signers.length} key{signers.length === 1 ? "" : "s"} on this device + + + ); +} diff --git a/mobile/src/screens/Simulator.tsx b/mobile/src/screens/Simulator.tsx new file mode 100644 index 0000000..d0e9ba4 --- /dev/null +++ b/mobile/src/screens/Simulator.tsx @@ -0,0 +1,70 @@ +import { useNavigation } from "@react-navigation/native"; +import { useMemo, useState } from "react"; +import { Pressable, Text, View } from "react-native"; +import { NATIVE_ASSET } from "@web/config/chain"; +import { fmtAmount, parseAmount } from "@web/lib/format"; +import { runScenarios, type Verdict } from "@web/lib/simulator"; +import { TEMPLATES, type TemplateId } from "@web/lib/templates"; +import type { Policy } from "@web/lib/types"; +import type { VaultData } from "@web/lib/vaultReads"; +import { BackButton, Badge, Card, CircleIcon, Field, Input, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; +import { C, F } from "../theme"; + +const TONE: Record = { blocked: "ok", impossible: "ok", delayed: "info", escalated: "warn", allowed: "bad" }; +const TEXT: Record = { blocked: "Blocked", impossible: "Not possible", delayed: "Delayed", escalated: "Escalated", allowed: "Would succeed" }; + +/** Runs the policy against the attacks that actually happen, with the contract's own rules. */ +export function Simulator({ vault }: { vault: VaultData | undefined }) { + const nav = useNavigation<{ goBack: () => void }>(); + const [source, setSource] = useState<"vault" | TemplateId>(vault ? "vault" : "startup"); + const [balanceText, setBalanceText] = useState("1,000,000"); + const [approvers, setApprovers] = useState("3"); + const [guardians, setGuardians] = useState("1"); + const stable = vault?.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault?.assets[0]; + const decimals = stable?.decimals ?? 6; + const symbol = stable?.symbol ?? "USD"; + const { policy, limits } = useMemo(() => { + if (source === "vault" && vault && stable) return { policy: vault.policy as Policy, limits: stable.limits }; + const t = TEMPLATES.find((x) => x.id === source) ?? TEMPLATES[0]; + return { policy: t.policy, limits: t.stable }; + }, [source, vault, stable]); + const balance = source === "vault" && stable ? stable.balance : (parseAmount(balanceText, decimals) ?? 0n); + const approverCount = source === "vault" && vault ? vault.counts.approvers : Number(approvers) || 0; + const guardianCount = source === "vault" && vault ? vault.counts.guardians : Number(guardians) || 0; + const results = useMemo(() => runScenarios({ policy, limits, balance, decimals, symbol, approverCount, guardianCount }), [policy, limits, balance, decimals, symbol, approverCount, guardianCount]); + const stopped = results.filter((r) => r.verdict !== "allowed").length; + const [open, setOpen] = useState(null); + return ( + nav.goBack()} />} center={Simulator} right={{stopped}/{results.length} stopped} />}> + + Configuration under test + + {vault && setSource("vault")}>Live vault v{vault.policyVersion}} + {TEMPLATES.map((t) => setSource(t.id)}>{t.name})} + + {source === "vault" && stable ? Treasury {fmtAmount(stable.balance, stable.decimals, stable.symbol)} · {approverCount} approvers · {guardianCount} guardians : ( + + + + + + + + )} + Scenarios + + {results.map((r, i) => ( + + } title={r.title} subtitle={r.narrative} trailing={{TEXT[r.verdict]}} chevron onPress={() => setOpen(open === r.id ? null : r.id)} last={i === results.length - 1 && open !== r.id} /> + {open === r.id && {r.detail.map((d) => ▪ {d})}} + + ))} + + Blocked and Not possible mean the contract refuses. Delayed means guardians get a veto window. Escalated means more approvals are needed but nothing waits. Would succeed is a gap to close before the policy goes live. + + + ); +} +function Chip({ on, onPress, children }: { on: boolean; onPress: () => void; children: React.ReactNode }) { + return {children}; +} diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx index e239db6..064910c 100644 --- a/mobile/src/screens/Transactions.tsx +++ b/mobile/src/screens/Transactions.tsx @@ -1,20 +1,21 @@ import { useNavigation } from "@react-navigation/native"; import { useState } from "react"; -import { RefreshControl, Text, View } from "react-native"; +import { Pressable, RefreshControl, Text, View } from "react-native"; import { fmtDate } from "@web/lib/format"; import { Kind, Status } from "@web/lib/types"; import type { ProposalView, VaultData } from "@web/lib/vaultReads"; import { describeProposal, statusText } from "../lib/describe"; import { Badge, Card, CircleIcon, Empty, IconButton, Notice, Row, Screen, StatusBadge, Tabs, TopBar, type IconName, s } from "../components/ui"; -import { C } from "../theme"; +import { C, F } from "../theme"; export const KIND_ICON: Record = { [Kind.TRANSFER]: "arrow-up-right", [Kind.POLICY_UPDATE]: "sliders", [Kind.ASSET_LIMITS]: "sliders", [Kind.MEMBER_SET]: "users", [Kind.RECIPIENT_TRUST]: "book", [Kind.MODE_RELAX]: "shield", [Kind.RECOVERY]: "life-buoy" }; export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const [tab, setTab] = useState<"queue" | "history">("queue"); + const [filter, setFilter] = useState<"all" | "transfers" | "governance">("all"); const pendingCount = vault.proposals.filter((p) => p.status === Status.PENDING).length; - const items = vault.proposals.filter((p) => (tab === "queue" ? p.status === Status.PENDING : p.status !== Status.PENDING)); + const items = vault.proposals.filter((p) => (tab === "queue" ? p.status === Status.PENDING : p.status !== Status.PENDING)).filter((p) => (filter === "all" ? true : filter === "transfers" ? p.kind === Kind.TRANSFER : p.kind !== Kind.TRANSFER)); const groups = new Map(); for (const p of items) { const d = fmtDate(p.createdAt).split(" at ")[0]; groups.set(d, [...(groups.get(d) ?? []), p]); } return ( @@ -22,6 +23,11 @@ export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; top={ nav.navigate("Send")} />} />}> + + {(["all", "transfers", "governance"] as const).map((f) => ( + setFilter(f)} style={{ paddingHorizontal: 12, height: 32, borderRadius: 16, backgroundColor: filter === f ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{f === "all" ? "All types" : f === "transfers" ? "Transfers" : "Governance & security"} + ))} + {vault.logsFailed && The chain's event log could not be read, so purposes and history details are missing.} {vault.activityLoading ? Reading proposals and history from the chain… : items.length === 0 ? ( diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx index 5721399..16beac6 100644 --- a/mobile/src/screens/Welcome.tsx +++ b/mobile/src/screens/Welcome.tsx @@ -1,41 +1,50 @@ import { useRef, useState } from "react"; -import { Dimensions, ScrollView, Text, View, type NativeScrollEvent, type NativeSyntheticEvent } from "react-native"; +import { Dimensions, Pressable, ScrollView, StatusBar, Text, View, type NativeScrollEvent, type NativeSyntheticEvent } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Identicon } from "../components/Identicon"; -import { Badge, Button, CircleIcon, Icon, Logo, Tape, s } from "../components/ui"; +import { Icon } from "../components/ui"; import { C, F } from "../theme"; const W = Dimensions.get("window").width; +/** Light tokens for the first-launch screens, matching the web's marketing pages. */ +const L = { bg: "#ffffff", text: "#212529", text2: "#6c757d", card: "#f1f3f5", card2: "#e9ecef", border: "#dee2e6" }; -/** First-launch carousel, after Safe{Mobile}'s: illustration, headline, dots, one button. Three pages, Skur's pattern. */ +const PAGES = [ + { title: "Track your\nvaults. Anywhere.", sub: "Easily track balances and get real-time updates on vault activity, anytime.", art: }, + { title: "Sign transactions\non the go", sub: "Enjoy peace of mind with transaction checks, ensuring secure signing.", art: }, + { title: "Get\npersonalized\nupdates", sub: "Stay informed with notifications tailored to your vaults.", art: }, +]; + +/** First launch, after Safe{Mobile}: wordmark, illustration, headline, dots, one black button. */ export function Welcome({ onDone }: { onDone: () => void }) { const insets = useSafeAreaInsets(); const [page, setPage] = useState(0); const ref = useRef(null); const onScroll = (e: NativeSyntheticEvent) => setPage(Math.round(e.nativeEvent.contentOffset.x / W)); - const pages = [ - { title: "Watch your\ntreasury. Anywhere.", sub: "Balances, the queue and the policy, read straight from the vault contract. No server in between.", art: }, - { title: "Sign from\nyour phone", sub: "A key kept in this phone's keychain, behind Face ID. Every payment is scored by the vault before you sign.", art: }, - { title: "Every payment,\nscored first", sub: "Amount, recipient trust, today's outflow and the security mode set how many approvals it needs and how long it waits.", art: }, - ]; return ( - - + + + + S + Skur + MOBILE + - {pages.map((p, i) => ( - - {p.art} - {p.title} - {p.sub} + {PAGES.map((p, i) => ( + + {p.art} + {p.title} + {p.sub} ))} - - {pages.map((_, i) => )} + + {PAGES.map((_, i) => )} - - Skip + ({ height: 56, borderRadius: 14, backgroundColor: L.text, alignItems: "center", justifyContent: "center", opacity: pressed ? 0.85 : 1 })}> + Get started + ); @@ -45,43 +54,71 @@ const A1 = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; const A2 = "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0"; const A3 = "0xCec10C48B8d37b6A083000173e3415Cc6f86974F"; -function ArtTreasury() { +function Blur({ x, y, size, color }: { x: number; y: number; size: number; color: string }) { + return ; +} + +/** Floating token and vault icons, as on Safe's first page; the Skur tile takes the place of the green Safe tile. */ +function ArtTrack() { return ( - - - - - - Normal - - + + + + + + A + K + S + + S + ); } +/** Phone mockup with the signer picker and a toast, as on Safe's second page. */ function ArtSign() { return ( - - - - Select signer - Device signer - + + + + Select signer + + My signer + + {[A3, A1].map((a, i) => ( + + My signer #{i + 2} + + ))} + + + Policy check passed - Policy check passed ); } -function ArtTiers() { - const rows: Array<[string, string, "ok" | "warn" | "bad"]> = [["1,000 sUSD · known supplier", "Low · 1 approval · now", "ok"], ["12,000 sUSD · new address", "High · 2 approvals · 1 day", "warn"], ["60,000 sUSD · 24% of holdings", "Critical · 2 + guardian", "bad"]]; +/** Stacked notification cards, as on Safe's third page. */ +function ArtUpdates() { + const cards: Array<{ text: string; when: string; tone: string; icon: "info" | "check" | "alert-circle"; strong?: string; w: number; dy: number; dim: number }> = [ + { strong: "A transaction", text: " requires your confirmation", when: "about 1 hour ago", tone: "#4dabf7", icon: "info", w: 1, dy: 0, dim: 1 }, + { text: "", when: "about 2 hours ago", tone: "#40c057", icon: "check", w: 0.9, dy: 92, dim: 0.75 }, + { text: "", when: "Just now", tone: "#fa5252", icon: "alert-circle", w: 0.82, dy: 176, dim: 0.5 }, + ]; return ( - - {rows.map(([a, b, t], i) => ( - - - {a}{b} - {t === "ok" ? "Low" : t === "warn" ? "High" : "Critical"} + + + + + {cards.map((c, i) => ( + + + + {c.strong ? {c.strong}{c.text} : } + {c.when} + + ))} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx index 946f673..33575c7 100644 --- a/mobile/src/state/store.tsx +++ b/mobile/src/state/store.tsx @@ -3,60 +3,87 @@ import * as SecureStore from "expo-secure-store"; import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; -export type Signer = { key: `0x${string}`; address: `0x${string}` }; +export type Signer = { key: `0x${string}`; address: `0x${string}`; label: string }; type Store = { ready: boolean; vaultAddress: `0x${string}` | null; setVaultAddress: (a: `0x${string}` | null) => Promise; labels: Record; setLabel: (vault: `0x${string}`, name: string) => Promise; + /** The active signer, or null when the phone holds no key. */ signer: Signer | null; - createSigner: () => Promise; - importSigner: (key: string) => Promise; - removeSigner: () => Promise; + signers: Signer[]; + createSigner: (label?: string) => Promise; + importSigner: (key: string, label?: string) => Promise; + removeSigner: (address?: `0x${string}`) => Promise; + setActiveSigner: (address: `0x${string}`) => Promise; + renameSigner: (address: `0x${string}`, label: string) => Promise; biometrics: boolean; setBiometrics: (on: boolean) => Promise; onboarded: boolean; - setOnboarded: () => Promise; + setOnboarded: (v?: boolean) => Promise; + notifications: boolean; + setNotifications: (on: boolean) => Promise; }; const Ctx = createContext(null); -const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer", onboarded: "skur.onboarded" }; +const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer", signers: "skur.signers", active: "skur.activeSigner", onboarded: "skur.onboarded", notif: "skur.notifications" }; -/** App state. The signer's private key lives only in the device keychain (expo-secure-store); nothing leaves the phone but signed transactions. */ +const toSigner = (key: `0x${string}`, label: string): Signer => ({ key, address: privateKeyToAccount(key).address, label }); + +/** App state. Signer keys live only in the device keychain (expo-secure-store); nothing leaves the phone but signed transactions. */ export function StoreProvider({ children }: { children: ReactNode }) { const [ready, setReady] = useState(false); const [vaultAddress, setVault] = useState<`0x${string}` | null>(null); const [labels, setLabels] = useState>({}); - const [signer, setSigner] = useState(null); + const [signers, setSigners] = useState([]); + const [active, setActive] = useState<`0x${string}` | null>(null); const [biometrics, setBio] = useState(true); const [onboarded, setOnb] = useState(false); + const [notifications, setNotif] = useState(true); useEffect(() => { (async () => { try { - const [v, l, b, key, o] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer), AsyncStorage.getItem(K.onboarded)]); - if (o === "1") setOnb(true); + const [v, l, b, legacy, list, act, o, n] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer), SecureStore.getItemAsync(K.signers), AsyncStorage.getItem(K.active), AsyncStorage.getItem(K.onboarded), AsyncStorage.getItem(K.notif)]); if (v) setVault(v as `0x${string}`); if (l) setLabels(JSON.parse(l)); if (b !== null) setBio(b === "1"); - if (key) setSigner({ key: key as `0x${string}`, address: privateKeyToAccount(key as `0x${string}`).address }); + if (o === "1") setOnb(true); + if (n !== null) setNotif(n === "1"); + let arr: Array<{ key: `0x${string}`; label: string }> = list ? JSON.parse(list) : []; + if (legacy && !arr.some((x) => x.key === legacy)) { arr = [{ key: legacy as `0x${string}`, label: "Device signer" }, ...arr]; await SecureStore.setItemAsync(K.signers, JSON.stringify(arr)); await SecureStore.deleteItemAsync(K.signer); } + const ss = arr.map((x) => toSigner(x.key, x.label)); + setSigners(ss); + setActive((act as `0x${string}`) && ss.some((s) => s.address === act) ? (act as `0x${string}`) : ss[0]?.address ?? null); } finally { setReady(true); } })(); }, []); + const persist = useCallback(async (ss: Signer[]) => { setSigners(ss); await SecureStore.setItemAsync(K.signers, JSON.stringify(ss.map((s) => ({ key: s.key, label: s.label })))); }, []); const setVaultAddress = useCallback(async (a: `0x${string}` | null) => { setVault(a); if (a) await AsyncStorage.setItem(K.vault, a); else await AsyncStorage.removeItem(K.vault); }, []); const setLabel = useCallback(async (vault: `0x${string}`, name: string) => { setLabels((l) => { const n = { ...l, [vault.toLowerCase()]: name }; void AsyncStorage.setItem(K.labels, JSON.stringify(n)); return n; }); }, []); - const persistSigner = useCallback(async (key: `0x${string}`) => { const s = { key, address: privateKeyToAccount(key).address }; await SecureStore.setItemAsync(K.signer, key, { keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY }); setSigner(s); return s; }, []); - const createSigner = useCallback(() => persistSigner(generatePrivateKey()), [persistSigner]); - const importSigner = useCallback((raw: string) => { const k = (raw.trim().startsWith("0x") ? raw.trim() : `0x${raw.trim()}`) as `0x${string}`; if (!/^0x[0-9a-fA-F]{64}$/.test(k)) throw new Error("A private key is 64 hex characters."); return persistSigner(k); }, [persistSigner]); - const removeSigner = useCallback(async () => { await SecureStore.deleteItemAsync(K.signer); setSigner(null); }, []); + const addSigner = useCallback(async (key: `0x${string}`, label: string) => { + const s = toSigner(key, label); + const next = signers.some((x) => x.address === s.address) ? signers : [...signers, s]; + await persist(next); + setActive(s.address); await AsyncStorage.setItem(K.active, s.address); + return s; + }, [signers, persist]); + const createSigner = useCallback((label?: string) => addSigner(generatePrivateKey(), label ?? `Signer ${signers.length + 1}`), [addSigner, signers.length]); + const importSigner = useCallback((raw: string, label?: string) => { const k = (raw.trim().startsWith("0x") ? raw.trim() : `0x${raw.trim()}`) as `0x${string}`; if (!/^0x[0-9a-fA-F]{64}$/.test(k)) throw new Error("A private key is 64 hex characters."); return addSigner(k, label ?? `Signer ${signers.length + 1}`); }, [addSigner, signers.length]); + const removeSigner = useCallback(async (address?: `0x${string}`) => { const target = address ?? active; const next = signers.filter((s) => s.address !== target); await persist(next); const a = next[0]?.address ?? null; setActive(a); if (a) await AsyncStorage.setItem(K.active, a); else await AsyncStorage.removeItem(K.active); }, [signers, active, persist]); + const setActiveSigner = useCallback(async (address: `0x${string}`) => { setActive(address); await AsyncStorage.setItem(K.active, address); }, []); + const renameSigner = useCallback(async (address: `0x${string}`, label: string) => { await persist(signers.map((s) => (s.address === address ? { ...s, label } : s))); }, [signers, persist]); const setBiometrics = useCallback(async (on: boolean) => { setBio(on); await AsyncStorage.setItem(K.bio, on ? "1" : "0"); }, []); - const setOnboarded = useCallback(async () => { setOnb(true); await AsyncStorage.setItem(K.onboarded, "1"); }, []); + const setOnboarded = useCallback(async (v = true) => { setOnb(v); await AsyncStorage.setItem(K.onboarded, v ? "1" : "0"); }, []); + const setNotifications = useCallback(async (on: boolean) => { setNotif(on); await AsyncStorage.setItem(K.notif, on ? "1" : "0"); }, []); - const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics, onboarded, setOnboarded }), [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, createSigner, importSigner, removeSigner, biometrics, setBiometrics, onboarded, setOnboarded]); + const signer = useMemo(() => signers.find((s) => s.address === active) ?? null, [signers, active]); + const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, signers, createSigner, importSigner, removeSigner, setActiveSigner, renameSigner, biometrics, setBiometrics, onboarded, setOnboarded, notifications, setNotifications }), + [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, signers, createSigner, importSigner, removeSigner, setActiveSigner, renameSigner, biometrics, setBiometrics, onboarded, setOnboarded, notifications, setNotifications]); return {children}; } diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json index 8cdbf88..1704c70 100644 --- a/mobile/tsconfig.json +++ b/mobile/tsconfig.json @@ -3,8 +3,24 @@ "compilerOptions": { "strict": true, "resolveJsonModule": true, - "paths": { "@web/*": ["../web/src/*"] } + "paths": { + "@web/*": [ + "../web/src/*" + ] + } }, - "include": ["**/*.ts", "**/*.tsx", "../web/src/lib/**/*.ts", "../web/src/abi/*.ts", "../web/src/config/*.ts"], - "exclude": ["node_modules", "../web/src/lib/*.test.ts", "../web/src/lib/motion.ts"] -} + "include": [ + "**/*.ts", + "**/*.tsx", + "../web/src/lib/**/*.ts", + "../web/src/abi/*.ts", + "../web/src/config/*.ts" + ], + "exclude": [ + "node_modules", + "ios", + "android", + "../web/src/lib/*.test.ts", + "../web/src/lib/motion.ts" + ] +} \ No newline at end of file diff --git a/web/src/lib/policyFields.ts b/web/src/lib/policyFields.ts new file mode 100644 index 0000000..d7db8ac --- /dev/null +++ b/web/src/lib/policyFields.ts @@ -0,0 +1,51 @@ +import type { Policy } from "./types"; + +/** Policy editor field definitions, shared by the web and mobile editors. */ +export const H = 3600; +export type Unit = "count" | "hours" | "bps" | "bool"; +export type PolicyField = { key: keyof Policy; label: string; hint: string; unit: Unit; max?: number }; + +export const POLICY_GROUPS: Array<{ title: string; sub: string; fields: PolicyField[] }> = [ + { + title: "Approvals", + sub: "How many confirmations each tier needs. Guardians confirm critical transfers in addition to approvers.", + fields: [ + { key: "approvalsLow", label: "Low tier", hint: "Routine payments under the routine threshold.", unit: "count" }, + { key: "approvalsHigh", label: "High tier", hint: "Larger payments, new recipients, elevated posture.", unit: "count" }, + { key: "approvalsCritical", label: "Critical tier", hint: "Very large or high-exposure payments.", unit: "count" }, + { key: "guardianRequiredCritical", label: "Guardian required for Critical", hint: "An independent sign-off on the largest transfers.", unit: "bool" }, + { key: "guardianThreshold", label: "Guardian confirmations", hint: "For critical transfers, leaving Lockdown and recovery.", unit: "count" }, + { key: "governanceThreshold", label: "Owner approvals for governance", hint: "Policy, limits, members, trust, mode changes.", unit: "count" }, + ], + }, + { + title: "Delays", + sub: "A delay gives guardians a veto window and gives the organisation time to notice.", + fields: [ + { key: "delayHigh", label: "High-tier delay", hint: "Between full approval and execution.", unit: "hours" }, + { key: "delayCritical", label: "Critical delay", hint: "Also the guardian veto window.", unit: "hours" }, + { key: "recipientActivationDelay", label: "New-recipient activation", hint: "A never-seen address cannot be paid sooner.", unit: "hours" }, + { key: "policyChangeDelay", label: "Security-reducing change delay", hint: "Any loosening waits this long and can be vetoed.", unit: "hours" }, + { key: "recoveryDelay", label: "Recovery delay", hint: "Owners can cancel a recovery during it.", unit: "hours" }, + { key: "proposalTtl", label: "Proposal lifetime", hint: "Must exceed the longest delay by at least 1h.", unit: "hours" }, + ], + }, + { + title: "Exposure", + sub: "Share of the asset's holdings that a single payment may move before it is escalated or refused.", + fields: [ + { key: "highExposureBps", label: "Escalate to High at", hint: "Percent of holdings.", unit: "bps", max: 100 }, + { key: "criticalExposureBps", label: "Escalate to Critical at", hint: "", unit: "bps", max: 100 }, + { key: "hardBlockExposureBps", label: "Refuse above", hint: "0 disables the hard block.", unit: "bps", max: 100 }, + ], + }, + { + title: "Circuit breaker", + sub: "Cumulative outflow per window as a share of holdings. The transfer that would exceed it is not paid; the vault enters Lockdown.", + fields: [ + { key: "envelopeBps", label: "Loss envelope", hint: "0 disables the breaker.", unit: "bps", max: 100 }, + { key: "envelopeWindow", label: "Envelope window", hint: "At least 1 hour.", unit: "hours" }, + ], + }, +]; + diff --git a/web/src/pages/Policies.tsx b/web/src/pages/Policies.tsx index e8f280a..3129def 100644 --- a/web/src/pages/Policies.tsx +++ b/web/src/pages/Policies.tsx @@ -10,53 +10,8 @@ import { limitReductions, policyReductions, policyToContract, validateCounts, va import { TEMPLATES, type TemplateId } from "../lib/templates"; import { ROLE_OWNER, type AssetLimits, type Policy } from "../lib/types"; -const H = 3600; -type Unit = "count" | "hours" | "bps" | "bool"; -type F = { key: keyof Policy; label: string; hint: string; unit: Unit; max?: number }; - -const GROUPS: Array<{ title: string; sub: string; fields: F[] }> = [ - { - title: "Approvals", - sub: "How many confirmations each tier needs. Guardians confirm critical transfers in addition to approvers.", - fields: [ - { key: "approvalsLow", label: "Low tier", hint: "Routine payments under the routine threshold.", unit: "count" }, - { key: "approvalsHigh", label: "High tier", hint: "Larger payments, new recipients, elevated posture.", unit: "count" }, - { key: "approvalsCritical", label: "Critical tier", hint: "Very large or high-exposure payments.", unit: "count" }, - { key: "guardianRequiredCritical", label: "Guardian required for Critical", hint: "An independent sign-off on the largest transfers.", unit: "bool" }, - { key: "guardianThreshold", label: "Guardian confirmations", hint: "For critical transfers, leaving Lockdown and recovery.", unit: "count" }, - { key: "governanceThreshold", label: "Owner approvals for governance", hint: "Policy, limits, members, trust, mode changes.", unit: "count" }, - ], - }, - { - title: "Delays", - sub: "A delay gives guardians a veto window and gives the organisation time to notice.", - fields: [ - { key: "delayHigh", label: "High-tier delay", hint: "Between full approval and execution.", unit: "hours" }, - { key: "delayCritical", label: "Critical delay", hint: "Also the guardian veto window.", unit: "hours" }, - { key: "recipientActivationDelay", label: "New-recipient activation", hint: "A never-seen address cannot be paid sooner.", unit: "hours" }, - { key: "policyChangeDelay", label: "Security-reducing change delay", hint: "Any loosening waits this long and can be vetoed.", unit: "hours" }, - { key: "recoveryDelay", label: "Recovery delay", hint: "Owners can cancel a recovery during it.", unit: "hours" }, - { key: "proposalTtl", label: "Proposal lifetime", hint: "Must exceed the longest delay by at least 1h.", unit: "hours" }, - ], - }, - { - title: "Exposure", - sub: "Share of the asset's holdings that a single payment may move before it is escalated or refused.", - fields: [ - { key: "highExposureBps", label: "Escalate to High at", hint: "Percent of holdings.", unit: "bps", max: 100 }, - { key: "criticalExposureBps", label: "Escalate to Critical at", hint: "", unit: "bps", max: 100 }, - { key: "hardBlockExposureBps", label: "Refuse above", hint: "0 disables the hard block.", unit: "bps", max: 100 }, - ], - }, - { - title: "Circuit breaker", - sub: "Cumulative outflow per window as a share of holdings. The transfer that would exceed it is not paid; the vault enters Lockdown.", - fields: [ - { key: "envelopeBps", label: "Loss envelope", hint: "0 disables the breaker.", unit: "bps", max: 100 }, - { key: "envelopeWindow", label: "Envelope window", hint: "At least 1 hour.", unit: "hours" }, - ], - }, -]; +import { H, POLICY_GROUPS, type PolicyField as F } from "../lib/policyFields"; +const GROUPS = POLICY_GROUPS; function Control({ f, value, onChange }: { f: F; value: number | boolean; onChange: (v: number | boolean) => void }) { if (f.unit === "bool") { From 22c61e00ee376bceebce41294c6db0f02eb555ac Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 17:22:04 +0100 Subject: [PATCH 05/44] refactor(mobile): reference onboarding and screens that open instead of sprawl Onboarding follows the reference flow: a white ground, the wordmark, one illustration, a large headline, a short subtitle, page dots, and the same dark Get started button on every page. No skip link; the dots carry the progress. The dense screens become short lists. Security is six summary cards (posture, mode, guardians, recovery, maximum loss, history) that open on tap, each header carrying the number you would otherwise scroll for. Policy is the same: templates, one card per control group showing its current values, and history. Home keeps only what a phone home screen needs: the vault, what is pending, the balance, Send and Receive, and the token list. Policy and members moved to Settings, where they already had rows. Deep linking to a tab now pops whatever was pushed on top of it, and only dispatches the pop when something is actually pushed. --- mobile/App.tsx | 5 +- mobile/src/components/ui.tsx | 17 +++++++ mobile/src/screens/Home.tsx | 75 +++++++++++---------------- mobile/src/screens/Policy.tsx | 60 ++++++++++++++-------- mobile/src/screens/Security.tsx | 89 ++++++++++++++++----------------- mobile/src/screens/Welcome.tsx | 2 +- 6 files changed, 132 insertions(+), 116 deletions(-) diff --git a/mobile/App.tsx b/mobile/App.tsx index d9c5708..4b4f165 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -2,7 +2,7 @@ import { DMMono_400Regular, DMMono_500Medium } from "@expo-google-fonts/dm-mono" import { DMSans_400Regular, DMSans_500Medium, DMSans_700Bold } from "@expo-google-fonts/dm-sans"; import { SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold } from "@expo-google-fonts/space-grotesk"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; -import { createNavigationContainerRef, DarkTheme, NavigationContainer, type NavigatorScreenParams } from "@react-navigation/native"; +import { createNavigationContainerRef, DarkTheme, NavigationContainer, StackActions, type NavigatorScreenParams } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useFonts } from "expo-font"; @@ -114,7 +114,8 @@ function useDeepLinks(ready: boolean) { if (!navigationRef.isReady()) return false; // eslint-disable-next-line @typescript-eslint/no-explicit-any const nav = navigationRef.navigate as unknown as (name: string, params?: object) => void; - if (Array.isArray(target)) nav(target[0], { screen: target[1], ...(params ?? {}) }); + // Going to a tab means leaving whatever was pushed on top of it. + if (Array.isArray(target)) { if ((navigationRef.getRootState()?.routes.length ?? 0) > 1) navigationRef.dispatch(StackActions.popToTop()); nav(target[0], { screen: target[1], ...(params ?? {}) }); } else nav(target, params); return true; }, []); diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx index ed1f834..d990432 100644 --- a/mobile/src/components/ui.tsx +++ b/mobile/src/components/ui.tsx @@ -56,6 +56,23 @@ export function Logo({ size = 28, wordmark = true }: { size?: number; wordmark?: ); } +/** A card that opens on tap: the header carries the summary, so a long screen reads as a short list. */ +export function Expandable({ title, summary, icon, tone = "dark", children, open, onToggle }: { title: string; summary?: string; icon?: IconName; tone?: "dark" | "accent" | "success" | "error" | "warn"; children: ReactNode; open: boolean; onToggle: () => void }) { + return ( + + [{ flexDirection: "row", alignItems: "center", gap: 12, padding: 16 }, pressed && { opacity: 0.7 }]}> + {icon ? : null} + + {title} + {summary ? {summary} : null} + + + + {open ? {children} : null} + + ); +} + export function Card({ children, style, flush = false }: { children: ReactNode; style?: StyleProp; flush?: boolean }) { return {children}; } diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index 985cfff..428db5c 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -2,32 +2,31 @@ import { useNavigation } from "@react-navigation/native"; import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { NATIVE_ASSET } from "@web/config/chain"; -import { fmtAmount, fmtDuration, short } from "@web/lib/format"; -import { Mode, ROLE_APPROVER, ROLE_OWNER, roleNames, Status } from "@web/lib/types"; +import { fmtAmount } from "@web/lib/format"; +import { Mode, ROLE_APPROVER, ROLE_OWNER, Status } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; +import { needsMe } from "../hooks/useAlerts"; import { useMyRoles } from "../hooks/useVault"; +import { scanBus } from "../lib/scanBus"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { needsMe } from "../hooks/useAlerts"; -import { scanBus } from "../lib/scanBus"; import { VaultSheet } from "../components/VaultSheet"; -import { Address, Badge, Card, CircleIcon, Icon, IconButton, KV, Row, Screen, Tabs, Tape, TopBar, s } from "../components/ui"; +import { Address, CircleIcon, Icon, IconButton, Row, Screen, Tape, TopBar, s } from "../components/ui"; import { C, F } from "../theme"; +/** Home is the vault at a glance: what it holds, what is waiting, and the two things you do most. */ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); - const { labels, signer } = useStore(); + const { labels, signer, setVaultAddress } = useStore(); const roles = useMyRoles(vault); const [sheet, setSheet] = useState(false); - const [tab, setTab] = useState<"tokens" | "policy" | "members">("tokens"); const label = labels[vault.address.toLowerCase()] ?? "Treasury vault"; const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; const canPropose = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)) && vault.mode !== Mode.LOCKDOWN; const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null).length; - const { setVaultAddress } = useStore(); - const scanVault = () => { scanBus.request((a) => void setVaultAddress(a as `0x${string}`)); nav.navigate("Scan"); }; const [whole, frac] = stable ? fmtAmount(stable.balance, stable.decimals, undefined, 2).split(".") : ["—", undefined]; + const scanVault = () => { scanBus.request((a) => void setVaultAddress(a as `0x${string}`)); nav.navigate("Scan"); }; return ( } @@ -41,82 +40,68 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch } - right={<> 0 || vault.mode !== Mode.NORMAL} onPress={() => nav.navigate("Notifications")} />} + right={<> 0} onPress={() => nav.navigate("Notifications")} />} /> {vault.mode !== Mode.NORMAL && } }> - + {pending > 0 && ( - nav.navigate("Main", { screen: "Transactions" })} style={h.pending}> + nav.navigate("Main", { screen: "Transactions" })} style={h.banner}> {pending} Pending transactions )} {vault.mode !== Mode.NORMAL && ( - nav.navigate("Security")} style={[h.pending, { backgroundColor: vault.mode === Mode.LOCKDOWN ? C.errorBg : C.warningBg }]}> + nav.navigate("Security")} style={[h.banner, { backgroundColor: vault.mode === Mode.LOCKDOWN ? C.errorBg : C.warningBg }]}> {vault.mode === Mode.LOCKDOWN ? "Lockdown: outgoing payments are frozen" : "Elevated: every payment scored one tier higher"} )} - + + A Ark devnet
      - + {whole} {frac ? .{frac} : null} {stable?.symbol} - policy v{vault.policyVersion} · {vault.members.length} members · {roleNames(roles).join(", ") || (signer ? "not a member" : "read-only")} - + + nav.navigate("Send")} /> nav.navigate("Receive")} /> - nav.navigate("Security")} /> - - - - {tab === "tokens" && vault.assets.map((a, i) => ( - } title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(a.balance, a.decimals)} ${a.symbol}`} onPress={canPropose ? () => nav.navigate("Send", { asset: a.address }) : undefined} last={i === vault.assets.length - 1} - trailing={{fmtAmount(a.balance, a.decimals)}{fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of {a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today} /> - ))} - {tab === "policy" && ( - - nav.navigate("Policy")} style={{ flexDirection: "row", alignItems: "center", gap: 8, paddingVertical: 10 }}>Edit policy · v{vault.policyVersion} - - - - - - {stable && } - - )} - {tab === "members" && vault.members.map((m, i) => ( - } title={short(m.address, 6)} subtitle={m.address.toLowerCase() === signer?.address.toLowerCase() ? "this phone" : undefined} onPress={() => nav.navigate("Members")} chevron last={i === vault.members.length - 1} - trailing={{roleNames(m.roles).map((r) => {r})}} /> + + Tokens + {vault.assets.map((a, i) => ( + } + title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of ${a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today`} + trailing={{fmtAmount(a.balance, a.decimals)}} + onPress={canPropose ? () => nav.navigate("Send", { asset: a.address }) : undefined} last={i === vault.assets.length - 1} /> ))} setSheet(false)} /> ); } -function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arrow-up-right" | "arrow-down-left" | "shield"; label: string; onPress: () => void; tone?: "dark" | "accent"; disabled?: boolean }) { +function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arrow-up-right" | "arrow-down-left"; label: string; onPress: () => void; tone?: "dark" | "accent"; disabled?: boolean }) { return ( - [h.action, tone === "accent" && { backgroundColor: C.accent }, { opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }]}> + [h.action, tone === "accent" && { backgroundColor: C.accent }, { opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }]}> - {label} + {label} ); } const h = { - pending: { flexDirection: "row" as const, alignItems: "center" as const, gap: 10, backgroundColor: C.accentBg, borderRadius: 14, paddingHorizontal: 14, height: 48, marginBottom: 12 }, + banner: { flexDirection: "row" as const, alignItems: "center" as const, gap: 10, backgroundColor: C.accentBg, borderRadius: 14, paddingHorizontal: 14, height: 48, marginBottom: 14 }, count: { minWidth: 22, height: 22, borderRadius: 11, backgroundColor: C.accent, alignItems: "center" as const, justifyContent: "center" as const, paddingHorizontal: 6 }, - balance: { fontFamily: F.display, fontSize: 40, color: C.text, letterSpacing: -1.2 }, - action: { flex: 1, height: 44, borderRadius: 12, backgroundColor: C.card, flexDirection: "row" as const, alignItems: "center" as const, justifyContent: "center" as const, gap: 6 }, + balance: { fontFamily: F.display, fontSize: 44, color: C.text, letterSpacing: -1.4 }, + action: { flex: 1, height: 48, borderRadius: 14, backgroundColor: C.card, flexDirection: "row" as const, alignItems: "center" as const, justifyContent: "center" as const, gap: 8 }, }; diff --git a/mobile/src/screens/Policy.tsx b/mobile/src/screens/Policy.tsx index b65fd4a..074f242 100644 --- a/mobile/src/screens/Policy.tsx +++ b/mobile/src/screens/Policy.tsx @@ -11,9 +11,22 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; -import { BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Screen, SectionLabel, SignBar, Tabs, TopBar, TxStatus, s } from "../components/ui"; +import { BackButton, Badge, Button, Card, Expandable, Field, Input, Notice, Screen, SignBar, Tabs, TopBar, TxStatus, type IconName, s } from "../components/ui"; import { C, F } from "../theme"; +const GROUP_ICON: Record = { Approvals: "users", Delays: "clock", Exposure: "pie-chart", "Circuit breaker": "zap" }; + +/** One line per group, opened on tap: the whole policy stays readable on a phone. */ +function groupSummary(fields: PolicyField[], p: Policy): string { + return fields.slice(0, 3).map((f) => { + const v = p[f.key]; + if (f.unit === "bool") return `${f.label.split(" ")[0]} ${v ? "yes" : "no"}`; + if (f.unit === "hours") return fmtDuration(Number(v)); + if (f.unit === "bps") return `${Number(v) / 100}%`; + return String(v); + }).join(" · "); +} + /** The policy editor: templates, every control in groups, security-reducing detection, and per-asset limits. */ export function Policy({ vault }: { vault: VaultData }) { const nav = useNavigation<{ goBack: () => void }>(); @@ -23,6 +36,8 @@ export function Policy({ vault }: { vault: VaultData }) { const invalidate = useInvalidateVault(vault.address); const tx = useTx(invalidate); const [tab, setTab] = useState<"policy" | "limits">("policy"); + const [open, setOpen] = useState(null); + const toggle = (k: string) => setOpen((o) => (o === k ? null : k)); const [draft, setDraft] = useState(vault.policy); const [template, setTemplate] = useState(null); const seen = useRef(vault.policyVersion); @@ -64,29 +79,32 @@ export function Policy({ vault }: { vault: VaultData }) { {tab === "policy" && ( - Templates - Start from a profile instead of designing a policy from scratch. Choosing one only fills the editor; nothing is proposed until you sign. - - {TEMPLATES.map((t) => ( - { setTemplate(t.id); setDraft(t.policy); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: template === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name} - ))} - {changed && { setDraft(vault.policy); setTemplate(null); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, borderWidth: 1, borderColor: C.border, alignItems: "center", justifyContent: "center" }}>Reset} - - {POLICY_GROUPS.map((g) => ( - - {g.title} - {g.sub} - - {g.fields.map((f, i) => set(f.key, v)} last={i === g.fields.length - 1} />)} - + t.id === template)?.name} loaded into the editor` : "start from a profile instead of designing from scratch"} icon="layers" open={open === "templates"} onToggle={() => toggle("templates")}> + + {TEMPLATES.map((t) => ( + { setTemplate(t.id); setDraft(t.policy); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: template === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name} + ))} - ))} + Choosing one only fills the editor. Nothing is proposed until you sign. + {changed && } + + + {POLICY_GROUPS.map((g) => { + const edited = g.fields.filter((f) => draft[f.key] !== vault.policy[f.key]).length; + return ( + toggle(g.title)}> + {g.sub} + {g.fields.map((f, i) => set(f.key, v)} last={i === g.fields.length - 1} />)} + + ); + })} + {errors.length > 0 && {errors.join(" ")}} {changed && errors.length === 0 && {reductions.length ? `Security-reducing: ${reductions.join("; ")}. Delayed ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto.` : "Tightens or keeps every control. Applies as soon as owners approve."}} - History - - {vault.policyHistory.length === 0 ? No policy versions recorded yet. : [...vault.policyHistory].reverse().map((h, i, arr) => v{h.version} · activated {new Date(Number(h.activatedAt) * 1000).toLocaleString()})} - + + toggle("history")}> + {vault.policyHistory.length === 0 ? No policy versions recorded yet. : [...vault.policyHistory].reverse().map((h) => v{h.version} · activated {new Date(Number(h.activatedAt) * 1000).toLocaleString()})} + )} {tab === "limits" && asset && text && ( diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx index 635c48b..4ae8de2 100644 --- a/mobile/src/screens/Security.tsx +++ b/mobile/src/screens/Security.tsx @@ -1,7 +1,7 @@ import { useNavigation } from "@react-navigation/native"; import { useState } from "react"; import { RefreshControl, Text, View } from "react-native"; -import { stringToHex } from "viem"; +import { isAddress, stringToHex } from "viem"; import { SkurVaultAbi } from "@web/abi/SkurVault"; import { NATIVE_ASSET } from "@web/config/chain"; import { fmtAmount, fmtDuration, short } from "@web/lib/format"; @@ -12,93 +12,88 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { Identicon } from "../components/Identicon"; -import { isAddress } from "viem"; -import { BackButton, Badge, Button, Card, CircleIcon, Field, Input, KV, ModeBadge, Notice, Row, Screen, SectionLabel, Tape, TopBar, TxStatus, s } from "../components/ui"; +import { BackButton, Badge, Button, Card, Expandable, Field, Input, KV, ModeBadge, Notice, Row, Screen, Tape, TopBar, TxStatus, s } from "../components/ui"; import { C, F } from "../theme"; +type Panel = "posture" | "mode" | "guardians" | "recovery" | "loss" | "history" | null; + +/** One card per concern, each opening on tap, so the screen reads as a short list rather than a wall. */ export function Security({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { const nav = useNavigation<{ goBack: () => void; canGoBack: () => boolean }>(); const roles = useMyRoles(vault); const invalidate = useInvalidateVault(vault.address); const tx = useTx(invalidate); + const [open, setOpen] = useState("posture"); const [reason, setReason] = useState(""); const [oldSigner, setOldSigner] = useState(""); const [newSigner, setNewSigner] = useState(""); - const isGuardian = Boolean(roles & ROLE_GUARDIAN); + const toggle = (p: Panel) => setOpen((o) => (o === p ? null : p)); const r32 = stringToHex(reason.slice(0, 31), { size: 32 }); const call = (fn: string, args: readonly unknown[]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); const posture = postureItems(vault); - const okCount = posture.filter((i) => i.ok === "ok").length; + const ok = posture.filter((i) => i.ok === "ok").length; + const weakest = posture.find((i) => i.ok === "bad") ?? posture.find((i) => i.ok === "warn"); const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; const loss = stable ? computeMaxLoss(vault.policy, stable.limits, stable.balance, vault.mode) : null; const canRaise = Boolean(roles & (ROLE_OWNER | ROLE_GUARDIAN)); + const isGuardian = Boolean(roles & ROLE_GUARDIAN); + return ( } top={<> nav.goBack()} /> : undefined} title="Security" right={} />{vault.mode !== Mode.NORMAL && }}> - - } title="Security posture" subtitle={`${okCount} of ${posture.length} controls confirmed`} last /> - - {posture.map((i) => ( - - {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} - {i.text} - - ))} - - + toggle("posture")}> + {posture.map((i) => ( + + {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} + {i.text} + + ))} + - Security mode - - Any owner or guardian can raise the mode at once. Lowering it needs owners and guardians together, and leaving Lockdown also waits out the policy-change delay. + toggle("mode")}> {vault.mode < Mode.ELEVATED && } {vault.mode < Mode.LOCKDOWN && } {vault.mode > Mode.NORMAL && } - {!canRaise && Only an owner or guardian signer can change the mode.} - - + {canRaise ? "Lowering the mode needs owners and guardians together." : "Only an owner or guardian signer can change the mode."} + - Guardians - - {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => } title={short(g.address, 6)} subtitle="freeze · veto · confirm · recover" trailing={Guardian} />)} - - - - - - + toggle("guardians")}> + {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => ( + {short(g.address, 6)}Guardian + ))} + + + - Recovery - - Replace a lost or compromised signer with a new address holding the same roles. It executes after {fmtDuration(vault.policy.recoveryDelay)}, any owner can cancel it, and the vault moves to Elevated when it completes. + toggle("recovery")}> + The new address takes the same roles. Any owner can cancel during the delay, and the vault moves to Elevated when it completes. setOldSigner(t.trim())} placeholder="0x…" mono /> setNewSigner(t.trim())} placeholder="0x…" mono /> {!isGuardian && Only a guardian signer can start a recovery.} - + {loss && stable && ( - <> - Maximum possible loss - - - - - A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. - - + toggle("loss")}> + + + + A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. + )} - Mode history - + toggle("history")}> {vault.modeHistory.length === 0 ? The mode has never changed. : [...vault.modeHistory].reverse().slice(0, 8).map((h, i, arr) => ( ))} - + + + ); diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx index 16beac6..8bf6dab 100644 --- a/mobile/src/screens/Welcome.tsx +++ b/mobile/src/screens/Welcome.tsx @@ -27,7 +27,7 @@ export function Welcome({ onDone }: { onDone: () => void }) { S Skur - MOBILE + {"[MOBILE]"} {PAGES.map((p, i) => ( From 23eb4236792b727caf886a3c326e0406fc0cd2dc Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 20:03:40 +0100 Subject: [PATCH 06/44] fix(mobile): stop the transaction list reloading on every background read Three things made the app look like it was reloading constantly. The pull-to-refresh spinner was wired to the query's isFetching, so it appeared on its own every 20 seconds and four more times after every write. It now tracks only a refresh the reader actually started. The vault object was rebuilt on every render and carried a timestamp that changed on every successful read, so every screen re-rendered whether or not anything had changed. It keeps its identity while the data is unchanged. A proposal count change starts a new activity query, and the queue swapped itself for a loader until that returned. The last good queue now stays on screen while the next read is in flight. Measured on the simulator: 70 seconds on the queue with no loader and no row churn, where the spinner previously appeared three times. --- mobile/src/hooks/useAlerts.ts | 2 +- mobile/src/hooks/useVault.ts | 37 ++++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/mobile/src/hooks/useAlerts.ts b/mobile/src/hooks/useAlerts.ts index c133dd1..a8e2a39 100644 --- a/mobile/src/hooks/useAlerts.ts +++ b/mobile/src/hooks/useAlerts.ts @@ -45,5 +45,5 @@ export function useAlerts(vault: VaultData | undefined) { await AsyncStorage.setItem(key, JSON.stringify([...seen.current!])); await Notifications.setBadgeCountAsync(due.length).catch(() => undefined); })(); - }, [vault, roles, signer, notifications]); + }, [vault, vault?.address, vault?.proposalCount, roles, signer?.address, notifications]); } diff --git a/mobile/src/hooks/useVault.ts b/mobile/src/hooks/useVault.ts index c6eb3bd..87965ab 100644 --- a/mobile/src/hooks/useVault.ts +++ b/mobile/src/hooks/useVault.ts @@ -1,4 +1,5 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { publicClient } from "../lib/client"; import { fetchActivity, fetchCore, type VaultActivity, type VaultData } from "@web/lib/vaultReads"; import { useStore } from "../state/store"; @@ -7,7 +8,11 @@ import { ROLE_GUARDIAN } from "@web/lib/types"; const EMPTY: VaultActivity = { proposals: [], recipients: [], logsFailed: false, policyHistory: [], modeHistory: [] }; const key = (a: `0x${string}` | null) => ["vault", a] as const; -/** Same two-query shape as the web app: core paints first, activity fills in. */ +/** + * Core paints first, activity fills in. Background refetches are deliberately invisible: only a pull + * to refresh shows the spinner, and the returned object keeps its identity while the data is unchanged, + * so a screen does not re-render (or flash its loader) every time the interval fires. + */ export function useVault(address: `0x${string}` | null) { const core = useQuery({ queryKey: [...key(address), "core"], queryFn: () => fetchCore(publicClient, address!), enabled: Boolean(address), refetchInterval: 20_000, staleTime: 10_000 }); const activity = useQuery({ @@ -18,16 +23,34 @@ export function useVault(address: `0x${string}` | null) { staleTime: 15_000, placeholderData: (prev) => prev, }); - const data: VaultData | undefined = core.data ? { ...core.data, ...(activity.data ?? EMPTY), activityLoading: !activity.data, fetchedAt: core.dataUpdatedAt } : undefined; - return { data, error: core.error ?? activity.error, isLoading: core.isLoading, refetch: () => { void core.refetch(); void activity.refetch(); }, refreshing: core.isFetching }; + + // The queue survives a proposal count change: the new query starts empty, and swapping the list for a + // loader for a few seconds is what reads as "reloading". + const lastActivity = useRef(null); + if (activity.data) lastActivity.current = activity.data; + const shownActivity = activity.data ?? lastActivity.current; + + const data: VaultData | undefined = useMemo( + () => (core.data ? { ...core.data, ...(shownActivity ?? EMPTY), activityLoading: !shownActivity, fetchedAt: Date.now() } : undefined), + // Identity changes only when the data itself does; React Query keeps the same reference otherwise. + [core.data, shownActivity], + ); + + const [manual, setManual] = useState(false); + useEffect(() => { if (manual && !core.isFetching && !activity.isFetching) setManual(false); }, [manual, core.isFetching, activity.isFetching]); + const refetch = useCallback(() => { setManual(true); void core.refetch(); void activity.refetch(); }, [core, activity]); + + return { data, error: core.error ?? activity.error, isLoading: core.isLoading && !core.data, refetch, refreshing: manual }; } export function useInvalidateVault(address: `0x${string}` | null) { const qc = useQueryClient(); - return () => { - void qc.invalidateQueries({ queryKey: key(address) }); - for (const ms of [6_000, 15_000, 30_000]) setTimeout(() => void qc.invalidateQueries({ queryKey: key(address) }), ms); - }; + return useCallback(() => { + const k = key(address); + void qc.invalidateQueries({ queryKey: k }); + // The devnet's replicas can lag a mined receipt by seconds; these catch up without a visible spinner. + for (const ms of [6_000, 15_000, 30_000]) setTimeout(() => void qc.invalidateQueries({ queryKey: k }), ms); + }, [qc, address]); } /** Roles the device signer holds in the open vault. */ From 86936826d815ac9c46326ff83772d51084e4e5e0 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 20:59:46 +0100 Subject: [PATCH 07/44] design(mobile): onboarding that shows the product instead of describing it Each page now carries one idea and one crafted illustration built from the app's own surfaces, rather than coloured blobs under three lines of copy. Page one is the vault card as the app draws it, balance and tokens, tilted with its assets orbiting. Page two is the same payment at three sizes with what the vault asks of each: one approval now, two and a day, two and a guardian. Page three is the notification that reaches you over the confirmation it opens, with the policy check answered. Headlines are two lines, subtitles one, and the wordmark, dots and button keep the reference rhythm. --- mobile/src/screens/Welcome.tsx | 165 +++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 70 deletions(-) diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx index 8bf6dab..8603ebc 100644 --- a/mobile/src/screens/Welcome.tsx +++ b/mobile/src/screens/Welcome.tsx @@ -6,43 +6,48 @@ import { Icon } from "../components/ui"; import { C, F } from "../theme"; const W = Dimensions.get("window").width; -/** Light tokens for the first-launch screens, matching the web's marketing pages. */ -const L = { bg: "#ffffff", text: "#212529", text2: "#6c757d", card: "#f1f3f5", card2: "#e9ecef", border: "#dee2e6" }; +const ART = 310; +/** Light palette for the first-launch screens, matching the web's marketing pages. */ +const L = { bg: "#ffffff", ink: "#212529", ink2: "#6c757d", line: "#e9ecef", wash: "#f1f3f5" }; +const shadow = { shadowColor: "#0b1220", shadowOpacity: 0.1, shadowRadius: 24, shadowOffset: { width: 0, height: 12 }, elevation: 6 } as const; const PAGES = [ - { title: "Track your\nvaults. Anywhere.", sub: "Easily track balances and get real-time updates on vault activity, anytime.", art: }, - { title: "Sign transactions\non the go", sub: "Enjoy peace of mind with transaction checks, ensuring secure signing.", art: }, - { title: "Get\npersonalized\nupdates", sub: "Stay informed with notifications tailored to your vaults.", art: }, + { title: "Track your treasury.\nAnywhere.", sub: "Balances and activity, read live from the chain.", art: }, + { title: "Every payment,\nscored first.", sub: "Approvals, delay and veto, set by the vault.", art: }, + { title: "Sign the moment\nyou're needed.", sub: "Face ID to sign. The vault checks the policy.", art: }, ]; -/** First launch, after Safe{Mobile}: wordmark, illustration, headline, dots, one black button. */ +/** First launch: one idea per page, a real product surface as its illustration, and a single button. */ export function Welcome({ onDone }: { onDone: () => void }) { const insets = useSafeAreaInsets(); const [page, setPage] = useState(0); const ref = useRef(null); const onScroll = (e: NativeSyntheticEvent) => setPage(Math.round(e.nativeEvent.contentOffset.x / W)); return ( - + - - S - Skur - {"[MOBILE]"} + + S + Skur + {"[MOBILE]"} - + + {PAGES.map((p, i) => ( - - {p.art} - {p.title} - {p.sub} + + {p.art} + {p.title} + {p.sub} ))} - - {PAGES.map((_, i) => )} + + + + {PAGES.map((_, i) => )} - - ({ height: 56, borderRadius: 14, backgroundColor: L.text, alignItems: "center", justifyContent: "center", opacity: pressed ? 0.85 : 1 })}> + + ({ height: 56, borderRadius: 16, backgroundColor: L.ink, alignItems: "center", justifyContent: "center", opacity: pressed ? 0.85 : 1 })}> Get started @@ -50,77 +55,97 @@ export function Welcome({ onDone }: { onDone: () => void }) { ); } -const A1 = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; -const A2 = "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0"; -const A3 = "0xCec10C48B8d37b6A083000173e3415Cc6f86974F"; - -function Blur({ x, y, size, color }: { x: number; y: number; size: number; color: string }) { - return ; -} +const VAULT = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; +const NEW_ADDR = "0x7c4f9A2b61e3d0c8F5a4B2e1D6c9A3f8E0b71e42"; -/** Floating token and vault icons, as on Safe's first page; the Skur tile takes the place of the green Safe tile. */ -function ArtTrack() { +function Coin({ label, size, bg, fg = "#fff", style }: { label: string; size: number; bg: string; fg?: string; style?: object }) { return ( - - - - - - A - K - S - - S - + + {label} ); } -/** Phone mockup with the signer picker and a toast, as on Safe's second page. */ -function ArtSign() { +/** Page 1: the vault as the app actually shows it, with its assets orbiting. */ +function ArtVault() { return ( - - - - Select signer - - My signer + + + + + + + + + + Treasury vault + Normal - {[A3, A1].map((a, i) => ( - - My signer #{i + 2} + 250,000 sUSD + + {[["S", "Skur Test USD", "250,000", C.accent, C.onAccent], ["K", "KASH", "3", "#4c6ef5", "#fff"]].map(([l, name, amt, bg, fg]) => ( + + {l} + {name} + {amt} ))} - - Policy check passed - ); } -/** Stacked notification cards, as on Safe's third page. */ -function ArtUpdates() { - const cards: Array<{ text: string; when: string; tone: string; icon: "info" | "check" | "alert-circle"; strong?: string; w: number; dy: number; dim: number }> = [ - { strong: "A transaction", text: " requires your confirmation", when: "about 1 hour ago", tone: "#4dabf7", icon: "info", w: 1, dy: 0, dim: 1 }, - { text: "", when: "about 2 hours ago", tone: "#40c057", icon: "check", w: 0.9, dy: 92, dim: 0.75 }, - { text: "", when: "Just now", tone: "#fa5252", icon: "alert-circle", w: 0.82, dy: 176, dim: 0.5 }, +/** Page 2: the same payment at three sizes, and what the vault asks of each. */ +function ArtTiers() { + const rows: Array<{ amt: string; req: string; tier: string; bg: string; fg: string; dx: number }> = [ + { amt: "1,000 sUSD", req: "1 approval · now", tier: "Low", bg: "#e6f6ec", fg: "#1b7f4a", dx: -14 }, + { amt: "12,000 sUSD", req: "2 approvals · 1 day", tier: "High", bg: "#fff3d6", fg: "#a86a00", dx: 10 }, + { amt: "60,000 sUSD", req: "2 + a guardian", tier: "Critical", bg: "#ffe3e3", fg: "#b42318", dx: -6 }, ]; return ( - - - - - {cards.map((c, i) => ( - - + + {rows.map((r) => ( + + + + - {c.strong ? {c.strong}{c.text} : } - {c.when} + {r.amt} + {r.req} - + {r.tier} ))} ); } + +/** Page 3: the alert that reaches you, over the confirmation it opens. */ +function ArtSign() { + return ( + + + + + Confirm transaction + −12,000 sUSD + to 0x7c4f…41e2 + + + + + + + A transaction needs you + just now + + + + + + + Policy check passed + + + ); +} From e4b1045a39face9dba079ac895d78e9a3ea7f3a0 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 21:45:23 +0100 Subject: [PATCH 08/44] design(mobile): one switchable ground, and screens that show values instead of paragraphs The onboarding stood on white while the app stood on charcoal, and every screen carried explanatory prose a wallet has no business showing. Both are fixed together. Light and dark are now two palettes behind one set of tokens. Every component and screen reads its colours through useTheme and its styles through useStyles, so a single choice reaches the splash, the onboarding, the tab bar, the sheets and the navigator chrome. Settings gains Light, Dark and System, remembered across launches and following the phone by default. About 3,500 characters of explanation came out of the screens. Transactions, Members, Address book, Policy, Simulator, Updates, Signers, Security and Create vault lose their paragraphs; the hints that remain are a line each. The vault error screen shows one sentence rather than a viem stack trace, and role badges collapse to All roles instead of truncating. Tab deep links no longer warn when no vault is open. --- mobile/App.tsx | 38 +++++++-- mobile/src/components/Identicon.tsx | 4 +- mobile/src/components/VaultSheet.tsx | 6 +- mobile/src/components/ui.tsx | 122 ++++++++++++++++----------- mobile/src/screens/AddressBook.tsx | 11 +-- mobile/src/screens/CreateVault.tsx | 10 +-- mobile/src/screens/Home.tsx | 11 ++- mobile/src/screens/Members.tsx | 10 +-- mobile/src/screens/Notifications.tsx | 9 +- mobile/src/screens/Onboard.tsx | 10 ++- mobile/src/screens/Policy.tsx | 14 +-- mobile/src/screens/Receive.tsx | 8 +- mobile/src/screens/Scan.tsx | 6 +- mobile/src/screens/Security.tsx | 12 +-- mobile/src/screens/Send.tsx | 10 ++- mobile/src/screens/Settings.tsx | 31 ++++--- mobile/src/screens/Signers.tsx | 16 ++-- mobile/src/screens/Simulator.tsx | 8 +- mobile/src/screens/Transactions.tsx | 7 +- mobile/src/screens/TxDetail.tsx | 6 +- mobile/src/screens/Welcome.tsx | 14 ++- mobile/src/state/theme.tsx | 31 +++++++ mobile/src/theme.ts | 48 ++++++----- 23 files changed, 282 insertions(+), 160 deletions(-) create mode 100644 mobile/src/state/theme.tsx diff --git a/mobile/App.tsx b/mobile/App.tsx index 4b4f165..39e3c85 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -1,8 +1,9 @@ import { DMMono_400Regular, DMMono_500Medium } from "@expo-google-fonts/dm-mono"; +import { useTheme } from "./src/state/theme"; import { DMSans_400Regular, DMSans_500Medium, DMSans_700Bold } from "@expo-google-fonts/dm-sans"; import { SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold } from "@expo-google-fonts/space-grotesk"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; -import { createNavigationContainerRef, DarkTheme, NavigationContainer, StackActions, type NavigatorScreenParams } from "@react-navigation/native"; +import { createNavigationContainerRef, DarkTheme, DefaultTheme, NavigationContainer, StackActions, type NavigatorScreenParams } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { useFonts } from "expo-font"; @@ -15,6 +16,7 @@ import { useState } from "react"; import { ActivityIndicator, Text, View } from "react-native"; import { Feather } from "@expo/vector-icons"; import { SafeAreaProvider } from "react-native-safe-area-context"; +import { describeError } from "@web/lib/errors"; import { Status } from "@web/lib/types"; import { Button, Notice, Screen, TopBar } from "./src/components/ui"; import { useVault } from "./src/hooks/useVault"; @@ -38,16 +40,18 @@ import { Settings } from "./src/screens/Settings"; import { Transactions } from "./src/screens/Transactions"; import { TxDetail } from "./src/screens/TxDetail"; import { StoreProvider, useStore } from "./src/state/store"; -import { C, F } from "./src/theme"; +import { ThemeProvider, useScheme } from "./src/state/theme"; +import { F } from "./src/theme"; const queryClient = new QueryClient(); const Tabs = createBottomTabNavigator(); const Stack = createNativeStackNavigator(); -const navTheme = { ...DarkTheme, colors: { ...DarkTheme.colors, background: C.canvas, card: C.card, border: C.border, primary: C.accent, text: C.text } }; + function VaultApp() { + const C = useTheme(); const { vaultAddress, setVaultAddress } = useStore(); const { data: vault, error, isLoading, refetch, refreshing } = useVault(vaultAddress); useAlerts(vault); @@ -62,7 +66,7 @@ function VaultApp() { ); if (error && !vault) return ( } />}> - Could not read the vault. {(error as Error).message} + {describeError(error).split("\n")[0]} @@ -109,9 +113,13 @@ const ROUTES: Record = { */ function useDeepLinks(ready: boolean) { const { setVaultAddress, importSigner, setOnboarded } = useStore(); + const { setScheme } = useScheme(); const queued = useRef(null); const go = useCallback((target: keyof RootParams | [keyof RootParams, string], params?: object) => { if (!navigationRef.isReady()) return false; + const names = navigationRef.getRootState()?.routeNames ?? []; + const wanted = Array.isArray(target) ? target[0] : target; + if (!names.includes(wanted as string)) return false; // eslint-disable-next-line @typescript-eslint/no-explicit-any const nav = navigationRef.navigate as unknown as (name: string, params?: object) => void; // Going to a tab means leaving whatever was pushed on top of it. @@ -128,10 +136,11 @@ function useDeepLinks(ready: boolean) { if (head === "vault" && rest[0] && isAddress(rest[0])) { void setVaultAddress(rest[0] as `0x${string}`); go(["Main", "Home"]); return; } if (__DEV__ && head === "dev" && rest[0] === "signer" && rest[1]) { void importSigner(rest[1]).catch(() => undefined); return; } if (__DEV__ && head === "dev" && rest[0] === "onboarding") { void setOnboarded(false); void setVaultAddress(null); return; } + if (__DEV__ && head === "dev" && rest[0] === "theme" && rest[1]) { setScheme(rest[1] as "light" | "dark" | "system"); return; } if (head === "tx" && rest[0]) { if (!go("TxDetail", { id: rest[0] })) queued.current = url; return; } const route = ROUTES[head ?? ""]; if (route && !go(route)) queued.current = url; - }, [setVaultAddress, importSigner, setOnboarded, go]); + }, [setVaultAddress, importSigner, setOnboarded, setScheme, go]); useEffect(() => { void Linking.getInitialURL().then(handle); const sub = Linking.addEventListener("url", (e) => handle(e.url)); @@ -158,6 +167,18 @@ function Gate() { type TabParams = { Home: undefined; Transactions: undefined; Settings: undefined }; type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined; Security: undefined; AddressBook: undefined; Members: undefined; Policy: undefined; Simulator: undefined; CreateVault: undefined; Signers: undefined; Notifications: undefined; Scan: undefined }; +function Root() { + const { C, dark } = useScheme(); + const base = dark ? DarkTheme : DefaultTheme; + const navTheme = { ...base, colors: { ...base.colors, background: C.canvas, card: C.card, border: C.border, primary: C.accent, text: C.text } }; + return ( + + + + + ); +} + export default function App() { const [fontsLoaded] = useFonts({ SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold, DMSans_400Regular, DMSans_500Medium, DMSans_700Bold, DMMono_400Regular, DMMono_500Medium }); if (!fontsLoaded) return ; @@ -165,10 +186,9 @@ export default function App() { - - - - + + + diff --git a/mobile/src/components/Identicon.tsx b/mobile/src/components/Identicon.tsx index b05efc6..962dfce 100644 --- a/mobile/src/components/Identicon.tsx +++ b/mobile/src/components/Identicon.tsx @@ -1,10 +1,12 @@ import { useMemo } from "react"; +import { useTheme } from "../state/theme"; import { Text, View } from "react-native"; import { keccak256, stringToHex } from "viem"; -import { C, F } from "../theme"; +import { F } from "../theme"; /** Same deterministic blocky avatar as the web interface (web/src/components/Identicon.tsx), drawn with views. */ export function Identicon({ address, size = 40, badge }: { address: string; size?: number; badge?: string }) { + const C = useTheme(); const { cells, fg, bg } = useMemo(() => { const hash = keccak256(stringToHex(address.toLowerCase())).slice(2); const hue = parseInt(hash.slice(0, 4), 16) % 360; diff --git a/mobile/src/components/VaultSheet.tsx b/mobile/src/components/VaultSheet.tsx index f98fee2..959dc0f 100644 --- a/mobile/src/components/VaultSheet.tsx +++ b/mobile/src/components/VaultSheet.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; +import { useTheme } from "../state/theme"; import { Text, View } from "react-native"; import { isAddress } from "viem"; import { SkurFactoryAbi } from "@web/abi/SkurFactory"; @@ -7,11 +8,12 @@ import { short } from "@web/lib/format"; import { publicClient } from "../lib/client"; import { useStore } from "../state/store"; import { Identicon } from "./Identicon"; -import { Button, CircleIcon, Icon, Input, Logo, Row, Sheet, s } from "./ui"; -import { C, F } from "../theme"; +import { Button, CircleIcon, Icon, Input, Logo, Row, Sheet, useStyles } from "./ui"; +import { F } from "../theme"; /** Safe's "My accounts" switcher: the open vault, vaults the device signer belongs to, and a way to add one by address. */ export function VaultSheet({ open, onClose }: { open: boolean; onClose: () => void }) { + const C = useTheme(); const s = useStyles(); const { vaultAddress, setVaultAddress, labels, signer } = useStore(); const [mine, setMine] = useState<`0x${string}`[]>([]); const [adding, setAdding] = useState(false); diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx index d990432..16d98b4 100644 --- a/mobile/src/components/ui.tsx +++ b/mobile/src/components/ui.tsx @@ -6,62 +6,69 @@ import { useSafeAreaInsets } from "react-native-safe-area-context"; import { short } from "@web/lib/format"; import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; import type { TxState } from "../hooks/useTx"; -import { C, F, R } from "../theme"; +import { useTheme } from "../state/theme"; +import { F, R, type Palette } from "../theme"; export type IconName = ComponentProps["name"]; -export const Icon = ({ name, size = 18, color = C.text }: { name: IconName; size?: number; color?: string }) => ; +export function Icon({ name, size = 18, color }: { name: IconName; size?: number; color?: string }) { + const C = useTheme(); + return ; +} -/** Screen shell: optional top bar, scrolling body, optional sticky footer above the home indicator. */ export function Screen({ children, top, footer, refreshControl, padded = true }: { children: ReactNode; top?: ReactNode; footer?: ReactNode; refreshControl?: ReactNode; padded?: boolean }) { - const insets = useSafeAreaInsets(); + const C = useTheme(); const s = useStyles(); const insets = useSafeAreaInsets(); return ( {top ? {top} : null} - {children} + {children} {footer ? {footer} : null} ); } export function TopBar({ left, center, right, title }: { left?: ReactNode; center?: ReactNode; right?: ReactNode; title?: string }) { + const s = useStyles(); return ( - {left}{title ? {title} : null} + {left}{title ? {title} : null} {center ? {center} : null} {right} ); } -export function IconButton({ name, onPress, dot, tone = "dark" }: { name: IconName; onPress?: () => void; dot?: boolean; tone?: "dark" | "accent" }) { +export function IconButton({ name, onPress, dot, tone = "dark", label }: { name: IconName; onPress?: () => void; dot?: boolean; tone?: "dark" | "accent"; label?: string }) { + const C = useTheme(); const s = useStyles(); return ( - [s.iconBtn, tone === "accent" && { backgroundColor: C.accent }, pressed && { opacity: 0.7 }]}> + [s.iconBtn, tone === "accent" && { backgroundColor: C.accent }, pressed && { opacity: 0.6 }]}> {dot ? : null} ); } -export function BackButton({ onPress }: { onPress: () => void }) { return ; } +export function BackButton({ onPress }: { onPress: () => void }) { return ; } -/** The web logo: yellow square with an S, then the wordmark. */ +/** The web logo: a yellow tile with an S, then the wordmark. */ export function Logo({ size = 28, wordmark = true }: { size?: number; wordmark?: boolean }) { + const C = useTheme(); return ( - - S + + S {wordmark ? Skur : null} ); } -/** A card that opens on tap: the header carries the summary, so a long screen reads as a short list. */ -export function Expandable({ title, summary, icon, tone = "dark", children, open, onToggle }: { title: string; summary?: string; icon?: IconName; tone?: "dark" | "accent" | "success" | "error" | "warn"; children: ReactNode; open: boolean; onToggle: () => void }) { +/** A card that opens on tap: the header carries the value, so a long screen reads as a short list. */ +export function Expandable({ title, summary, icon, tone = "dark", children, open, onToggle }: { title: string; summary?: string; icon?: IconName; tone?: Tone; children: ReactNode; open: boolean; onToggle: () => void }) { + const C = useTheme(); const s = useStyles(); return ( - [{ flexDirection: "row", alignItems: "center", gap: 12, padding: 16 }, pressed && { opacity: 0.7 }]}> - {icon ? : null} + [{ flexDirection: "row", alignItems: "center", gap: 12, padding: 16 }, pressed && { opacity: 0.6 }]}> + {icon ? : null} {title} {summary ? {summary} : null} @@ -74,12 +81,14 @@ export function Expandable({ title, summary, icon, tone = "dark", children, open } export function Card({ children, style, flush = false }: { children: ReactNode; style?: StyleProp; flush?: boolean }) { + const s = useStyles(); return {children}; } -export function SectionLabel({ children }: { children: ReactNode }) { return {children}; } +export function SectionLabel({ children }: { children: ReactNode }) { const s = useStyles(); return {children}; } -/** Safe-style list row: leading icon or avatar, title, subtitle, trailing content, optional chevron. */ +/** The list row every screen is built from: leading mark, title, value, chevron. */ export function Row({ leading, title, subtitle, trailing, onPress, chevron = false, last = false }: { leading?: ReactNode; title: ReactNode; subtitle?: ReactNode; trailing?: ReactNode; onPress?: () => void; chevron?: boolean; last?: boolean }) { + const C = useTheme(); const s = useStyles(); const body = ( {leading ? {leading} : null} @@ -91,20 +100,30 @@ export function Row({ leading, title, subtitle, trailing, onPress, chevron = fal {chevron ? : null} ); - return onPress ? pressed && { opacity: 0.7 }}>{body} : body; + return onPress ? pressed && { opacity: 0.6 }}>{body} : body; +} + +type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent" | "dark" | "success" | "error"; +function tones(C: Palette): Record { + return { + ok: { bg: C.successBg, fg: C.success }, success: { bg: C.successBg, fg: C.success }, + warn: { bg: C.warningBg, fg: C.warning }, bad: { bg: C.errorBg, fg: C.error }, error: { bg: C.errorBg, fg: C.error }, + info: { bg: C.infoBg, fg: C.info }, neutral: { bg: C.card2, fg: C.text2 }, dark: { bg: C.card2, fg: C.text }, + accent: { bg: C.accent, fg: C.onAccent }, + }; } -export function CircleIcon({ name, size = 40, tone = "dark", text }: { name?: IconName; size?: number; tone?: "dark" | "accent" | "success" | "error" | "warn"; text?: string }) { - const bg = tone === "accent" ? C.accent : tone === "success" ? C.successBg : tone === "error" ? C.errorBg : tone === "warn" ? C.warningBg : C.card2; - const fg = tone === "accent" ? C.onAccent : tone === "success" ? C.success : tone === "error" ? C.error : tone === "warn" ? C.warning : C.text; +export function CircleIcon({ name, size = 40, tone = "dark", text }: { name?: IconName; size?: number; tone?: Tone; text?: string }) { + const C = useTheme(); const t = tones(C)[tone]; return ( - - {text ? {text} : name ? : null} + + {text ? {text} : name ? : null} ); } export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNode; mono?: boolean; last?: boolean }) { + const s = useStyles(); return ( {k} @@ -113,13 +132,8 @@ export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNo ); } -type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent"; -const TONES: Record = { - ok: { bg: C.successBg, fg: C.success }, warn: { bg: C.warningBg, fg: C.warning }, bad: { bg: C.errorBg, fg: C.error }, - info: { bg: C.infoBg, fg: C.info }, neutral: { bg: C.card2, fg: C.text2 }, accent: { bg: C.accent, fg: C.onAccent }, -}; export function Badge({ tone = "neutral", children, icon }: { tone?: Tone; children: ReactNode; icon?: IconName }) { - const t = TONES[tone]; + const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; return {icon ? : null}{children}; } export const TierBadge = ({ tier }: { tier: Tier }) => {TIER_LABEL[tier]}; @@ -128,6 +142,7 @@ export const StatusBadge = ({ status }: { status: Status }) => {TRUST_LABEL[trust]}; export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md" }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm" }) { + const C = useTheme(); const s = useStyles(); const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.card2 : "transparent"; const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; return ( @@ -137,8 +152,9 @@ export function Button({ children, onPress, kind = "primary", disabled, loading, ); } -/** Safe's sticky "Sign with ‹signer›" bar, used for the primary action of a screen. */ +/** The sticky primary action: what you are about to sign, and with which key. */ export function SignBar({ label, signerAddress, onPress, disabled, loading, hint }: { label: string; signerAddress?: string | null; onPress?: () => void; disabled?: boolean; loading?: boolean; hint?: string }) { + const C = useTheme(); const s = useStyles(); return ( {hint ? {hint} : null} @@ -153,6 +169,7 @@ export function SignBar({ label, signerAddress, onPress, disabled, loading, hint } export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { + const s = useStyles(); return ( {label} @@ -161,25 +178,28 @@ export function Field({ label, hint, children }: { label: string; hint?: string; ); } + export const Input = forwardRef(function Input(props, ref) { + const C = useTheme(); const s = useStyles(); return ; }); -/** Underlined text tabs, as on Safe's Tokens / NFTs switch. */ export function Tabs({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { + const C = useTheme(); const s = useStyles(); return ( {options.map(([v, label]) => ( - onChange(v)} style={[s.tab, value === v && s.tabOn]}>{label} + onChange(v)} style={[s.tab, value === v && { borderBottomColor: C.accent }]}>{label} ))} ); } export function Address({ value, full = false, style }: { value: string; full?: boolean; style?: object }) { + const C = useTheme(); const s = useStyles(); const [copied, setCopied] = useState(false); return ( - { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8} style={{ flexDirection: "row", alignItems: "center", gap: 6 }}> + { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8} style={{ flexDirection: "row", alignItems: "center", gap: 6 }}> {full ? value : short(value)} @@ -187,24 +207,26 @@ export function Address({ value, full = false, style }: { value: string; full?: } export function Notice({ tone = "info", children }: { tone?: Tone; children: ReactNode }) { - const t = TONES[tone]; + const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; return {children}; } export function TxStatus({ state }: { state: TxState }) { if (state.phase === "idle") return null; if (state.phase === "error") return {state.message}; - if (state.phase === "done") return Confirmed onchain · {short(state.hash, 6)}; - const msg = state.phase === "auth" ? "Waiting for authentication…" : state.phase === "simulating" ? "Checking the transaction against the vault's policy…" : "Waiting for the block…"; + if (state.phase === "done") return Confirmed · {short(state.hash, 6)}; + const msg = state.phase === "auth" ? "Waiting for Face ID…" : state.phase === "simulating" ? "Checking against the policy…" : "Waiting for the block…"; return {msg}; } export function Empty({ icon = "inbox", children }: { icon?: IconName; children: ReactNode }) { - return {children}; + const C = useTheme(); + return {children}; } -/** Caution-tape band: the brand's signature. */ +/** Caution tape: the brand's mark, used only where the vault is not in Normal mode. */ export function Tape({ height = 8 }: { height?: number }) { + const C = useTheme(); return ( {Array.from({ length: 34 }).map((_, i) => )} @@ -212,9 +234,8 @@ export function Tape({ height = 8 }: { height?: number }) { ); } -/** Bottom sheet like Safe's account and network switchers. */ export function Sheet({ open, onClose, title, children, action }: { open: boolean; onClose: () => void; title: string; children: ReactNode; action?: ReactNode }) { - const insets = useSafeAreaInsets(); + const s = useStyles(); const insets = useSafeAreaInsets(); return ( @@ -230,7 +251,7 @@ export function Sheet({ open, onClose, title, children, action }: { open: boolea ); } -export const s = StyleSheet.create({ +const makeStyles = (C: Palette) => StyleSheet.create({ screen: { flex: 1, backgroundColor: C.canvas }, topbar: { height: 52, paddingHorizontal: 16, flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, topTitle: { fontFamily: F.display, fontSize: 22, color: C.text, letterSpacing: -0.3 }, @@ -238,8 +259,8 @@ export const s = StyleSheet.create({ dot: { position: "absolute", top: 8, right: 8, width: 8, height: 8, borderRadius: 4, backgroundColor: C.accent, borderWidth: 1.5, borderColor: C.canvas }, footer: { position: "absolute", left: 0, right: 0, bottom: 0, padding: 16, backgroundColor: C.canvas, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: C.border }, card: { backgroundColor: C.card, borderRadius: R.lg, padding: 16, marginBottom: 12 }, - sectionLabel: { fontFamily: F.mono, fontSize: 11, letterSpacing: 1.2, textTransform: "uppercase", color: C.text3, marginBottom: 8, marginTop: 6 }, - row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 12, paddingHorizontal: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + sectionLabel: { fontFamily: F.mono, fontSize: 11, letterSpacing: 1.2, textTransform: "uppercase", color: C.text3, marginBottom: 8, marginTop: 8 }, + row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 13, paddingHorizontal: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, rowTitle: { fontFamily: F.bodyBold, fontSize: 15, color: C.text }, rowSub: { fontFamily: F.body, fontSize: 13, color: C.text2 }, kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 11, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, @@ -251,19 +272,26 @@ export const s = StyleSheet.create({ btnText: { fontFamily: F.bodyBold, fontSize: 15 }, signbar: { height: 56, borderRadius: R.lg, backgroundColor: C.accent, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 18 }, signbarText: { fontFamily: F.bodyBold, fontSize: 16, color: C.onAccent, flex: 1 }, - signerChip: { backgroundColor: "rgba(33,37,41,0.15)", borderRadius: R.pill, paddingHorizontal: 10, height: 28, justifyContent: "center" }, + signerChip: { backgroundColor: "rgba(16,20,24,0.12)", borderRadius: R.pill, paddingHorizontal: 10, height: 28, justifyContent: "center" }, signerChipText: { fontFamily: F.monoMedium, fontSize: 12, color: C.onAccent }, label: { fontFamily: F.bodyMedium, fontSize: 13, color: C.text2, marginBottom: 6 }, hint: { fontFamily: F.body, fontSize: 12, color: C.text3, marginTop: 6, lineHeight: 16 }, input: { backgroundColor: C.card2, borderRadius: R.md, paddingHorizontal: 14, height: 48, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, tabs: { flexDirection: "row", borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border, marginBottom: 4 }, tab: { paddingVertical: 10, paddingHorizontal: 4, marginRight: 22, borderBottomWidth: 2, borderBottomColor: "transparent" }, - tabOn: { borderBottomColor: C.accent }, tabText: { fontFamily: F.bodyBold, fontSize: 15, color: C.text3 }, addr: { fontFamily: F.mono, fontSize: 13, color: C.text2 }, notice: { padding: 12, borderRadius: R.md, marginTop: 10 }, - sheetBackdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.55)" }, + sheetBackdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)" }, sheet: { backgroundColor: C.card, borderTopLeftRadius: 22, borderTopRightRadius: 22, paddingHorizontal: 16, paddingTop: 8 }, grabber: { width: 40, height: 4, borderRadius: 2, backgroundColor: C.border, alignSelf: "center", marginBottom: 14 }, sheetTitle: { fontFamily: F.display, fontSize: 18, color: C.text }, }); + +const cache = new Map>(); +/** Styles for the ground currently in use, built once per palette. */ +export function useStyles() { + const C = useTheme(); + if (!cache.has(C.canvas)) cache.set(C.canvas, makeStyles(C)); + return cache.get(C.canvas)!; +} diff --git a/mobile/src/screens/AddressBook.tsx b/mobile/src/screens/AddressBook.tsx index 949185f..8c4d39a 100644 --- a/mobile/src/screens/AddressBook.tsx +++ b/mobile/src/screens/AddressBook.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { isAddress } from "viem"; @@ -10,11 +11,12 @@ import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { scanBus } from "../lib/scanBus"; import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, Empty, Field, IconButton, Input, Notice, Row, Screen, Sheet, TopBar, TrustBadge, TxStatus, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Address, BackButton, Badge, Button, Card, Empty, Field, IconButton, Input, Notice, Row, Screen, Sheet, TopBar, TrustBadge, TxStatus, useStyles } from "../components/ui"; +import { F } from "../theme"; /** Recipients are security objects: register early, verify, restrict or block. */ export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); const roles = useMyRoles(vault); const invalidate = useInvalidateVault(vault.address); @@ -31,7 +33,6 @@ export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; } top={ nav.goBack()} />} center={Address book} right={ { setTarget(""); setDialog("register"); }} />} />}> - A new recipient waits {fmtDuration(vault.policy.recipientActivationDelay)} before normal policy applies to it. Registering a supplier early means its first payment later does not wait. {vault.activityLoading ? Reading recipients from the chain… : vault.recipients.length === 0 ? No recipients yet. Register one to start its activation clock. : ( {vault.recipients.map((r, i) => { @@ -47,7 +48,7 @@ export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; setDialog(null)} title="New entry"> - + setTarget(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> {!canRegister && Only an owner or approver signer can register a recipient.} @@ -56,7 +57,7 @@ export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; setDialog(null)} title="Propose a trust change"> setTarget(t.trim())} placeholder="0x…" mono /> - + {[Trust.VERIFIED, Trust.TRUSTED, Trust.RESTRICTED, Trust.BLOCKED].map((t) => ( setTrust(t)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: trust === t ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{TRUST_LABEL[t]} diff --git a/mobile/src/screens/CreateVault.tsx b/mobile/src/screens/CreateVault.tsx index 6d171db..4e9951f 100644 --- a/mobile/src/screens/CreateVault.tsx +++ b/mobile/src/screens/CreateVault.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useMemo, useRef, useState } from "react"; import { Pressable, Text, View, type TextInput } from "react-native"; import { isAddress, keccak256, stringToHex } from "viem"; @@ -13,14 +14,15 @@ import { scanBus } from "../lib/scanBus"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { BackButton, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Screen, SectionLabel, SignBar, TopBar, TxStatus, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Screen, SectionLabel, SignBar, TopBar, TxStatus, useStyles } from "../components/ui"; +import { F } from "../theme"; type Row = { address: string; roles: number }; const ROLE_CHIPS: Array<[number, string]> = [[ROLE_OWNER, "Owner"], [ROLE_APPROVER, "Approver"], [ROLE_EXECUTOR, "Executor"], [ROLE_GUARDIAN, "Guardian"]]; /** Create a vault from the phone: name, template, members, review, one signature. */ export function CreateVault() { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); const { signer, setVaultAddress, setLabel } = useStore(); const [name, setName] = useState(""); @@ -55,14 +57,13 @@ export function CreateVault() { 1 · Name and template - + {TEMPLATES.map((t) => setTemplateId(t.id)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: templateId === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name})} {template.tagline} Needs {template.minSigners}+ signers and {template.minGuardians}+ guardian{template.minGuardians === 1 ? "" : "s"}. 2 · Signers and guardians - Owners govern, approvers confirm payments, executors execute. Guardians can only freeze, veto and recover; the contract will not let them hold a treasury role. {members.map((m, i) => ( @@ -88,7 +89,6 @@ export function CreateVault() { {errors.length > 0 && {errors.join(" ")}} - The vault is a minimal proxy over the verified implementation. The factory that creates it keeps no authority over it; only the members listed above can act. ); diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index 428db5c..a1fb1e0 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -11,11 +11,13 @@ import { scanBus } from "../lib/scanBus"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; import { VaultSheet } from "../components/VaultSheet"; -import { Address, CircleIcon, Icon, IconButton, Row, Screen, Tape, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Address, CircleIcon, Icon, IconButton, Row, Screen, Tape, TopBar, useStyles } from "../components/ui"; +import { F, type Palette } from "../theme"; +import { useTheme } from "../state/theme"; /** Home is the vault at a glance: what it holds, what is waiting, and the two things you do most. */ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const C = useTheme(); const s = useStyles(); const h = styles(C); const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const { labels, signer, setVaultAddress } = useStore(); const roles = useMyRoles(vault); @@ -91,6 +93,7 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch } function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arrow-up-right" | "arrow-down-left"; label: string; onPress: () => void; tone?: "dark" | "accent"; disabled?: boolean }) { + const C = useTheme(); const h = styles(C); return ( [h.action, tone === "accent" && { backgroundColor: C.accent }, { opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }]}> @@ -99,9 +102,9 @@ function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arro ); } -const h = { +const styles = (C: Palette) => ({ banner: { flexDirection: "row" as const, alignItems: "center" as const, gap: 10, backgroundColor: C.accentBg, borderRadius: 14, paddingHorizontal: 14, height: 48, marginBottom: 14 }, count: { minWidth: 22, height: 22, borderRadius: 11, backgroundColor: C.accent, alignItems: "center" as const, justifyContent: "center" as const, paddingHorizontal: 6 }, balance: { fontFamily: F.display, fontSize: 44, color: C.text, letterSpacing: -1.4 }, action: { flex: 1, height: 48, borderRadius: 14, backgroundColor: C.card, flexDirection: "row" as const, alignItems: "center" as const, justifyContent: "center" as const, gap: 8 }, -}; +}); diff --git a/mobile/src/screens/Members.tsx b/mobile/src/screens/Members.tsx index 5bc2ee8..9b15d30 100644 --- a/mobile/src/screens/Members.tsx +++ b/mobile/src/screens/Members.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { isAddress } from "viem"; @@ -10,13 +11,14 @@ import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; import { scanBus } from "../lib/scanBus"; -import { Address, BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Row, Screen, SectionLabel, Sheet, TopBar, TxStatus, s } from "../components/ui"; +import { Address, BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Row, Screen, SectionLabel, Sheet, TopBar, TxStatus, useStyles } from "../components/ui"; import { Identicon } from "../components/Identicon"; -import { C, F } from "../theme"; +import { F } from "../theme"; const ROLE_BITS: Array<[number, string, string]> = [[ROLE_OWNER, "Owner", "governs"], [ROLE_APPROVER, "Approver", "confirms payments"], [ROLE_EXECUTOR, "Executor", "executes"], [ROLE_GUARDIAN, "Guardian", "freeze · veto · recover"]]; export function Members({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); const { signer } = useStore(); const roles = useMyRoles(vault); @@ -46,15 +48,12 @@ export function Members({ vault, refetch, refreshing }: { vault: VaultData; refe top={ nav.goBack()} />} center={Members} right={isOwner ? { setTarget(""); setBits(ROLE_APPROVER); setOpen(true); }} /> : undefined} />}> Treasury signers · {signers.length} - Owners govern, approvers confirm payments, executors execute once every condition holds. A member may hold several of these roles. Guardians · {guardians.length} - Guardians can freeze the vault, veto risky or security-reducing proposals, confirm critical transfers and start a recovery. The contract will not let them hold a treasury role. {guardians.length ? : No guardian configured. Nobody independent can veto a proposal or freeze the vault.} Thresholds Routine {vault.policy.approvalsLow} · High {vault.policy.approvalsHigh} · Critical {vault.policy.approvalsCritical}{vault.policy.guardianRequiredCritical ? ` + ${vault.policy.guardianThreshold} guardian` : ""} · Governance {vault.policy.governanceThreshold} owner{vault.policy.governanceThreshold === 1 ? "" : "s"} - Thresholds are part of the policy. Lowering any of them waits {fmtDuration(vault.policy.policyChangeDelay)}, and any guardian can veto the change. @@ -70,7 +69,6 @@ export function Members({ vault, refetch, refreshing }: { vault: VaultData; refe ))} - {bits === 0 ? "Removing a member takes effect as soon as owners approve." : reducing ? `Adding authority or weakening the guardian layer loosens security: it waits ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto it.` : "Reducing a member's authority takes effect as soon as owners approve."} {existing && bits !== 0 && } diff --git a/mobile/src/screens/Notifications.tsx b/mobile/src/screens/Notifications.tsx index 55c9a8b..56d70da 100644 --- a/mobile/src/screens/Notifications.tsx +++ b/mobile/src/screens/Notifications.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { Switch, Text, View } from "react-native"; import { fmtRelative, short } from "@web/lib/format"; import { Status } from "@web/lib/types"; @@ -7,11 +8,12 @@ import { describeProposal } from "../lib/describe"; import { needsMe } from "../hooks/useAlerts"; import { useMyRoles } from "../hooks/useVault"; import { useStore } from "../state/store"; -import { BackButton, Badge, Card, CircleIcon, Empty, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; -import { C } from "../theme"; +import { BackButton, Badge, Card, CircleIcon, Empty, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; + /** Safe's notification centre: what needs this signer, then what happened recently. */ export function NotificationsScreen({ vault }: { vault: VaultData }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); const { signer, notifications, setNotifications } = useStore(); const roles = useMyRoles(vault); @@ -21,7 +23,7 @@ export function NotificationsScreen({ vault }: { vault: VaultData }) { nav.goBack()} />} center={Updates} />}> - } title="Notify me on this phone" subtitle="When a proposal newly needs your confirmation" trailing={ void setNotifications(v)} trackColor={{ true: C.accent }} />} last /> + } title="Notify me on this phone" subtitle="When a proposal needs you" trailing={ void setNotifications(v)} trackColor={{ true: C.accent }} />} last /> Needs you · {due.length} {due.length === 0 ? Nothing needs your signature right now. : ( @@ -35,7 +37,6 @@ export function NotificationsScreen({ vault }: { vault: VaultData }) { {recent.map((p, i) => { const d = describeProposal(p, vault); const tone = p.status === Status.EXECUTED ? "success" : p.status === Status.VETOED ? "error" : p.status === Status.PENDING ? "warn" : "dark"; return } title={`${d.title} · ${["", "pending", "executed", "cancelled", "vetoed"][p.status]}`} subtitle={`${d.detail} · by ${short(p.proposer)} · ${fmtRelative(p.createdAt)}`} trailing={p.status === Status.PENDING ? {p.liveApprovals}/{p.requiredApprovals} : undefined} chevron onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} last={i === recent.length - 1} />; })} )} - Notifications are raised on this phone when the app reads the vault and finds a proposal that newly needs you. There is no server between you and the chain. ); diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx index 434ff37..f02f12a 100644 --- a/mobile/src/screens/Onboard.tsx +++ b/mobile/src/screens/Onboard.tsx @@ -1,4 +1,5 @@ import { useState } from "react"; +import { useTheme } from "../state/theme"; import { Text, View } from "react-native"; import { isAddress } from "viem"; import { SkurFactoryAbi } from "@web/abi/SkurFactory"; @@ -7,11 +8,12 @@ import { short } from "@web/lib/format"; import { publicClient } from "../lib/client"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, Tape, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, Tape, TopBar, useStyles } from "../components/ui"; +import { F } from "../theme"; /** First screen: the web logo, then open a vault by address, the demo vault, or one the device signer belongs to. */ export function Onboard() { + const C = useTheme(); const s = useStyles(); const { setVaultAddress, signer, createSigner } = useStore(); const [addr, setAddr] = useState(""); const [mine, setMine] = useState<`0x${string}`[] | null>(null); @@ -27,7 +29,7 @@ export function Onboard() { } />}> Treasury security{"\n"}that assumes{"\n"}compromise - Open a vault to read its balances, queue and policy, and sign from this phone. Every rule is enforced by the vault contract, not by a server. + Read its balances, queue and policy. Sign from this phone. @@ -45,7 +47,7 @@ export function Onboard() { )} {err ? {err} : null} - Verified contracts on the Ark Constellation devnet. Skur never holds keys or funds. + Verified contracts. Skur holds no keys and no funds. ); } diff --git a/mobile/src/screens/Policy.tsx b/mobile/src/screens/Policy.tsx index 074f242..12bd1c3 100644 --- a/mobile/src/screens/Policy.tsx +++ b/mobile/src/screens/Policy.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useRef, useState } from "react"; import { Pressable, Switch, Text, View } from "react-native"; import { SkurVaultAbi } from "@web/abi/SkurVault"; @@ -11,8 +12,8 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; -import { BackButton, Badge, Button, Card, Expandable, Field, Input, Notice, Screen, SignBar, Tabs, TopBar, TxStatus, type IconName, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Badge, Button, Card, Expandable, Field, Input, Notice, Screen, SignBar, Tabs, TopBar, TxStatus, type IconName, useStyles } from "../components/ui"; +import { F } from "../theme"; const GROUP_ICON: Record = { Approvals: "users", Delays: "clock", Exposure: "pie-chart", "Circuit breaker": "zap" }; @@ -29,6 +30,7 @@ function groupSummary(fields: PolicyField[], p: Policy): string { /** The policy editor: templates, every control in groups, security-reducing detection, and per-asset limits. */ export function Policy({ vault }: { vault: VaultData }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void }>(); const { signer } = useStore(); const roles = useMyRoles(vault); @@ -79,13 +81,12 @@ export function Policy({ vault }: { vault: VaultData }) { {tab === "policy" && ( - t.id === template)?.name} loaded into the editor` : "start from a profile instead of designing from scratch"} icon="layers" open={open === "templates"} onToggle={() => toggle("templates")}> + t.id === template)?.name} loaded` : `${TEMPLATES.length} profiles to start from`} icon="layers" open={open === "templates"} onToggle={() => toggle("templates")}> {TEMPLATES.map((t) => ( { setTemplate(t.id); setDraft(t.policy); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: template === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name} ))} - Choosing one only fills the editor. Nothing is proposed until you sign. {changed && } @@ -93,7 +94,6 @@ export function Policy({ vault }: { vault: VaultData }) { const edited = g.fields.filter((f) => draft[f.key] !== vault.policy[f.key]).length; return ( toggle(g.title)}> - {g.sub} {g.fields.map((f, i) => set(f.key, v)} last={i === g.fields.length - 1} />)} ); @@ -109,7 +109,6 @@ export function Policy({ vault }: { vault: VaultData }) { )} {tab === "limits" && asset && text && ( - Tiers and caps for each asset, in that asset's own units. Approving a new asset loosens security and goes through the delayed path. {vault.assets.map((a) => setAssetAddr(a.address)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: a.address === assetAddr ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{a.symbol})} @@ -128,6 +127,7 @@ export function Policy({ vault }: { vault: VaultData }) { } function Control({ f, value, live, onChange, last }: { f: PolicyField; value: number | boolean; live: number | boolean; onChange: (v: number | boolean) => void; last: boolean }) { + const C = useTheme(); const s = useStyles(); const changed = value !== live; const label = {f.label}{f.hint ? {f.hint} : null}; const wrap = (control: React.ReactNode) => {label}{control}; @@ -138,9 +138,11 @@ function Control({ f, value, live, onChange, last }: { f: PolicyField; value: nu return wrap( onChange(Math.min((f.max ?? 100) * 100, Math.round(Number(t || 0) * 100)))} />); } function Stepper({ value, onChange }: { value: number; onChange: (v: number) => void }) { + const C = useTheme(); const B = ({ t, onPress }: { t: string; onPress: () => void }) => {t}; return onChange(value - 1)} />{value} onChange(value + 1)} />; } function Unit({ value, unit, onChange }: { value: string; unit: string; onChange: (t: string) => void }) { + const C = useTheme(); return {unit}; } diff --git a/mobile/src/screens/Receive.tsx b/mobile/src/screens/Receive.tsx index 250380a..dc56d4a 100644 --- a/mobile/src/screens/Receive.tsx +++ b/mobile/src/screens/Receive.tsx @@ -1,11 +1,13 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { Text, View } from "react-native"; import type { VaultData } from "@web/lib/vaultReads"; import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Card, Screen, Tape, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Address, BackButton, Card, Screen, Tape, TopBar, useStyles } from "../components/ui"; +import { F } from "../theme"; export function Receive({ vault }: { vault: VaultData }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void }>(); return ( nav.goBack()} />} center={Receive} />}> @@ -14,7 +16,7 @@ export function Receive({ vault }: { vault: VaultData }) { Vault address Ark Constellation devnet · chain 9000
      - Tap to copy. Deposits are accepted in every mode, including Lockdown. + Tap to copy. Deposits are always accepted. diff --git a/mobile/src/screens/Scan.tsx b/mobile/src/screens/Scan.tsx index 8eeefff..b72e999 100644 --- a/mobile/src/screens/Scan.tsx +++ b/mobile/src/screens/Scan.tsx @@ -1,14 +1,16 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { CameraView, useCameraPermissions } from "expo-camera"; import { useRef, useState } from "react"; import { Text, View } from "react-native"; import { isAddress } from "viem"; import { scanBus } from "../lib/scanBus"; -import { BackButton, Button, Notice, Screen, Tape, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Button, Notice, Screen, Tape, TopBar, useStyles } from "../components/ui"; +import { F } from "../theme"; /** QR scanner for vault and recipient addresses, as Safe's scan button. Accepts a bare address or an EIP-681 "ethereum:0x…" URI. */ export function Scan() { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void }>(); const [permission, requestPermission] = useCameraPermissions(); const [err, setErr] = useState(null); diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx index 4ae8de2..f57ec71 100644 --- a/mobile/src/screens/Security.tsx +++ b/mobile/src/screens/Security.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { RefreshControl, Text, View } from "react-native"; import { isAddress, stringToHex } from "viem"; @@ -12,13 +13,14 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { Identicon } from "../components/Identicon"; -import { BackButton, Badge, Button, Card, Expandable, Field, Input, KV, ModeBadge, Notice, Row, Screen, Tape, TopBar, TxStatus, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Badge, Button, Card, Expandable, Field, Input, KV, ModeBadge, Notice, Row, Screen, Tape, TopBar, TxStatus, useStyles } from "../components/ui"; +import { F } from "../theme"; type Panel = "posture" | "mode" | "guardians" | "recovery" | "loss" | "history" | null; /** One card per concern, each opening on tap, so the screen reads as a short list rather than a wall. */ export function Security({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; canGoBack: () => boolean }>(); const roles = useMyRoles(vault); const invalidate = useInvalidateVault(vault.address); @@ -59,7 +61,7 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref {vault.mode < Mode.LOCKDOWN && } {vault.mode > Mode.NORMAL && } - {canRaise ? "Lowering the mode needs owners and guardians together." : "Only an owner or guardian signer can change the mode."} + {canRaise ? "Lowering needs owners and guardians." : "Owners and guardians only."} toggle("guardians")}> @@ -71,11 +73,10 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref toggle("recovery")}> - The new address takes the same roles. Any owner can cancel during the delay, and the vault moves to Elevated when it completes. setOldSigner(t.trim())} placeholder="0x…" mono /> setNewSigner(t.trim())} placeholder="0x…" mono /> - {!isGuardian && Only a guardian signer can start a recovery.} + {!isGuardian && Guardians only.} {loss && stable && ( @@ -83,7 +84,6 @@ export function Security({ vault, refetch, refreshing }: { vault: VaultData; ref - A conservative upper bound for {stable.symbol} under the stated assumptions. A bound, never a guarantee. )} diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index aa556ef..f92ab61 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -1,4 +1,5 @@ import { useNavigation, useRoute } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useEffect, useState } from "react"; import { Pressable, Text, View } from "react-native"; import { scanBus } from "../lib/scanBus"; @@ -13,13 +14,14 @@ import { publicClient } from "../lib/client"; import { useInvalidateVault } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; -import { BackButton, Badge, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Row, Screen, Sheet, SignBar, TierBadge, TopBar, TrustBadge, TxStatus, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Badge, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Row, Screen, Sheet, SignBar, TierBadge, TopBar, TrustBadge, TxStatus, useStyles } from "../components/ui"; +import { F } from "../theme"; type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust }; /** Send: big amount, asset chips, recipient and purpose; the vault's own review card; sticky sign bar to propose. */ export function Send({ vault }: { vault: VaultData }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); const route = useRoute<{ key: string; name: string; params?: { asset?: `0x${string}`; to?: `0x${string}` } }>(); const { signer } = useStore(); @@ -85,7 +87,7 @@ export function Send({ vault }: { vault: VaultData }) { {asset ? `Vault holds ${fmtAmount(asset.balance, asset.decimals, asset.symbol)}` : ""} - + {isAddress(to) ? : } setTo(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> @@ -93,7 +95,7 @@ export function Send({ vault }: { vault: VaultData }) { { scanBus.request((a) => setTo(a)); nav.navigate("Scan"); }} /> - + diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index e0a72bb..4007824 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -1,4 +1,5 @@ import * as LocalAuthentication from "expo-local-authentication"; +import { useScheme, useTheme } from "../state/theme"; import { useNavigation } from "@react-navigation/native"; import { useEffect, useState } from "react"; import { Linking, Switch, Text, View } from "react-native"; @@ -9,15 +10,17 @@ import type { VaultData } from "@web/lib/vaultReads"; import { useMyRoles } from "../hooks/useVault"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { Address, Badge, Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; -import { C } from "../theme"; +import { Address, Badge, Button, Card, CircleIcon, Field, Icon, Input, Logo, Notice, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; + export function Settings({ vault }: { vault: VaultData | undefined }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const { vaultAddress, setVaultAddress, labels, setLabel, signer, biometrics, setBiometrics } = useStore(); const roles = useMyRoles(vault); const [name, setName] = useState(vaultAddress ? labels[vaultAddress.toLowerCase()] ?? "" : ""); const [bioAvailable, setBioAvailable] = useState(false); + const { scheme, setScheme } = useScheme(); useEffect(() => { void (async () => setBioAvailable((await LocalAuthentication.hasHardwareAsync()) && (await LocalAuthentication.isEnrolledAsync())))(); }, []); return ( @@ -30,23 +33,30 @@ export function Settings({ vault }: { vault: VaultData | undefined }) { } title={ { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} style={{ height: 36, paddingHorizontal: 10, backgroundColor: "transparent", borderWidth: 0, fontFamily: "DMSans_700Bold" }} />} subtitle={
      } /> } title="Policy" subtitle={vault ? `v${vault.policyVersion} · templates, tiers, delays, caps` : "…"} onPress={() => nav.navigate("Policy")} chevron /> } title="Members" subtitle={vault ? `${vault.members.length} members · roles and thresholds` : "…"} onPress={() => nav.navigate("Members")} chevron /> - } title="Address book" subtitle="Recipients, activation and trust" onPress={() => nav.navigate("AddressBook")} chevron /> - } title="Simulator" subtitle="Run attacks against the policy" onPress={() => nav.navigate("Simulator")} chevron /> - } title="Updates" subtitle="What needs you, recent activity" onPress={() => nav.navigate("Notifications")} chevron /> - } title="Security" subtitle="Mode, guardians, posture, maximum loss" onPress={() => nav.navigate("Security")} chevron /> + } title="Address book" subtitle="Recipients and trust" onPress={() => nav.navigate("AddressBook")} chevron /> + } title="Simulator" subtitle="Attacks against the policy" onPress={() => nav.navigate("Simulator")} chevron /> + } title="Updates" subtitle="What needs you" onPress={() => nav.navigate("Notifications")} chevron /> + } title="Security" subtitle="Mode, guardians, posture" onPress={() => nav.navigate("Security")} chevron /> } title="View on Blockscout" onPress={() => void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vaultAddress}`)} chevron /> } title="Switch vault" onPress={() => void setVaultAddress(null)} chevron /> - } title="Create a new vault" subtitle="Name, template, members, one signature" onPress={() => nav.navigate("CreateVault")} chevron last /> + } title="Create a new vault" subtitle="One signature" onPress={() => nav.navigate("CreateVault")} chevron last /> ) : <>} title="Open a vault" onPress={() => void setVaultAddress(null)} chevron />} title="Create a new vault" onPress={() => nav.navigate("CreateVault")} chevron last />} Signers on this phone - : } title={signer ? signer.label : "No signer yet"} subtitle={signer ?
      : "Create or import a key to sign from this phone"} trailing={roles ? {roleNames(roles).join(" · ")} : signer ? no role here : undefined} onPress={() => nav.navigate("Signers")} chevron /> - } title="Require Face ID to sign" subtitle={bioAvailable ? "Prompted before every signature" : "No biometrics enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} last /> + : } title={signer ? signer.label : "No signer yet"} subtitle={signer ?
      : "Create or import a key to sign from this phone"} trailing={roles ? {roleNames(roles).length > 2 ? "All roles" : roleNames(roles).join(" · ")} : signer ? no role : undefined} onPress={() => nav.navigate("Signers")} chevron /> + } title="Require Face ID to sign" subtitle={bioAvailable ? "Before every signature" : "Not enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} last /> + + + Appearance + + {([["light", "Light", "sun"], ["dark", "Dark", "moon"], ["system", "System", "smartphone"]] as const).map(([v, label, icon], i) => ( + } title={label} onPress={() => setScheme(v)} last={i === 2} + trailing={scheme === v ? : undefined} /> + ))} - The private key never leaves the phone. Only signed transactions do. Give this address a role in a vault to sign for it. Environment @@ -56,7 +66,6 @@ export function Settings({ vault }: { vault: VaultData | undefined }) { } title="Vault implementation" subtitle={
      } /> } title="Skur V1" subtitle={`demo vault ${short(DEPLOYMENTS.demoVault)}`} last /> - If this app ever disappears, the vault stays reachable through these endpoints and the verified contracts on the explorer. ); diff --git a/mobile/src/screens/Signers.tsx b/mobile/src/screens/Signers.tsx index c93ca38..25f54fb 100644 --- a/mobile/src/screens/Signers.tsx +++ b/mobile/src/screens/Signers.tsx @@ -1,15 +1,17 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { Alert, Text, View } from "react-native"; import { roleNames } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, CircleIcon, Field, Icon, Input, Notice, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Address, BackButton, Badge, Button, Card, CircleIcon, Field, Icon, Input, Notice, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; +import { F } from "../theme"; /** Safe's "Select signer": every key on this phone, which one signs, and how to add or remove one. */ export function Signers({ vault }: { vault: VaultData | undefined }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void }>(); const { signers, signer, setActiveSigner, createSigner, importSigner, removeSigner } = useStore(); const [importing, setImporting] = useState(false); @@ -26,15 +28,15 @@ export function Signers({ vault }: { vault: VaultData | undefined }) { const r = rolesOf(sg.address); return ( } title={sg.label} subtitle={
      } onPress={() => void setActiveSigner(sg.address)} last={i === signers.length - 1} - trailing={{r ? {roleNames(r).join(" · ")} : vault ? no role : null}{signer?.address === sg.address ? : null}} /> + trailing={{r ? {roleNames(r).length > 2 ? "All roles" : roleNames(r).join(" · ")} : vault ? no role : null}{signer?.address === sg.address ? : null}} /> ); })} )} Add a signer - } title="Create a signer key" subtitle="Generated and kept in the device keychain" onPress={() => void createSigner()} chevron /> - } title="Import a private key" subtitle="A key you already use as a member" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> + } title="Create a signer key" subtitle="Kept in the device keychain" onPress={() => void createSigner()} chevron /> + } title="Import a private key" subtitle="A key you already use" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> {importing && ( @@ -47,13 +49,11 @@ export function Signers({ vault }: { vault: VaultData | undefined }) { <> Active signer - } title={Remove {signer.label}} subtitle="Deletes the key from this phone" chevron last + } title={Remove {signer.label}} subtitle="Deleted from this phone" chevron last onPress={() => Alert.alert("Remove signer key?", "The key is deleted from this phone. Anything it can sign for becomes unreachable from here unless you have it backed up.", [{ text: "Keep", style: "cancel" }, { text: "Remove", style: "destructive", onPress: () => void removeSigner(signer.address) }])} /> )} - Keys never leave the phone. Only signed transactions do. The active signer is the one the Sign bar uses. - {signers.length} key{signers.length === 1 ? "" : "s"} on this device ); diff --git a/mobile/src/screens/Simulator.tsx b/mobile/src/screens/Simulator.tsx index d0e9ba4..bb428d5 100644 --- a/mobile/src/screens/Simulator.tsx +++ b/mobile/src/screens/Simulator.tsx @@ -1,4 +1,5 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useMemo, useState } from "react"; import { Pressable, Text, View } from "react-native"; import { NATIVE_ASSET } from "@web/config/chain"; @@ -7,14 +8,15 @@ import { runScenarios, type Verdict } from "@web/lib/simulator"; import { TEMPLATES, type TemplateId } from "@web/lib/templates"; import type { Policy } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; -import { BackButton, Badge, Card, CircleIcon, Field, Input, Row, Screen, SectionLabel, TopBar, s } from "../components/ui"; -import { C, F } from "../theme"; +import { BackButton, Badge, Card, CircleIcon, Field, Input, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; +import { F } from "../theme"; const TONE: Record = { blocked: "ok", impossible: "ok", delayed: "info", escalated: "warn", allowed: "bad" }; const TEXT: Record = { blocked: "Blocked", impossible: "Not possible", delayed: "Delayed", escalated: "Escalated", allowed: "Would succeed" }; /** Runs the policy against the attacks that actually happen, with the contract's own rules. */ export function Simulator({ vault }: { vault: VaultData | undefined }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ goBack: () => void }>(); const [source, setSource] = useState<"vault" | TemplateId>(vault ? "vault" : "startup"); const [balanceText, setBalanceText] = useState("1,000,000"); @@ -60,11 +62,11 @@ export function Simulator({ vault }: { vault: VaultData | undefined }) { ))} - Blocked and Not possible mean the contract refuses. Delayed means guardians get a veto window. Escalated means more approvals are needed but nothing waits. Would succeed is a gap to close before the policy goes live. ); } function Chip({ on, onPress, children }: { on: boolean; onPress: () => void; children: React.ReactNode }) { + const C = useTheme(); return {children}; } diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx index 064910c..52c3385 100644 --- a/mobile/src/screens/Transactions.tsx +++ b/mobile/src/screens/Transactions.tsx @@ -1,16 +1,18 @@ import { useNavigation } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { fmtDate } from "@web/lib/format"; import { Kind, Status } from "@web/lib/types"; import type { ProposalView, VaultData } from "@web/lib/vaultReads"; import { describeProposal, statusText } from "../lib/describe"; -import { Badge, Card, CircleIcon, Empty, IconButton, Notice, Row, Screen, StatusBadge, Tabs, TopBar, type IconName, s } from "../components/ui"; -import { C, F } from "../theme"; +import { Badge, Card, CircleIcon, Empty, IconButton, Notice, Row, Screen, StatusBadge, Tabs, TopBar, type IconName, useStyles } from "../components/ui"; +import { F } from "../theme"; export const KIND_ICON: Record = { [Kind.TRANSFER]: "arrow-up-right", [Kind.POLICY_UPDATE]: "sliders", [Kind.ASSET_LIMITS]: "sliders", [Kind.MEMBER_SET]: "users", [Kind.RECIPIENT_TRUST]: "book", [Kind.MODE_RELAX]: "shield", [Kind.RECOVERY]: "life-buoy" }; export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { + const C = useTheme(); const s = useStyles(); const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); const [tab, setTab] = useState<"queue" | "history">("queue"); const [filter, setFilter] = useState<"all" | "transfers" | "governance">("all"); @@ -44,7 +46,6 @@ export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; ))} - Governance proposals need owner confirmations. Security-reducing ones also wait out their timelock, and any guardian can veto them. ); } diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx index 9b647a4..3539868 100644 --- a/mobile/src/screens/TxDetail.tsx +++ b/mobile/src/screens/TxDetail.tsx @@ -1,4 +1,5 @@ import { useNavigation, useRoute } from "@react-navigation/native"; +import { useTheme } from "../state/theme"; import { useState } from "react"; import { Linking, Pressable, Text, View } from "react-native"; import { stringToHex } from "viem"; @@ -12,12 +13,13 @@ import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; import { useTx } from "../hooks/useTx"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, CircleIcon, Icon, IconButton, KV, Notice, Row, Screen, SignBar, StatusBadge, TierBadge, TopBar, TxStatus, s } from "../components/ui"; +import { Address, BackButton, Badge, Button, Card, CircleIcon, Icon, IconButton, KV, Notice, Row, Screen, SignBar, StatusBadge, TierBadge, TopBar, TxStatus, useStyles } from "../components/ui"; import { KIND_ICON } from "./Transactions"; -import { C, F } from "../theme"; +import { F } from "../theme"; /** Safe's "Confirm transaction": hero amount, To card with advanced details, checks and confirmations rows, sticky sign bar. */ export function TxDetail({ vault }: { vault: VaultData }) { + const C = useTheme(); const s = useStyles(); const route = useRoute<{ key: string; name: string; params: { id: string } }>(); const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); const { signer } = useStore(); diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx index 8603ebc..cdb36e5 100644 --- a/mobile/src/screens/Welcome.tsx +++ b/mobile/src/screens/Welcome.tsx @@ -3,13 +3,14 @@ import { Dimensions, Pressable, ScrollView, StatusBar, Text, View, type NativeSc import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Identicon } from "../components/Identicon"; import { Icon } from "../components/ui"; -import { C, F } from "../theme"; +import { F, type Palette } from "../theme"; +import { useTheme } from "../state/theme"; const W = Dimensions.get("window").width; const ART = 310; -/** Light palette for the first-launch screens, matching the web's marketing pages. */ -const L = { bg: "#ffffff", ink: "#212529", ink2: "#6c757d", line: "#e9ecef", wash: "#f1f3f5" }; -const shadow = { shadowColor: "#0b1220", shadowOpacity: 0.1, shadowRadius: 24, shadowOffset: { width: 0, height: 12 }, elevation: 6 } as const; +/** The onboarding stands on the same ground as the app, so the two never disagree. */ +const ink = (C: Palette) => ({ bg: C.canvas, ink: C.text, ink2: C.text2, line: C.border, wash: C.card }); +const shade = (C: Palette) => ({ shadowColor: "#000", shadowOpacity: C.shadowOpacity * 1.2, shadowRadius: 24, shadowOffset: { width: 0, height: 12 }, elevation: 6 } as const); const PAGES = [ { title: "Track your treasury.\nAnywhere.", sub: "Balances and activity, read live from the chain.", art: }, @@ -19,6 +20,7 @@ const PAGES = [ /** First launch: one idea per page, a real product surface as its illustration, and a single button. */ export function Welcome({ onDone }: { onDone: () => void }) { + const C = useTheme(); const L = ink(C); const shadow = shade(C); const insets = useSafeAreaInsets(); const [page, setPage] = useState(0); const ref = useRef(null); @@ -59,6 +61,7 @@ const VAULT = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; const NEW_ADDR = "0x7c4f9A2b61e3d0c8F5a4B2e1D6c9A3f8E0b71e42"; function Coin({ label, size, bg, fg = "#fff", style }: { label: string; size: number; bg: string; fg?: string; style?: object }) { + const C = useTheme(); const L = ink(C); const shadow = shade(C); return ( {label} @@ -68,6 +71,7 @@ function Coin({ label, size, bg, fg = "#fff", style }: { label: string; size: nu /** Page 1: the vault as the app actually shows it, with its assets orbiting. */ function ArtVault() { + const C = useTheme(); const L = ink(C); const shadow = shade(C); return ( @@ -97,6 +101,7 @@ function ArtVault() { /** Page 2: the same payment at three sizes, and what the vault asks of each. */ function ArtTiers() { + const C = useTheme(); const L = ink(C); const shadow = shade(C); const rows: Array<{ amt: string; req: string; tier: string; bg: string; fg: string; dx: number }> = [ { amt: "1,000 sUSD", req: "1 approval · now", tier: "Low", bg: "#e6f6ec", fg: "#1b7f4a", dx: -14 }, { amt: "12,000 sUSD", req: "2 approvals · 1 day", tier: "High", bg: "#fff3d6", fg: "#a86a00", dx: 10 }, @@ -122,6 +127,7 @@ function ArtTiers() { /** Page 3: the alert that reaches you, over the confirmation it opens. */ function ArtSign() { + const C = useTheme(); const L = ink(C); const shadow = shade(C); return ( diff --git a/mobile/src/state/theme.tsx b/mobile/src/state/theme.tsx new file mode 100644 index 0000000..62f7b97 --- /dev/null +++ b/mobile/src/state/theme.tsx @@ -0,0 +1,31 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; +import { useColorScheme } from "react-native"; +import { DARK, LIGHT, type Palette } from "../theme"; + +export type Scheme = "light" | "dark" | "system"; +const Ctx = createContext<{ C: Palette; scheme: Scheme; dark: boolean; setScheme: (s: Scheme) => void } | null>(null); +const KEY = "skur.theme"; + +/** One ground for the whole app, onboarding included, switchable in Settings and remembered. */ +export function ThemeProvider({ children }: { children: ReactNode }) { + const system = useColorScheme(); + const [scheme, setSchemeState] = useState("system"); + useEffect(() => { void AsyncStorage.getItem(KEY).then((v) => { if (v === "light" || v === "dark" || v === "system") setSchemeState(v); }); }, []); + const setScheme = useCallback((s: Scheme) => { setSchemeState(s); void AsyncStorage.setItem(KEY, s); }, []); + const dark = scheme === "system" ? system === "dark" : scheme === "dark"; + const value = useMemo(() => ({ C: dark ? DARK : LIGHT, scheme, dark, setScheme }), [dark, scheme, setScheme]); + return {children}; +} + +export function useTheme(): Palette { + const t = useContext(Ctx); + if (!t) throw new Error("ThemeProvider missing"); + return t.C; +} + +export function useScheme() { + const t = useContext(Ctx); + if (!t) throw new Error("ThemeProvider missing"); + return t; +} diff --git a/mobile/src/theme.ts b/mobile/src/theme.ts index bf6395a..ec21780 100644 --- a/mobile/src/theme.ts +++ b/mobile/src/theme.ts @@ -1,24 +1,30 @@ -/** Skur mobile: Safe{Mobile}'s skeleton in Skur's clothes. Charcoal ground instead of black, #FFD000 as hazard tape and highlighter. */ -export const C = { - canvas: "#212529", - card: "#2b3035", - card2: "#343a40", - border: "#495057", - text: "#f8f9fa", - text2: "#adb5bd", - text3: "#6c757d", - accent: "#ffd000", - accentBg: "#3d3400", - onAccent: "#212529", - success: "#75b798", - successBg: "#1b4332", - warning: "#ffa94d", - warningBg: "#4d2e05", - error: "#ea868f", - errorBg: "#4a1c22", - info: "#6ea8fe", - infoBg: "#1b3a5c", -} as const; +/** Skur's two grounds. Same tokens in both, so a screen never needs to know which one is on. */ +export type Palette = { + canvas: string; card: string; card2: string; border: string; + text: string; text2: string; text3: string; + accent: string; accentBg: string; onAccent: string; + success: string; successBg: string; warning: string; warningBg: string; + error: string; errorBg: string; info: string; infoBg: string; + shadowOpacity: number; +}; + +export const LIGHT: Palette = { + canvas: "#ffffff", card: "#f6f7f9", card2: "#eceef2", border: "#e4e7ec", + text: "#101418", text2: "#667085", text3: "#98a2b3", + accent: "#ffd000", accentBg: "#fff6cc", onAccent: "#101418", + success: "#11875a", successBg: "#e6f6ec", warning: "#a86a00", warningBg: "#fff3d6", + error: "#b42318", errorBg: "#ffe4e2", info: "#1971c2", infoBg: "#e7f1ff", + shadowOpacity: 0.08, +}; + +export const DARK: Palette = { + canvas: "#212529", card: "#2b3035", card2: "#343a40", border: "#495057", + text: "#f8f9fa", text2: "#adb5bd", text3: "#6c757d", + accent: "#ffd000", accentBg: "#3d3400", onAccent: "#212529", + success: "#75b798", successBg: "#1b4332", warning: "#ffa94d", warningBg: "#4d2e05", + error: "#ea868f", errorBg: "#4a1c22", info: "#6ea8fe", infoBg: "#1b3a5c", + shadowOpacity: 0.4, +}; export const F = { display: "SpaceGrotesk_700Bold", From 294de9f681d4c29ab896ffd8851c2a8ae31e3ea9 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 21:59:37 +0100 Subject: [PATCH 09/44] fix(mobile): the onboarding carousel always opens on its first page The horizontal pager could come back on whichever page the view last showed. It now scrolls to the start on mount, so a first launch always begins at page one. --- mobile/src/screens/Welcome.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx index cdb36e5..4d6515b 100644 --- a/mobile/src/screens/Welcome.tsx +++ b/mobile/src/screens/Welcome.tsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { Dimensions, Pressable, ScrollView, StatusBar, Text, View, type NativeScrollEvent, type NativeSyntheticEvent } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { Identicon } from "../components/Identicon"; @@ -25,6 +25,8 @@ export function Welcome({ onDone }: { onDone: () => void }) { const [page, setPage] = useState(0); const ref = useRef(null); const onScroll = (e: NativeSyntheticEvent) => setPage(Math.round(e.nativeEvent.contentOffset.x / W)); + // The carousel always opens on the first page, whatever the view was showing before. + useEffect(() => { ref.current?.scrollTo({ x: 0, animated: false }); setPage(0); }, []); return ( @@ -34,7 +36,7 @@ export function Welcome({ onDone }: { onDone: () => void }) { {"[MOBILE]"} - + {PAGES.map((p, i) => ( {p.art} From 424870290348a08f8306859b07e3f4d386b7b75c Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 16 Sep 2026 22:20:17 +0100 Subject: [PATCH 10/44] feat: a five-asset demo vault, token marks, and a wallet-style add-vault screen The demo vault held one token and native KASH, so a portfolio had nothing to show. A parameterised devnet token joins the test USD, and a new demo vault holds sUSD, KASH, sEUR, sBTC and sETH with limits for each. Deployed and funded on the Ark devnet; the deployment record carries the new addresses. Each asset now has a mark rather than a letter in a circle: one colour and glyph per symbol, defined once in web/src/lib/tokens.ts and drawn the same way by the web app and the phone. The screen that opened a vault led with a marketing headline. It is now what a wallet shows: Add a vault, the vaults this signer belongs to, then the ways in as rows, with watching a vault behind a sheet. The Environment section leaves Settings; the network already appears where it matters. --- .../9000/run-1789592989926.json | 617 ++++++++++++++++++ .../DemoVault.s.sol/9000/run-latest.json | 617 ++++++++++++++++++ contracts/deployments/9000.json | 2 +- contracts/script/DemoVault.s.sol | 72 ++ contracts/src/SkurTestToken.sol | 24 + mobile/src/components/TokenMark.tsx | 13 + mobile/src/screens/Home.tsx | 6 +- mobile/src/screens/Onboard.tsx | 95 ++- mobile/src/screens/Send.tsx | 3 +- mobile/src/screens/Settings.tsx | 8 - web/src/components/ui.tsx | 9 +- web/src/config/chain.ts | 3 + web/src/config/deployments.json | 13 +- web/src/lib/tokens.ts | 17 + web/src/pages/Assets.tsx | 3 +- web/src/pages/Overview.tsx | 3 +- web/src/styles.css | 5 +- 17 files changed, 1453 insertions(+), 57 deletions(-) create mode 100644 contracts/broadcast/DemoVault.s.sol/9000/run-1789592989926.json create mode 100644 contracts/broadcast/DemoVault.s.sol/9000/run-latest.json create mode 100644 contracts/script/DemoVault.s.sol create mode 100644 contracts/src/SkurTestToken.sol create mode 100644 mobile/src/components/TokenMark.tsx create mode 100644 web/src/lib/tokens.ts diff --git a/contracts/broadcast/DemoVault.s.sol/9000/run-1789592989926.json b/contracts/broadcast/DemoVault.s.sol/9000/run-1789592989926.json new file mode 100644 index 0000000..6e77bf6 --- /dev/null +++ b/contracts/broadcast/DemoVault.s.sol/9000/run-1789592989926.json @@ -0,0 +1,617 @@ +{ + "transactions": [ + { + "hash": "0x11436b12e80a550f467e9dd471ceaed6ccbac80947d6ee2fa9ab3bac5831553c", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "function": null, + "arguments": [ + "Skur Test EUR", + "sEUR", + "6" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204555520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047345555200000000000000000000000000000000000000000000000000000000", + "nonce": "0x19d", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0c89e0c4c7fcf8603bafb96b5d7c2d4564e4be2a146d0ee8ff80a84a9f940e2f", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "function": null, + "arguments": [ + "Skur Test BTC", + "sBTC", + "8" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047342544300000000000000000000000000000000000000000000000000000000", + "nonce": "0x19e", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3e73ec3499f019074cfef70a79552fbc7376c7902b353cea8720fc5df11f15b2", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "function": null, + "arguments": [ + "Skur Test ETH", + "sETH", + "18" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047345544800000000000000000000000000000000000000000000000000000000", + "nonce": "0x19f", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionType": "CALL", + "contractName": "SkurFactory", + "contractAddress": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "function": "createVault(bytes32,address[],uint8[],(uint8,uint8,uint8,uint8,uint8,bool,uint32,uint32,uint32,uint32,uint32,uint32,uint16,uint16,uint16,uint16,uint32),address[],(bool,uint256,uint256,uint256,uint256)[])", + "arguments": [ + "0xa7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a", + "[0x4FEA262782b5BE34B18cf24b6aC026215899EEc0, 0xB6685D046E34A3260b9098aA6073CD7867e2de1C, 0xCec10C48B8d37b6A083000173e3415Cc6f86974F]", + "[7, 3, 8]", + "(1, 2, 2, 2, 1, true, 21600, 86400, 86400, 86400, 172800, 604800, 500, 2000, 5000, 1000, 86400)", + "[0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a, 0x0000000000000000000000000000000000000000, 0xb524729FbfCA5724BfcfBbEd70eF3e45b1aBD8F1, 0xdF32512Dd6bC9E196fb442150b182172E1Ce292e, 0x2e494E1b1138aD260Be8bede8E8dA5110E5239bd]", + "[(true, 5000000000, 25000000000, 100000000000, 100000000000), (true, 100000000000000000000, 1000000000000000000000, 0, 5000000000000000000000), (true, 5000000000, 25000000000, 100000000000, 100000000000), (true, 50000000, 500000000, 2000000000, 5000000000), (true, 1000000000000000000, 10000000000000000000, 40000000000000000000, 100000000000000000000)]" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "gas": "0x1c41b6", + "value": "0x0", + "input": "0x5492a6eca7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000030000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0000000000000000000000000b6685d046e34a3260b9098aa6073cd7867e2de1c000000000000000000000000cec10c48b8d37b6a083000173e3415cc6f86974f000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000050000000000000000000000003e41424adf6bb69b6271ef9b0541acd59a0d454a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b524729fbfca5724bfcfbbed70ef3e45b1abd8f1000000000000000000000000df32512dd6bc9e196fb442150b182172e1ce292e0000000000000000000000002e494e1b1138ad260be8bede8e8da5110e5239bd00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010f0cf064dd592000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000022b1c8c1227a000000000000000000000000000000000000000000000000000056bc75e2d63100000", + "nonce": "0x1a0", + "chainId": "0x2328" + }, + "additionalContracts": [ + { + "transactionType": "CREATE2", + "contractName": null, + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "initCode": "0x3d602d80600a3d3981f3363d3d373d3d3d363d73e21c7ad3a56d187848f9915bb43f88820278dea35af43d82803e903d91602b57fd5bf3" + } + ], + "isFixedGasLimit": false + }, + { + "hash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionType": "CALL", + "contractName": "SkurTestUSD", + "contractAddress": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "250000000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "gas": "0x1235c", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed520000000000000000000000000000000000000000000000000000003a35294400", + "nonce": "0x1a1", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "84500000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "gas": "0x184e4", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed5200000000000000000000000000000000000000000000000000000013ac97ad00", + "nonce": "0x1a2", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "342000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "gas": "0x184e4", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed520000000000000000000000000000000000000000000000000000000014628180", + "nonce": "0x1a3", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "12400000000000000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "gas": "0x18507", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52000000000000000000000000000000000000000000000000ac15a64d4ed80000", + "nonce": "0x1a4", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "function": null, + "arguments": null, + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "gas": "0x10197", + "value": "0x29a2241af62c0000", + "input": "0x", + "nonce": "0x1a5", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x11436b12e80a550f467e9dd471ceaed6ccbac80947d6ee2fa9ab3bac5831553c", + "transactionIndex": "0x0", + "blockHash": "0xcf8df0182a959216da019155272f259a9f417bc085a21c91cce6f874cd4bcaf3", + "blockNumber": "0x7e4c3", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x0c89e0c4c7fcf8603bafb96b5d7c2d4564e4be2a146d0ee8ff80a84a9f940e2f", + "transactionIndex": "0x0", + "blockHash": "0x2d22f39b521ba338c15b5419cdae4d69076b3422c54b3fa2eaede04995a317e6", + "blockNumber": "0x7e4c6", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x3e73ec3499f019074cfef70a79552fbc7376c7902b353cea8720fc5df11f15b2", + "transactionIndex": "0x0", + "blockHash": "0x27fa9e6f914ca42f16bd5bdb652967db2ce001229548ff9f709437ca36afbce2", + "blockNumber": "0x7e4c8", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x147514", + "logs": [ + { + "address": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "topics": [ + "0xc18dea5f6b30c3fd606e8e38832933e2fa57407dd77800aad0658505ee94df98", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0", + "0x0000000000000000000000000000000000000000000000000000000000000005" + ], + "data": "0xa7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x1", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x000000000000000000000000b6685d046e34a3260b9098aa6073cd7867e2de1c" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x2", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x000000000000000000000000cec10c48b8d37b6a083000173e3415cc6f86974f" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000003e41424adf6bb69b6271ef9b0541acd59a0d454a" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e800", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010f0cf064dd59200000", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x000000000000000000000000b524729fbfca5724bfcfbbed70ef3e45b1abd8f1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e800", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x000000000000000000000000df32512dd6bc9e196fb442150b182172e1ce292e" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000000000000012a05f200", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x7", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000002e494e1b1138ad260be8bede8e8da5110e5239bd" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000022b1c8c1227a000000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x8", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x1a734774792c149a91deb03650b2a2bc51de7bbab7262857ace6fb1699b43041", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + "data": "0x000000000000000000000000000000000000000000000000000000006aab05710000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000015180", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x9", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x4488062cfafbbb2c1d440f13796e120c4522761f74ecade440ee8f31f1bfbee0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0xa", + "removed": false + } + ], + "logsBloom": "0x001000000000800100000000000000040800000000000000000000000000000000000400000000000000000000000000000000020100080008000000000404000000100000000000000010000000008000000000000400000000000000000000000000000204000009000000000008000800080000000000000000000000800200008000000c0000000802000000001000002800000000000000000000000000000010800000000001000000000000000010000000008000008000000000020000000000080008000020400000000000000000000000000000400002010060000000000480000000000000000000000000000000000410000000400000000000", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "gasUsed": "0x147514", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xc739", + "logs": [ + { + "address": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x0000000000000000000000000000000000000000000000000000003a35294400", + "blockHash": "0x17f1d915592124a53cb8bae6f9ad21ef1d9e512187e6a3afd45b246fa79ff5bb", + "blockNumber": "0x7e4cd", + "blockTimestamp": "0x6aab0577", + "transactionHash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000012000000004100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionIndex": "0x0", + "blockHash": "0x17f1d915592124a53cb8bae6f9ad21ef1d9e512187e6a3afd45b246fa79ff5bb", + "blockNumber": "0x7e4cd", + "gasUsed": "0xc739", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x109e9", + "logs": [ + { + "address": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x00000000000000000000000000000000000000000000000000000013ac97ad00", + "blockHash": "0x8fdf62612cf1da7ed881d37f351d2c94d6ebfbc16799a7e9b65ada50826cac54", + "blockNumber": "0x7e4cf", + "blockTimestamp": "0x6aab057f", + "transactionHash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000080000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000040000000000000000", + "transactionHash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionIndex": "0x0", + "blockHash": "0x8fdf62612cf1da7ed881d37f351d2c94d6ebfbc16799a7e9b65ada50826cac54", + "blockNumber": "0x7e4cf", + "gasUsed": "0x109e9", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x109e9", + "logs": [ + { + "address": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000014628180", + "blockHash": "0x3fd2619543d1d0a65be1bf1ec1dfbb7972e608190db958a587cf2c51f4929c6d", + "blockNumber": "0x7e4d1", + "blockTimestamp": "0x6aab0585", + "transactionHash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000002000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020200000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionIndex": "0x0", + "blockHash": "0x3fd2619543d1d0a65be1bf1ec1dfbb7972e608190db958a587cf2c51f4929c6d", + "blockNumber": "0x7e4d1", + "gasUsed": "0x109e9", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x10a01", + "logs": [ + { + "address": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x000000000000000000000000000000000000000000000000ac15a64d4ed80000", + "blockHash": "0xdef889a1914fbe461b0c9a177f5d94c1daab4e770564418b573cfa17105715ff", + "blockNumber": "0x7e4d3", + "blockTimestamp": "0x6aab058f", + "transactionHash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000002000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionIndex": "0x0", + "blockHash": "0xdef889a1914fbe461b0c9a177f5d94c1daab4e770564418b573cfa17105715ff", + "blockNumber": "0x7e4d3", + "gasUsed": "0x10a01", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xba7f", + "logs": [ + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000029a2241af62c0000", + "blockHash": "0xf503e14bf69b301c143c588e3dd8969141d45fd83252d493605b11a67a527415", + "blockNumber": "0x7e4d5", + "blockTimestamp": "0x6aab0596", + "transactionHash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000020000000800000000000800000008000000000000000000000080020000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionIndex": "0x0", + "blockHash": "0xf503e14bf69b301c143c588e3dd8969141d45fd83252d493605b11a67a527415", + "blockNumber": "0x7e4d5", + "gasUsed": "0xba7f", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "contractAddress": null + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1789592989926, + "chain": 9000, + "commit": "294de9f" +} \ No newline at end of file diff --git a/contracts/broadcast/DemoVault.s.sol/9000/run-latest.json b/contracts/broadcast/DemoVault.s.sol/9000/run-latest.json new file mode 100644 index 0000000..6e77bf6 --- /dev/null +++ b/contracts/broadcast/DemoVault.s.sol/9000/run-latest.json @@ -0,0 +1,617 @@ +{ + "transactions": [ + { + "hash": "0x11436b12e80a550f467e9dd471ceaed6ccbac80947d6ee2fa9ab3bac5831553c", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "function": null, + "arguments": [ + "Skur Test EUR", + "sEUR", + "6" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204555520000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047345555200000000000000000000000000000000000000000000000000000000", + "nonce": "0x19d", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0c89e0c4c7fcf8603bafb96b5d7c2d4564e4be2a146d0ee8ff80a84a9f940e2f", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "function": null, + "arguments": [ + "Skur Test BTC", + "sBTC", + "8" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204254430000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047342544300000000000000000000000000000000000000000000000000000000", + "nonce": "0x19e", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3e73ec3499f019074cfef70a79552fbc7376c7902b353cea8720fc5df11f15b2", + "transactionType": "CREATE", + "contractName": "SkurTestToken", + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "function": null, + "arguments": [ + "Skur Test ETH", + "sETH", + "18" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "gas": "0x9771b", + "value": "0x0", + "input": "0x60a06040523461033057610a398038038061001981610334565b9283398101906060818303126103305780516001600160401b0381116103305782610045918301610359565b60208201519092906001600160401b03811161033057604091610069918401610359565b91015160ff811681036103305782516001600160401b03811161024157600354600181811c91168015610326575b602082101461022357601f81116102c3575b506020601f821160011461026057819293945f92610255575b50508160011b915f199060031b1c1916176003555b81516001600160401b03811161024157600454600181811c91168015610237575b602082101461022357601f81116101c0575b50602092601f821160011461015f57928192935f92610154575b50508160011b915f199060031b1c1916176004555b60805260405161068e90816103ab82396080518161031c0152f35b015190505f80610124565b601f1982169360045f52805f20915f5b8681106101a85750836001959610610190575b505050811b01600455610139565b01515f1960f88460031b161c191690555f8080610182565b9192602060018192868501518155019401920161016f565b60045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c81019160208410610219575b601f0160051c01905b81811061020e575061010a565b5f8155600101610201565b90915081906101f8565b634e487b7160e01b5f52602260045260245ffd5b90607f16906100f8565b634e487b7160e01b5f52604160045260245ffd5b015190505f806100c2565b601f1982169060035f52805f20915f5b8181106102ab57509583600195969710610293575b505050811b016003556100d7565b01515f1960f88460031b161c191690555f8080610285565b9192602060018192868b015181550194019201610270565b60035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c8101916020841061031c575b601f0160051c01905b81811061031157506100a9565b5f8155600101610304565b90915081906102fb565b90607f1690610097565b5f80fd5b6040519190601f01601f191682016001600160401b0381118382101761024157604052565b81601f82011215610330578051906001600160401b03821161024157610388601f8301601f1916602001610334565b928284526020838301011161033057815f9260208093018386015e830101529056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146104bf57508063095ea7b31461043d57806318160ddd1461042057806323b872dd14610340578063313ce5671461030357806340c10f191461026157806370a082311461022a57806395d89b411461010f578063a9059cbb146100de5763dd62ed3e1461008a575f80fd5b346100da5760403660031901126100da576100a36105b8565b6100ab6105ce565b6001600160a01b039182165f908152600160209081526040808320949093168252928352819020549051908152f35b5f80fd5b346100da5760403660031901126100da576101046100fa6105b8565b60243590336105e4565b602060405160018152f35b346100da575f3660031901126100da576040515f6004548060011c90600181168015610220575b60208310811461020c578285529081156101f0575060011461019b575b50819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b0390f35b634e487b7160e01b5f52604160045260245ffd5b905060045f527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5f905b8282106101da57506020915082010182610153565b60018160209254838588010152019101906101c5565b90506020925060ff191682840152151560051b82010182610153565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610136565b346100da5760203660031901126100da576001600160a01b0361024b6105b8565b165f525f602052602060405f2054604051908152f35b346100da5760403660031901126100da5761027a6105b8565b6001600160a01b031660243581156102f057600254908082018092116102dc5760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef915f9360025584845283825260408420818154019055604051908152a3005b634e487b7160e01b5f52601160045260245ffd5b63ec442f0560e01b5f525f60045260245ffd5b346100da575f3660031901126100da57602060405160ff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100da5760603660031901126100da576103596105b8565b6103616105ce565b6001600160a01b0382165f8181526001602081815260408084203385529091529091205491936044359392909181016103a0575b5061010493506105e4565b8381106104055784156103f25733156103df57610104945f52600160205260405f2060018060a01b0333165f526020528360405f209103905584610395565b634a1406b160e11b5f525f60045260245ffd5b63e602df0560e01b5f525f60045260245ffd5b8390637dc7a0d960e11b5f523360045260245260445260645ffd5b346100da575f3660031901126100da576020600254604051908152f35b346100da5760403660031901126100da576104566105b8565b6024359033156103f2576001600160a01b03169081156103df57335f52600160205260405f20825f526020528060405f20556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346100da575f3660031901126100da575f6003548060011c90600181168015610584575b60208310811461020c578285529081156101f0575060011461052f5750819003601f01601f191681019067ffffffffffffffff821181831017610187576101838291826040528261058e565b905060035f527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5f905b82821061056e57506020915082010182610153565b6001816020925483858801015201910190610559565b91607f16916104e3565b602060409281835280519182918282860152018484015e5f828201840152601f01601f1916010190565b600435906001600160a01b03821682036100da57565b602435906001600160a01b03821682036100da57565b6001600160a01b031690811561067b576001600160a01b03169182156102f057815f525f60205260405f205481811061066257817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92602092855f525f84520360405f2055845f525f825260405f20818154019055604051908152a3565b8263391434e360e21b5f5260045260245260445260645ffd5b634b637e8f60e11b5f525f60045260245ffd000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000d536b75722054657374204554480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047345544800000000000000000000000000000000000000000000000000000000", + "nonce": "0x19f", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionType": "CALL", + "contractName": "SkurFactory", + "contractAddress": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "function": "createVault(bytes32,address[],uint8[],(uint8,uint8,uint8,uint8,uint8,bool,uint32,uint32,uint32,uint32,uint32,uint32,uint16,uint16,uint16,uint16,uint32),address[],(bool,uint256,uint256,uint256,uint256)[])", + "arguments": [ + "0xa7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a", + "[0x4FEA262782b5BE34B18cf24b6aC026215899EEc0, 0xB6685D046E34A3260b9098aA6073CD7867e2de1C, 0xCec10C48B8d37b6A083000173e3415Cc6f86974F]", + "[7, 3, 8]", + "(1, 2, 2, 2, 1, true, 21600, 86400, 86400, 86400, 172800, 604800, 500, 2000, 5000, 1000, 86400)", + "[0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a, 0x0000000000000000000000000000000000000000, 0xb524729FbfCA5724BfcfBbEd70eF3e45b1aBD8F1, 0xdF32512Dd6bC9E196fb442150b182172E1Ce292e, 0x2e494E1b1138aD260Be8bede8E8dA5110E5239bd]", + "[(true, 5000000000, 25000000000, 100000000000, 100000000000), (true, 100000000000000000000, 1000000000000000000000, 0, 5000000000000000000000), (true, 5000000000, 25000000000, 100000000000, 100000000000), (true, 50000000, 500000000, 2000000000, 5000000000), (true, 1000000000000000000, 10000000000000000000, 40000000000000000000, 100000000000000000000)]" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "gas": "0x1c41b6", + "value": "0x0", + "input": "0x5492a6eca7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000000030000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0000000000000000000000000b6685d046e34a3260b9098aa6073cd7867e2de1c000000000000000000000000cec10c48b8d37b6a083000173e3415cc6f86974f000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000050000000000000000000000003e41424adf6bb69b6271ef9b0541acd59a0d454a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b524729fbfca5724bfcfbbed70ef3e45b1abd8f1000000000000000000000000df32512dd6bc9e196fb442150b182172e1ce292e0000000000000000000000002e494e1b1138ad260be8bede8e8da5110e5239bd00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010f0cf064dd592000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e80000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000022b1c8c1227a000000000000000000000000000000000000000000000000000056bc75e2d63100000", + "nonce": "0x1a0", + "chainId": "0x2328" + }, + "additionalContracts": [ + { + "transactionType": "CREATE2", + "contractName": null, + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "initCode": "0x3d602d80600a3d3981f3363d3d373d3d3d363d73e21c7ad3a56d187848f9915bb43f88820278dea35af43d82803e903d91602b57fd5bf3" + } + ], + "isFixedGasLimit": false + }, + { + "hash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionType": "CALL", + "contractName": "SkurTestUSD", + "contractAddress": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "250000000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "gas": "0x1235c", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed520000000000000000000000000000000000000000000000000000003a35294400", + "nonce": "0x1a1", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "84500000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "gas": "0x184e4", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed5200000000000000000000000000000000000000000000000000000013ac97ad00", + "nonce": "0x1a2", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "342000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "gas": "0x184e4", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed520000000000000000000000000000000000000000000000000000000014628180", + "nonce": "0x1a3", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionType": "CALL", + "contractName": "SkurTestToken", + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "function": "mint(address,uint256)", + "arguments": [ + "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "12400000000000000000" + ], + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "gas": "0x18507", + "value": "0x0", + "input": "0x40c10f19000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52000000000000000000000000000000000000000000000000ac15a64d4ed80000", + "nonce": "0x1a4", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "function": null, + "arguments": null, + "transaction": { + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "gas": "0x10197", + "value": "0x29a2241af62c0000", + "input": "0x", + "nonce": "0x1a5", + "chainId": "0x2328" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x11436b12e80a550f467e9dd471ceaed6ccbac80947d6ee2fa9ab3bac5831553c", + "transactionIndex": "0x0", + "blockHash": "0xcf8df0182a959216da019155272f259a9f417bc085a21c91cce6f874cd4bcaf3", + "blockNumber": "0x7e4c3", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x0c89e0c4c7fcf8603bafb96b5d7c2d4564e4be2a146d0ee8ff80a84a9f940e2f", + "transactionIndex": "0x0", + "blockHash": "0x2d22f39b521ba338c15b5419cdae4d69076b3422c54b3fa2eaede04995a317e6", + "blockNumber": "0x7e4c6", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0xdf32512dd6bc9e196fb442150b182172e1ce292e" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x747ee", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x3e73ec3499f019074cfef70a79552fbc7376c7902b353cea8720fc5df11f15b2", + "transactionIndex": "0x0", + "blockHash": "0x27fa9e6f914ca42f16bd5bdb652967db2ce001229548ff9f709437ca36afbce2", + "blockNumber": "0x7e4c8", + "gasUsed": "0x747ee", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": null, + "contractAddress": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd" + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x147514", + "logs": [ + { + "address": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "topics": [ + "0xc18dea5f6b30c3fd606e8e38832933e2fa57407dd77800aad0658505ee94df98", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0", + "0x0000000000000000000000000000000000000000000000000000000000000005" + ], + "data": "0xa7e1f8be776b25f953cfd5202e480e9ca280a6f0f1362ddef35cefd805b9c11a", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x1", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x000000000000000000000000b6685d046e34a3260b9098aa6073cd7867e2de1c" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x2", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5d3de0fa15f594659e83f792fff19b5062cbc430ea0e9cf465377cdfaab88454", + "0x000000000000000000000000cec10c48b8d37b6a083000173e3415cc6f86974f" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000003e41424adf6bb69b6271ef9b0541acd59a0d454a" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e800", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000056bc75e2d6310000000000000000000000000000000000000000000000000003635c9adc5dea00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010f0cf064dd59200000", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x000000000000000000000000b524729fbfca5724bfcfbbed70ef3e45b1abd8f1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000012a05f20000000000000000000000000000000000000000000000000000000005d21dba00000000000000000000000000000000000000000000000000000000174876e800000000000000000000000000000000000000000000000000000000174876e800", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x000000000000000000000000df32512dd6bc9e196fb442150b182172e1ce292e" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000001dcd65000000000000000000000000000000000000000000000000000000000077359400000000000000000000000000000000000000000000000000000000012a05f200", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x7", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x9d182ff993316b1c662980e27e42d42fae0bd158f1bed04e9988ec637fea8da4", + "0x0000000000000000000000002e494e1b1138ad260be8bede8e8da5110e5239bd" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000008ac7230489e800000000000000000000000000000000000000000000000000022b1c8c1227a000000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x8", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x1a734774792c149a91deb03650b2a2bc51de7bbab7262857ace6fb1699b43041", + "0x0000000000000000000000000000000000000000000000000000000000000001" + ], + "data": "0x000000000000000000000000000000000000000000000000000000006aab05710000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000001518000000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000002a3000000000000000000000000000000000000000000000000000000000000093a8000000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000003e80000000000000000000000000000000000000000000000000000000000015180", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0x9", + "removed": false + }, + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x4488062cfafbbb2c1d440f13796e120c4522761f74ecade440ee8f31f1bfbee0" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "blockTimestamp": "0x6aab0571", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "logIndex": "0xa", + "removed": false + } + ], + "logsBloom": "0x001000000000800100000000000000040800000000000000000000000000000000000400000000000000000000000000000000020100080008000000000404000000100000000000000010000000008000000000000400000000000000000000000000000204000009000000000008000800080000000000000000000000800200008000000c0000000802000000001000002800000000000000000000000000000010800000000001000000000000000010000000008000008000000000020000000000080008000020400000000000000000000000000000400002010060000000000480000000000000000000000000000000000410000000400000000000", + "transactionHash": "0xd4b435b68e5d68876448db42690ac3ec546b5a4a4c7b6e8200671e4559aecc76", + "transactionIndex": "0x0", + "blockHash": "0x36c6c725c18ff2aec1fdddc669d2b9e593acb7c88f97cdde595394687ddf04bf", + "blockNumber": "0x7e4cb", + "gasUsed": "0x147514", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x018c12ba8b085da81e434b9e4001e07cf48764e9", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xc739", + "logs": [ + { + "address": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x0000000000000000000000000000000000000000000000000000003a35294400", + "blockHash": "0x17f1d915592124a53cb8bae6f9ad21ef1d9e512187e6a3afd45b246fa79ff5bb", + "blockNumber": "0x7e4cd", + "blockTimestamp": "0x6aab0577", + "transactionHash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000012000000004100000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0xa113882318cfdeba3d8fc0cee717e2dba3980f9afb75b7b3357df50f716b3f46", + "transactionIndex": "0x0", + "blockHash": "0x17f1d915592124a53cb8bae6f9ad21ef1d9e512187e6a3afd45b246fa79ff5bb", + "blockNumber": "0x7e4cd", + "gasUsed": "0xc739", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x3e41424adf6bb69b6271ef9b0541acd59a0d454a", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x109e9", + "logs": [ + { + "address": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x00000000000000000000000000000000000000000000000000000013ac97ad00", + "blockHash": "0x8fdf62612cf1da7ed881d37f351d2c94d6ebfbc16799a7e9b65ada50826cac54", + "blockNumber": "0x7e4cf", + "blockTimestamp": "0x6aab057f", + "transactionHash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000080000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000040000000000000000", + "transactionHash": "0xd45bd5960a647b364b07d5560f71e766063780d1570f7a33c8d5908ff0863031", + "transactionIndex": "0x0", + "blockHash": "0x8fdf62612cf1da7ed881d37f351d2c94d6ebfbc16799a7e9b65ada50826cac54", + "blockNumber": "0x7e4cf", + "gasUsed": "0x109e9", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xb524729fbfca5724bfcfbbed70ef3e45b1abd8f1", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x109e9", + "logs": [ + { + "address": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000014628180", + "blockHash": "0x3fd2619543d1d0a65be1bf1ec1dfbb7972e608190db958a587cf2c51f4929c6d", + "blockNumber": "0x7e4d1", + "blockTimestamp": "0x6aab0585", + "transactionHash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000002000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020200000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x868a69df3618f859e85fbef023d1785a1f0a175251f08dc9009815b947f2f305", + "transactionIndex": "0x0", + "blockHash": "0x3fd2619543d1d0a65be1bf1ec1dfbb7972e608190db958a587cf2c51f4929c6d", + "blockNumber": "0x7e4d1", + "gasUsed": "0x109e9", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xdf32512dd6bc9e196fb442150b182172e1ce292e", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0x10a01", + "logs": [ + { + "address": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000d3f026024e015e1ec841a88d983883d4a017ed52" + ], + "data": "0x000000000000000000000000000000000000000000000000ac15a64d4ed80000", + "blockHash": "0xdef889a1914fbe461b0c9a177f5d94c1daab4e770564418b573cfa17105715ff", + "blockNumber": "0x7e4d3", + "blockTimestamp": "0x6aab058f", + "transactionHash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000010000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000002000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0x449550890f6b113cecd809bd89f14a2c07234f77acdd63223ab9306141c0e54a", + "transactionIndex": "0x0", + "blockHash": "0xdef889a1914fbe461b0c9a177f5d94c1daab4e770564418b573cfa17105715ff", + "blockNumber": "0x7e4d3", + "gasUsed": "0x10a01", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0x2e494e1b1138ad260be8bede8e8da5110e5239bd", + "contractAddress": null + }, + { + "type": "0x2", + "status": "0x1", + "cumulativeGasUsed": "0xba7f", + "logs": [ + { + "address": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "topics": [ + "0x5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f62", + "0x0000000000000000000000004fea262782b5be34b18cf24b6ac026215899eec0", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x00000000000000000000000000000000000000000000000029a2241af62c0000", + "blockHash": "0xf503e14bf69b301c143c588e3dd8969141d45fd83252d493605b11a67a527415", + "blockNumber": "0x7e4d5", + "blockTimestamp": "0x6aab0596", + "transactionHash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000040000000000000000008000000000000000000000000000000000000000000000000000000000000020000000800000000000800000008000000000000000000000080020000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000", + "transactionHash": "0xb33b467aafb9583d57b8fab67d5dcc976e01963ba5be65de8b9608a1fdf98cd3", + "transactionIndex": "0x0", + "blockHash": "0xf503e14bf69b301c143c588e3dd8969141d45fd83252d493605b11a67a527415", + "blockNumber": "0x7e4d5", + "gasUsed": "0xba7f", + "effectiveGasPrice": "0x3b9aca01", + "from": "0x4fea262782b5be34b18cf24b6ac026215899eec0", + "to": "0xd3f026024e015e1ec841a88d983883d4a017ed52", + "contractAddress": null + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1789592989926, + "chain": 9000, + "commit": "294de9f" +} \ No newline at end of file diff --git a/contracts/deployments/9000.json b/contracts/deployments/9000.json index ec54f6a..4a43c5f 100644 --- a/contracts/deployments/9000.json +++ b/contracts/deployments/9000.json @@ -1 +1 @@ -{"chainId":9000,"testUsd":"0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a","factory":"0x018c12BA8b085da81E434b9e4001e07CF48764E9","vaultImplementation":"0xE21C7ad3a56D187848F9915bb43f88820278DeA3","demoVault":"0xCC31c7474267ca5600c2D530ebD7657A09c042Dc","deployer":"0x4FEA262782b5BE34B18cf24b6aC026215899EEc0","deployedAtBlock":481946} \ No newline at end of file +{"chainId": 9000, "testUsd": "0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a", "factory": "0x018c12BA8b085da81E434b9e4001e07CF48764E9", "vaultImplementation": "0xE21C7ad3a56D187848F9915bb43f88820278DeA3", "demoVault": "0xD3f026024e015e1eC841a88D983883d4a017ED52", "deployer": "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0", "deployedAtBlock": 481946, "testEur": "0xb524729FbfCA5724BfcfBbEd70eF3e45b1aBD8F1", "testBtc": "0xdF32512Dd6bC9E196fb442150b182172E1Ce292e", "testEth": "0x2e494E1b1138aD260Be8bede8E8dA5110E5239bd"} \ No newline at end of file diff --git a/contracts/script/DemoVault.s.sol b/contracts/script/DemoVault.s.sol new file mode 100644 index 0000000..d4348d3 --- /dev/null +++ b/contracts/script/DemoVault.s.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {Script, console} from "forge-std/Script.sol"; +import {SkurFactory} from "../src/SkurFactory.sol"; +import {SkurTestToken} from "../src/SkurTestToken.sol"; +import {SkurTestUSD} from "../src/SkurTestUSD.sol"; +import {SkurTemplates} from "./SkurTemplates.sol"; +import {AssetLimits, Policy} from "../src/SkurTypes.sol"; + +/// @notice Devnet only: deploys a few more test tokens and a demo vault that holds a realistic mix, +/// so the interfaces have more than one asset to show. +contract DemoVaultScript is Script { + address constant NATIVE = address(0); + + function run() external { + uint256 pk = vm.envUint("PRIVATE_KEY"); + address deployer = vm.addr(pk); + SkurFactory factory = SkurFactory(vm.envAddress("FACTORY")); + SkurTestUSD usd = SkurTestUSD(vm.envAddress("TEST_USD")); + + vm.startBroadcast(pk); + + SkurTestToken eur = new SkurTestToken("Skur Test EUR", "sEUR", 6); + SkurTestToken btc = new SkurTestToken("Skur Test BTC", "sBTC", 8); + SkurTestToken eth = new SkurTestToken("Skur Test ETH", "sETH", 18); + + address[] memory members = new address[](3); + uint8[] memory roles = new uint8[](3); + members[0] = deployer; + roles[0] = 1 | 2 | 4; + members[1] = vm.addr(uint256(keccak256(abi.encode(pk, "approver2")))); + roles[1] = 1 | 2; + members[2] = vm.addr(uint256(keccak256(abi.encode(pk, "guardian")))); + roles[2] = 8; + + address[] memory assets = new address[](5); + AssetLimits[] memory limits = new AssetLimits[](5); + assets[0] = address(usd); + limits[0] = + AssetLimits({approved: true, lowMax: 5_000e6, highMax: 25_000e6, perTxMax: 100_000e6, dailyMax: 100_000e6}); + assets[1] = NATIVE; + limits[1] = + AssetLimits({approved: true, lowMax: 100 ether, highMax: 1_000 ether, perTxMax: 0, dailyMax: 5_000 ether}); + assets[2] = address(eur); + limits[2] = + AssetLimits({approved: true, lowMax: 5_000e6, highMax: 25_000e6, perTxMax: 100_000e6, dailyMax: 100_000e6}); + assets[3] = address(btc); + limits[3] = AssetLimits({approved: true, lowMax: 5e7, highMax: 5e8, perTxMax: 2e9, dailyMax: 5e9}); + assets[4] = address(eth); + limits[4] = + AssetLimits({approved: true, lowMax: 1 ether, highMax: 10 ether, perTxMax: 40 ether, dailyMax: 100 ether}); + + Policy memory policy = SkurTemplates.startup(); + address vault = factory.createVault(keccak256("skur-demo-vault-multi"), members, roles, policy, assets, limits); + + usd.mint(vault, 250_000 * 1e6); + eur.mint(vault, 84_500 * 1e6); + btc.mint(vault, 3_4200_0000); + eth.mint(vault, 12.4 ether); + // transfer() caps at 2300 gas; the vault emits on receive, so forward the full stipend. + (bool ok,) = payable(vault).call{value: 3 ether}(""); + require(ok, "native funding failed"); + + vm.stopBroadcast(); + + console.log("demoVault:", vault); + console.log("testEur:", address(eur)); + console.log("testBtc:", address(btc)); + console.log("testEth:", address(eth)); + } +} diff --git a/contracts/src/SkurTestToken.sol b/contracts/src/SkurTestToken.sol new file mode 100644 index 0000000..f71d72d --- /dev/null +++ b/contracts/src/SkurTestToken.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.28; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +/// @title Skur test token (devnet only) +/// @notice A parameterised stand-in so a demo vault can hold a realistic mix of assets. Anyone can mint. +/// @dev NEVER deploy this to a network with real value. Approving one on a vault is still a policy +/// decision that goes through the policy-change firewall. +contract SkurTestToken is ERC20 { + uint8 private immutable _decimals; + + constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) { + _decimals = decimals_; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} diff --git a/mobile/src/components/TokenMark.tsx b/mobile/src/components/TokenMark.tsx new file mode 100644 index 0000000..0234d83 --- /dev/null +++ b/mobile/src/components/TokenMark.tsx @@ -0,0 +1,13 @@ +import { Text, View } from "react-native"; +import { tokenMark } from "@web/lib/tokens"; +import { F } from "../theme"; + +/** The asset's mark: one colour and glyph per symbol, the same in both interfaces. */ +export function TokenMark({ symbol, size = 40 }: { symbol: string; size?: number }) { + const m = tokenMark(symbol); + return ( + + {m.glyph} + + ); +} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index a1fb1e0..7700f3a 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { Pressable, RefreshControl, Text, View } from "react-native"; import { NATIVE_ASSET } from "@web/config/chain"; import { fmtAmount } from "@web/lib/format"; +import { tokenMark } from "@web/lib/tokens"; import { Mode, ROLE_APPROVER, ROLE_OWNER, Status } from "@web/lib/types"; import type { VaultData } from "@web/lib/vaultReads"; import { needsMe } from "../hooks/useAlerts"; @@ -10,6 +11,7 @@ import { useMyRoles } from "../hooks/useVault"; import { scanBus } from "../lib/scanBus"; import { useStore } from "../state/store"; import { Identicon } from "../components/Identicon"; +import { TokenMark } from "../components/TokenMark"; import { VaultSheet } from "../components/VaultSheet"; import { Address, CircleIcon, Icon, IconButton, Row, Screen, Tape, TopBar, useStyles } from "../components/ui"; import { F, type Palette } from "../theme"; @@ -82,8 +84,8 @@ export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch Tokens {vault.assets.map((a, i) => ( - } - title={a.symbol === "sUSD" ? "Skur Test USD" : a.symbol} subtitle={`${fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of ${a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today`} + } + title={tokenMark(a.symbol).name} subtitle={`${fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of ${a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today`} trailing={{fmtAmount(a.balance, a.decimals)}} onPress={canPropose ? () => nav.navigate("Send", { asset: a.address }) : undefined} last={i === vault.assets.length - 1} /> ))} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx index f02f12a..dcd88b7 100644 --- a/mobile/src/screens/Onboard.tsx +++ b/mobile/src/screens/Onboard.tsx @@ -1,53 +1,80 @@ -import { useState } from "react"; -import { useTheme } from "../state/theme"; -import { Text, View } from "react-native"; +import { useNavigation } from "@react-navigation/native"; +import { useEffect, useState } from "react"; +import { Pressable, Text, View } from "react-native"; import { isAddress } from "viem"; import { SkurFactoryAbi } from "@web/abi/SkurFactory"; import { DEPLOYMENTS } from "@web/config/chain"; import { short } from "@web/lib/format"; import { publicClient } from "../lib/client"; +import { scanBus } from "../lib/scanBus"; import { useStore } from "../state/store"; +import { useTheme } from "../state/theme"; import { Identicon } from "../components/Identicon"; -import { Button, Card, CircleIcon, Field, Input, Logo, Notice, Row, Screen, Tape, TopBar, useStyles } from "../components/ui"; +import { Card, CircleIcon, Icon, IconButton, Input, Logo, Row, Screen, Sheet, TopBar, useStyles } from "../components/ui"; import { F } from "../theme"; -/** First screen: the web logo, then open a vault by address, the demo vault, or one the device signer belongs to. */ +/** Add an account, the way a wallet does it: a short title, then the ways in, as rows. */ export function Onboard() { const C = useTheme(); const s = useStyles(); - const { setVaultAddress, signer, createSigner } = useStore(); + const nav = useNavigation<{ navigate: (n: string) => void }>(); + const { setVaultAddress, signer, createSigner, labels } = useStore(); + const [sheet, setSheet] = useState(false); const [addr, setAddr] = useState(""); - const [mine, setMine] = useState<`0x${string}`[] | null>(null); - const [busy, setBusy] = useState(false); - const [err, setErr] = useState(null); - const findMine = async () => { + const [mine, setMine] = useState<`0x${string}`[]>([]); + const [looking, setLooking] = useState(false); + + useEffect(() => { if (!signer) return; - setBusy(true); setErr(null); - try { const v = await publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }); setMine([...v]); } - catch (e) { setErr((e as Error).message); } finally { setBusy(false); } - }; + setLooking(true); + publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }) + .then((v) => setMine([...v].filter((a) => a.toLowerCase() !== DEPLOYMENTS.demoVault.toLowerCase()))) + .catch(() => setMine([])) + .finally(() => setLooking(false)); + }, [signer]); + + const open = (a: `0x${string}`) => { setSheet(false); void setVaultAddress(a); }; + return ( - } />}> - - Treasury security{"\n"}that assumes{"\n"}compromise - Read its balances, queue and policy. Sign from this phone. - - - - setAddr(t.trim())} placeholder="0x…" mono /> - - + } right={ { scanBus.request((a) => open(a as `0x${string}`)); nav.navigate("Scan"); }} />} />}> + Add a vault + Open one you belong to, or watch any vault by address. + + {signer && ( + <> + Your vaults + + {looking && mine.length === 0 ? } title="Looking up your vaults…" subtitle={short(signer.address)} last /> + : mine.length === 0 ? } title="No vault has this signer yet" subtitle={`Add ${short(signer.address)} as a member`} last /> + : mine.map((v, i) => } title={labels[v.toLowerCase()] ?? "Treasury vault"} subtitle={short(v, 6)} onPress={() => open(v)} chevron last={i === mine.length - 1} />)} + + + )} + + Get started - } title="Demo vault" subtitle={short(DEPLOYMENTS.demoVault, 6)} onPress={() => setVaultAddress(DEPLOYMENTS.demoVault)} chevron /> - {signer ? ( - mine === null ? } title="Vaults this device belongs to" subtitle={`Signer ${short(signer.address)}`} onPress={findMine} trailing={busy ? looking… : undefined} chevron last /> - : mine.length === 0 ? } title="No vault has this signer yet" subtitle={`Add ${short(signer.address)} as a member to sign for one`} last /> - : mine.map((v, i) => } title="Member vault" subtitle={short(v, 6)} onPress={() => setVaultAddress(v)} chevron last={i === mine.length - 1} />) - ) : ( - } title="Create a signer key" subtitle="Kept in this phone's keychain" onPress={() => void createSigner()} chevron last /> - )} + } title="Create a vault" subtitle="Name, template, members" onPress={() => nav.navigate("CreateVault")} chevron /> + } title="Watch a vault" subtitle="Read any vault by its address" onPress={() => setSheet(true)} chevron /> + } title="Demo vault" subtitle={short(DEPLOYMENTS.demoVault, 6)} onPress={() => open(DEPLOYMENTS.demoVault)} chevron /> + {!signer && } title="Create a signer key" subtitle="Kept in this phone's keychain" onPress={() => void createSigner()} chevron last />} + } title="Signers on this phone" subtitle={signer ? short(signer.address) : "None yet"} onPress={() => nav.navigate("Signers")} chevron last={Boolean(signer)} /> - {err ? {err} : null} - Verified contracts. Skur holds no keys and no funds. + + + A + Ark Constellation devnet · chain 9000 + + + setSheet(false)} title="Watch a vault"> + + setAddr(t.trim())} placeholder="0x… vault address" mono autoFocus style={{ flex: 1 }} /> + { setSheet(false); scanBus.request((a) => setAddr(a)); nav.navigate("Scan"); }} /> + + open(addr as `0x${string}`)} + style={({ pressed }) => ({ height: 48, borderRadius: 12, backgroundColor: C.accent, alignItems: "center", justifyContent: "center", flexDirection: "row", gap: 8, opacity: !isAddress(addr) ? 0.4 : pressed ? 0.85 : 1 })}> + + Open vault + + ); } diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index f92ab61..eb8e25e 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import { Pressable, Text, View } from "react-native"; import { scanBus } from "../lib/scanBus"; import { Identicon } from "../components/Identicon"; +import { TokenMark } from "../components/TokenMark"; import { isAddress } from "viem"; import { SkurVaultAbi } from "@web/abi/SkurVault"; import { fmtAmount, fmtBps, fmtDuration, parseAmount, short } from "@web/lib/format"; @@ -78,7 +79,7 @@ export function Send({ vault }: { vault: VaultData }) { {vault.assets.map((a) => ( setAssetAddr(a.address)} style={[{ flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: 12, height: 34, borderRadius: 17, backgroundColor: C.card2 }, a.address === assetAddr && { backgroundColor: C.accent }]}> - + {a.symbol} ))} diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index 4007824..0185997 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -58,14 +58,6 @@ export function Settings({ vault }: { vault: VaultData | undefined }) { ))} - Environment - - } title="Ark Constellation devnet" subtitle="chain 9000" /> - } title="RPC" subtitle={ARK_DEVNET_RPC.replace("https://", "")} /> - } title="Factory" subtitle={
      } /> - } title="Vault implementation" subtitle={
      } /> - } title="Skur V1" subtitle={`demo vault ${short(DEPLOYMENTS.demoVault)}`} last /> - ); diff --git a/web/src/components/ui.tsx b/web/src/components/ui.tsx index 1362339..a9c67e2 100644 --- a/web/src/components/ui.tsx +++ b/web/src/components/ui.tsx @@ -1,6 +1,7 @@ import { useEffect, useState, type ReactNode } from "react"; import { explorerAddress, explorerTx } from "../config/chain"; import { short } from "../lib/format"; +import { tokenMark } from "../lib/tokens"; import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "../lib/types"; import type { TxState } from "../hooks/useTx"; import { IconCheck, IconClose, IconCopy, IconExternal } from "./icons"; @@ -178,12 +179,10 @@ export function Switch({ on, onChange, label }: { on: boolean; onChange: (v: boo } export function TokenIcon({ symbol, size = 32 }: { symbol: string; size?: number }) { - const s = symbol.toUpperCase(); - const stable = s.includes("USD"); - const native = s === "KASH"; + const m = tokenMark(symbol); return ( - - {stable ? "$" : s.slice(0, 1)} + + {m.glyph} ); } diff --git a/web/src/config/chain.ts b/web/src/config/chain.ts index cf97a63..5bc6215 100644 --- a/web/src/config/chain.ts +++ b/web/src/config/chain.ts @@ -27,6 +27,9 @@ export const arkDevnet = defineChain({ export type Deployments = { chainId: number; testUsd: `0x${string}`; + testEur?: `0x${string}`; + testBtc?: `0x${string}`; + testEth?: `0x${string}`; factory: `0x${string}`; vaultImplementation: `0x${string}`; demoVault: `0x${string}`; diff --git a/web/src/config/deployments.json b/web/src/config/deployments.json index ec54f6a..bbf8be2 100644 --- a/web/src/config/deployments.json +++ b/web/src/config/deployments.json @@ -1 +1,12 @@ -{"chainId":9000,"testUsd":"0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a","factory":"0x018c12BA8b085da81E434b9e4001e07CF48764E9","vaultImplementation":"0xE21C7ad3a56D187848F9915bb43f88820278DeA3","demoVault":"0xCC31c7474267ca5600c2D530ebD7657A09c042Dc","deployer":"0x4FEA262782b5BE34B18cf24b6aC026215899EEc0","deployedAtBlock":481946} \ No newline at end of file +{ + "chainId": 9000, + "testUsd": "0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a", + "factory": "0x018c12BA8b085da81E434b9e4001e07CF48764E9", + "vaultImplementation": "0xE21C7ad3a56D187848F9915bb43f88820278DeA3", + "demoVault": "0xD3f026024e015e1eC841a88D983883d4a017ED52", + "deployer": "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0", + "deployedAtBlock": 481946, + "testEur": "0xb524729FbfCA5724BfcfBbEd70eF3e45b1aBD8F1", + "testBtc": "0xdF32512Dd6bC9E196fb442150b182172E1Ce292e", + "testEth": "0x2e494E1b1138aD260Be8bede8E8dA5110E5239bd" +} \ No newline at end of file diff --git a/web/src/lib/tokens.ts b/web/src/lib/tokens.ts new file mode 100644 index 0000000..1a406c5 --- /dev/null +++ b/web/src/lib/tokens.ts @@ -0,0 +1,17 @@ +/** + * Marks for the assets a Skur vault can hold. Devnet tokens have no brand, so each carries a + * distinct colour and glyph; both interfaces draw the same mark for the same symbol. + */ +export type TokenMark = { name: string; glyph: string; bg: string; fg: string }; + +const MARKS: Record = { + sUSD: { name: "Skur Test USD", glyph: "$", bg: "#16a34a", fg: "#ffffff" }, + sEUR: { name: "Skur Test EUR", glyph: "€", bg: "#2563eb", fg: "#ffffff" }, + sBTC: { name: "Skur Test BTC", glyph: "₿", bg: "#f7931a", fg: "#ffffff" }, + sETH: { name: "Skur Test ETH", glyph: "Ξ", bg: "#5b5bd6", fg: "#ffffff" }, + KASH: { name: "Ark KASH", glyph: "◈", bg: "#ffd000", fg: "#101418" }, +}; + +export function tokenMark(symbol: string): TokenMark { + return MARKS[symbol] ?? { name: symbol, glyph: symbol.replace(/^s/, "").slice(0, 1).toUpperCase(), bg: "#64748b", fg: "#ffffff" }; +} diff --git a/web/src/pages/Assets.tsx b/web/src/pages/Assets.tsx index a688fd5..957b11c 100644 --- a/web/src/pages/Assets.tsx +++ b/web/src/pages/Assets.tsx @@ -1,4 +1,5 @@ import { useState } from "react"; +import { tokenMark } from "../lib/tokens"; import { NATIVE_ASSET } from "../config/chain"; import type { VaultData } from "../hooks/useVault"; import { fmtAmount, fmtRelative } from "../lib/format"; @@ -52,7 +53,7 @@ export function Assets({ vault, onSend, onNavigate }: { vault: VaultData; onSend
      -
      {a.symbol === "KASH" ? "KASH" : a.symbol === "sUSD" ? "Skur Test USD" : a.symbol}
      +
      {tokenMark(a.symbol).name}
      {a.address === NATIVE_ASSET ? "native token" :
      }
      diff --git a/web/src/pages/Overview.tsx b/web/src/pages/Overview.tsx index 51e751d..21ddf4b 100644 --- a/web/src/pages/Overview.tsx +++ b/web/src/pages/Overview.tsx @@ -1,4 +1,5 @@ import { useState } from "react"; +import { tokenMark } from "../lib/tokens"; import { NATIVE_ASSET } from "../config/chain"; import type { VaultData } from "../hooks/useVault"; import { fmtAmount, fmtDuration } from "../lib/format"; @@ -73,7 +74,7 @@ export function Overview({ vault, onChanged, onNavigate, onNewTransaction }: { v
    1. -
      {a.symbol === "KASH" ? "KASH" : a.symbol === "sUSD" ? "Skur Test USD" : a.symbol}
      +
      {tokenMark(a.symbol).name}
      {fmtAmount(a.balance, a.decimals)} {a.symbol}
      diff --git a/web/src/styles.css b/web/src/styles.css index 6e8d415..f905a70 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -286,9 +286,8 @@ h1, h2, h3, .display, .balance-card .amount, .scorecard .v, .stats .v { font-fam .list .title { font-weight: 700; } .list .sub { font-size: 12px; color: var(--text-2); } .list .right { text-align: right; } -.token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; background: var(--panel-2); color: var(--text); font-weight: 700; font-size: 12px; } -.token-ico.stable { background: #2775ca; color: #fff; } -.token-ico.native { background: var(--accent); color: var(--accent-contrast); } +/* Colour and glyph come from lib/tokens.ts, so both interfaces draw an asset the same way. */ +.token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; line-height: 1; } table { width: 100%; border-collapse: collapse; } th, td { text-align: left; padding: 14px 24px; border-top: 1px solid var(--border); vertical-align: middle; } thead th { border-top: 0; color: var(--text-2); font-weight: 500; font-size: 13px; } From 692bb7859186223138f080d13f35676b58dfc40d Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 17 Sep 2026 03:08:10 +0100 Subject: [PATCH 11/44] feat(web): show the phone app on the site The site described a mobile app nobody could see. It now shows one. A phone mockup component draws the app's own screens inside a device frame: the vault with its five assets, a payment being confirmed, and the queue. They are drawn rather than screenshotted, so they stay sharp at any size, follow the design system and cannot go stale against a screenshot. A Mobile page joins the nav with the three phones, what the app does on a phone, and how its keys work. The landing page gains a strip beside the FAQ that leads to it. Two fixes found while building it: a marketing page opened at whatever scroll position the previous one had, and the phone frames were scaled with a value calc() produced as a length, which scale() rejects, so they rendered full size and overlapped. --- web/src/App.tsx | 12 ++-- web/src/components/MarketingShell.tsx | 5 +- web/src/components/PhoneMockup.tsx | 90 +++++++++++++++++++++++++++ web/src/pages/Landing.tsx | 22 ++++++- web/src/pages/Mobile.tsx | 68 ++++++++++++++++++++ web/src/styles.css | 67 ++++++++++++++++++++ 6 files changed, 257 insertions(+), 7 deletions(-) create mode 100644 web/src/components/PhoneMockup.tsx create mode 100644 web/src/pages/Mobile.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index 5144dc1..0895075 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -14,6 +14,7 @@ import { Policies } from "./pages/Policies"; import { Product } from "./pages/Product"; import { Security } from "./pages/Security"; import { SecurityPage } from "./pages/SecurityPage"; +import { Mobile } from "./pages/Mobile"; import { Settings } from "./pages/Settings"; import { Simulator } from "./pages/Simulator"; import { Solutions } from "./pages/Solutions"; @@ -24,11 +25,11 @@ import { useVaultAddress } from "./state/vaultAddress"; /** * Routes, patterned on safe.global -> app.safe.global: - * #/ #/product #/solutions #/security marketing + * #/ #/product #/solutions #/security #/mobile marketing * #/welcome #/new-vault onboarding * #/app/ the vault app */ -type Route = { kind: "landing" } | { kind: "product" } | { kind: "solutions" } | { kind: "securitypage" } | { kind: "welcome" } | { kind: "create" } | { kind: "app"; page: AppPage }; +type Route = { kind: "landing" } | { kind: "product" } | { kind: "solutions" } | { kind: "securitypage" } | { kind: "mobile" } | { kind: "welcome" } | { kind: "create" } | { kind: "app"; page: AppPage }; const APP_PAGES: AppPage[] = ["overview", "assets", "transactions", "addressbook", "members", "settings", "policies", "security", "simulator"]; const LEGACY: Record = { home: "overview", recipients: "addressbook" }; @@ -39,6 +40,7 @@ function readRoute(): Route { if (raw === "product") return { kind: "product" }; if (raw === "solutions") return { kind: "solutions" }; if (raw === "security") return { kind: "securitypage" }; + if (raw === "mobile") return { kind: "mobile" }; if (raw === "welcome") return { kind: "welcome" }; if (raw === "new-vault") return { kind: "create" }; const seg = raw.replace(/^app\//, ""); @@ -48,7 +50,7 @@ function readRoute(): Route { } function go(route: Route) { - const hash = route.kind === "landing" ? "#/" : route.kind === "product" ? "#/product" : route.kind === "solutions" ? "#/solutions" : route.kind === "securitypage" ? "#/security" : route.kind === "welcome" ? "#/welcome" : route.kind === "create" ? "#/new-vault" : `#/app/${route.page}`; + const hash = route.kind === "landing" ? "#/" : route.kind === "product" ? "#/product" : route.kind === "solutions" ? "#/solutions" : route.kind === "securitypage" ? "#/security" : route.kind === "mobile" ? "#/mobile" : route.kind === "welcome" ? "#/welcome" : route.kind === "create" ? "#/new-vault" : `#/app/${route.page}`; if (window.location.hash !== hash) window.location.hash = hash; window.scrollTo({ top: 0 }); } @@ -82,7 +84,8 @@ export default function App() { return () => window.removeEventListener("hashchange", onHash); }, []); - const marketing = route.kind === "landing" || route.kind === "product" || route.kind === "solutions" || route.kind === "securitypage"; + useEffect(() => { window.scrollTo(0, 0); }, [route.kind, "page" in route ? route.page : ""]); + const marketing = route.kind === "landing" || route.kind === "product" || route.kind === "solutions" || route.kind === "securitypage" || route.kind === "mobile"; useEffect(() => { document.documentElement.setAttribute("data-theme", marketing ? "light" : themeState.theme); }, [marketing, themeState.theme]); @@ -96,6 +99,7 @@ export default function App() { if (route.kind === "product") return ; if (route.kind === "solutions") return ; if (route.kind === "securitypage") return ; + if (route.kind === "mobile") return ; return ( diff --git a/web/src/components/MarketingShell.tsx b/web/src/components/MarketingShell.tsx index 2348a9f..55491a4 100644 --- a/web/src/components/MarketingShell.tsx +++ b/web/src/components/MarketingShell.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from "react"; import { useScrolled } from "../lib/motion"; import { IconChevronRight } from "./icons"; -export type MarketingPage = "landing" | "product" | "solutions" | "security"; +export type MarketingPage = "landing" | "product" | "solutions" | "security" | "mobile"; /** Nav, closing CTA and footer shared by every marketing page. */ export function MarketingShell({ page, onLaunch, children, hideCta = false }: { page: MarketingPage; onLaunch: () => void; children: ReactNode; hideCta?: boolean }) { @@ -16,6 +16,7 @@ export function MarketingShell({ page, onLaunch, children, hideCta = false }: { Product Solutions Security + Mobile FAQ GitHub ↗ @@ -44,7 +45,7 @@ export function MarketingShell({ page, onLaunch, children, hideCta = false }: {
      Skur

      Programmable treasury security for onchain businesses.

      - + diff --git a/web/src/components/PhoneMockup.tsx b/web/src/components/PhoneMockup.tsx new file mode 100644 index 0000000..ba27ab7 --- /dev/null +++ b/web/src/components/PhoneMockup.tsx @@ -0,0 +1,90 @@ +import { tokenMark } from "../lib/tokens"; + +type Variant = "home" | "queue" | "confirm"; + +const TOKENS: Array<[string, string]> = [ + ["sUSD", "250,000"], + ["KASH", "3"], + ["sEUR", "84,500"], + ["sBTC", "3.42"], + ["sETH", "12.4"], +]; + +/** The phone app, drawn rather than screenshotted, so it stays sharp and follows the design system. */ +export function PhoneMockup({ variant = "home", label }: { variant?: Variant; label?: string }) { + return ( +
      +
      + +
      {variant === "home" ? : variant === "queue" ? : }
      +
      +
      + ); +} + +function Mark({ symbol, size = 26 }: { symbol: string; size?: number }) { + const m = tokenMark(symbol); + return {m.glyph}; +} + +function Home() { + return ( + <> +
      + Treasury vault⌄ + +
      +
      1Pending transactions›
      +
      AArk devnet0xD3f0…ED52
      +
      250,000sUSD
      +
      ↗ Send↙ Receive
      +
      Tokens
      + {TOKENS.slice(0, 4).map(([sym, amt]) => ( +
      + + {tokenMark(sym).name}0 of cap today + {amt} +
      + ))} + + ); +} + +function Queue() { + return ( + <> +
      Transactions+
      +
      Queue · 2History
      +
      All typesTransfersGovernance
      +
      Sep 17, 2026
      + {[["↗", "Send", "12,000 sUSD to 0x7c4f…41e2", "1 of 2", "warn"], ["≡", "Policy update", "tightens every control", "0 of 1", "warn"]].map(([g, t, d, s, tone]) => ( +
      + {g} + {t}{d} + {s} +
      + ))} + + ); +} + +function Confirm() { + return ( + <> +
      ←Confirm
      +
      + + −12,000 sUSD + to 0x7c4f…41e2 · just now + 1 of 2 +
      +
      +
      To0x7c4f…41e2
      +
      NetworkArk devnet
      +
      +
      ⛨Risk reviewnew recipient · above routineHigh
      +
      ◎Confirmationswaiting for one more1/2
      +
      ✎ Confirm0x4FEA…EEc0›
      + + ); +} diff --git a/web/src/pages/Landing.tsx b/web/src/pages/Landing.tsx index 613d09c..04b814c 100644 --- a/web/src/pages/Landing.tsx +++ b/web/src/pages/Landing.tsx @@ -1,6 +1,7 @@ import { useEffect } from "react"; import { MarketingShell } from "../components/MarketingShell"; import { AppMockup } from "../components/Mockup"; +import { PhoneMockup } from "../components/PhoneMockup"; import { ScoreTicker } from "../components/Ticker"; import { Reveal } from "../components/Reveal"; import { IconArrowRight, IconCheck, IconChevronRight } from "../components/icons"; @@ -259,9 +260,28 @@ export function Landing({ onLaunch }: { onLaunch: () => void }) {
      +
      +
      + +
      +
      07 / On the phone
      +

      Skur goes with you

      +

      Read the treasury, review what is waiting and sign with a key kept in the phone's keychain, behind Face ID. iOS and Android, sharing this site's risk engine and policy rules.

      +
        +
      • Notified the moment a payment needs you
      • +
      • Checked against the policy before you sign
      • +
      • Guardians can freeze from anywhere
      • +
      + See the mobile app +
      +
      +
      +
      +
      +
      -
      07 / Questions

      Questions, answered plainly

      +
      08 / Questions

      Questions, answered plainly

      {FAQ.map(([q, a]) => ( diff --git a/web/src/pages/Mobile.tsx b/web/src/pages/Mobile.tsx new file mode 100644 index 0000000..1e85a10 --- /dev/null +++ b/web/src/pages/Mobile.tsx @@ -0,0 +1,68 @@ +import { MarketingShell, SubHero } from "../components/MarketingShell"; +import { PhoneMockup } from "../components/PhoneMockup"; +import { Reveal } from "../components/Reveal"; +import { IconBook, IconClock, IconGuard, IconLab, IconShield, IconTx } from "../components/icons"; + +export function Mobile({ onLaunch }: { onLaunch: () => void }) { + return ( + + The vault
      in your pocket} sub="Read the treasury, review what is waiting, and sign with the key on your phone. The same contracts, the same policy, no server in between." onLaunch={onLaunch}> + Build it yourself +
      + +
      +
      + + + + + +
      +
      + +
      +
      + +
      01 / On the phone
      +

      Everything the desktop does

      +

      Balances, the queue, the policy editor, members, the address book, the attack simulator and recovery. Nothing is read-only because you are on a phone.

      +
      + +

      Sign where you are

      A key created on the phone and kept in its keychain, behind Face ID or Touch ID. Nothing leaves the device but a signed transaction.

      +

      Checked before you sign

      Every payment is simulated against the vault first, so a refusal reads as plain language rather than a failed transaction.

      +

      Told when you are needed

      A notification when a proposal newly needs your confirmation, and a tap takes you straight to it.

      +

      Freeze from anywhere

      Guardians can raise the mode or veto a proposal from the phone the moment something looks wrong.

      +

      Scan, do not type

      The camera reads a vault or recipient address, so a 42-character address is never typed on a phone keyboard.

      +

      Test the policy

      The same attack scenarios as the desktop simulator, run against the live policy or any template.

      +
      +
      +
      + +
      +
      + +
      02 / Keys
      +

      No wallet connection to lose

      +

      The phone holds its own signer. Give that address a role in the vault and it signs; without a role the app is a reader.

      +
      + +

      Created on the device

      Generated on the phone or imported, stored in the keychain, never synced anywhere.

      +

      Several keys, one phone

      Hold an approver key and a guardian key side by side and choose which one signs.

      +

      Biometrics before every signature

      Face ID or Touch ID gates each signature, and can be turned off for a device you keep offline.

      +

      Losing the phone is recoverable

      Guardians replace a lost signer after a delay any owner can cancel. The policy is untouched.

      +
      +
      +
      + +
      +
      + +

      Built with Expo and React Native

      +

      iOS and Android from one codebase, sharing the risk engine, policy rules and contract reads with this website. Not on the stores yet: build it from the repository.

      + Read the mobile README +
      +
      +
      +
      + ); +} diff --git a/web/src/styles.css b/web/src/styles.css index f905a70..2300d8e 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -718,3 +718,70 @@ input:read-only { color: var(--text-2); } .mode-strip.elevated { background: #ffd000; } .mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } @media (prefers-reduced-motion: reduce) { .tape.run, .mark-hl, .ticker .prog.on i, .ticker .why li, .ticker .tier { animation: none; } .mark-hl { background-size: 100% 100%; } .ticker .prog.on i { width: 100%; } } + +/* ================================================================== phone mockups (marketing) */ +/* One intrinsic size, scaled as a whole, so the content never reflows or clips at smaller sizes. */ +/* --pwn is unitless: dividing two lengths in calc() yields a length, and scale() would reject it. */ +.phone { --pwn: 268; --scale: calc(var(--pwn) / 268); position: relative; width: calc(var(--pwn) * 1px); height: calc(548px * var(--scale)); flex: none; } +.phone-frame { position: absolute; top: 0; left: 0; width: 268px; height: 548px; transform: scale(var(--scale)); transform-origin: top left; border-radius: 40px; background: #101418; padding: 9px; box-shadow: 0 30px 70px rgba(16,20,24,0.28); } +.phone-frame .notch { position: absolute; top: 9px; left: 50%; transform: translateX(-50%); width: 92px; height: 24px; background: #101418; border-radius: 0 0 14px 14px; z-index: 2; } +.phone-screen { width: 100%; height: 100%; border-radius: 32px; background: #fff; overflow: hidden; padding: 34px 14px 10px; font-size: 11px; color: #101418; display: flex; flex-direction: column; gap: 7px; } +.phone-screen b { font-weight: 700; } +.p-top { display: flex; align-items: center; gap: 7px; font-size: 12px; } +.p-ident { width: 22px; height: 22px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #2ec27e); flex: none; } +.p-chev { color: #98a2b3; margin-left: auto; } +.p-icons { display: flex; gap: 5px; margin-left: 4px; } +.p-icons i { width: 20px; height: 20px; border-radius: 50%; background: #f1f3f5; display: block; } +.p-icons i.dot { position: relative; } +.p-icons i.dot::after { content: ""; position: absolute; top: 1px; right: 1px; width: 6px; height: 6px; border-radius: 50%; background: #ffd000; } +.p-banner { display: flex; align-items: center; gap: 7px; background: #fff6cc; color: #8a6d00; border-radius: 10px; padding: 7px 9px; font-weight: 700; } +.p-banner .n { width: 16px; height: 16px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 10px; } +.p-chain { display: flex; align-items: center; gap: 6px; font-weight: 700; } +.p-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-weight: 400; } +.p-a { width: 15px; height: 15px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 9px; font-weight: 800; } +.p-balance { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; } +.p-balance small { font-size: 13px; color: #667085; margin-left: 6px; } +.p-actions { display: flex; gap: 6px; } +.p-actions span { flex: 1; text-align: center; padding: 8px 0; border-radius: 10px; background: #f1f3f5; font-weight: 700; } +.p-actions .go { background: #ffd000; } +.p-label { font-family: "DM Mono", monospace; font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 2px; } +.p-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid #f1f3f5; } +.p-row.tight { border-bottom: 0; background: #f6f7f9; border-radius: 10px; padding: 7px 8px; } +.p-mark, .p-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } +.p-circle { width: 24px; height: 24px; background: #f1f3f5; font-size: 11px; } +.p-circle.sm { width: 20px; height: 20px; } +.p-name { display: flex; flex-direction: column; flex: 1; font-weight: 700; min-width: 0; } +.p-name small { font-weight: 400; color: #667085; font-size: 10px; } +.p-badge { background: #f1f3f5; color: #667085; border-radius: 99px; padding: 2px 7px; font-weight: 700; font-size: 10px; } +.p-badge.warn { background: #fff3d6; color: #a86a00; } +.p-title { font-family: "Space Grotesk", sans-serif; font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px; } +.p-title .p-plus { margin-left: auto; width: 22px; height: 22px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 13px; } +.p-tabs { display: flex; gap: 14px; border-bottom: 1px solid #f1f3f5; padding-bottom: 5px; } +.p-tabs b { border-bottom: 2px solid #ffd000; padding-bottom: 4px; } +.p-tabs span { color: #98a2b3; } +.p-chips { display: flex; gap: 5px; } +.p-chips b, .p-chips span { border-radius: 99px; padding: 3px 8px; font-size: 10px; background: #f1f3f5; color: #667085; } +.p-chips b { background: #ffd000; color: #101418; } +.p-hero { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 2px 0; } +.p-hero b { font-family: "Space Grotesk", sans-serif; font-size: 20px; letter-spacing: -0.02em; } +.p-hero small { color: #667085; } +.p-card { background: #f6f7f9; border-radius: 12px; padding: 4px 10px; } +.p-kv { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eceef2; } +.p-kv:last-child { border-bottom: 0; } +.p-kv span { color: #667085; } +.p-sign { margin-top: auto; margin-bottom: 2px; background: #ffd000; border-radius: 12px; padding: 11px 12px; display: flex; align-items: center; gap: 8px; font-weight: 700; } +.p-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 2px 7px; font-family: "DM Mono", monospace; font-size: 9px; } +.phones { display: flex; gap: 28px; justify-content: center; align-items: flex-end; flex-wrap: wrap; } +.phones .phone:nth-child(2) { transform: translateY(-22px); } +@media (max-width: 860px) { .phones .phone:nth-child(2) { transform: none; } .phone { --pwn: 232; } } +/* The landing's mobile strip: copy on the left, two phones on the right, the card sized by both. */ +.mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } +.mstrip h2 { text-align: left; margin-bottom: 16px; } +.mstrip p { color: #6c757d; max-width: 380px; margin-bottom: 26px; } +.mstrip ul { list-style: none; padding: 0; margin: 0 0 26px; display: flex; flex-direction: column; gap: 14px; font-size: 17px; font-weight: 700; color: #212529; } +.mstrip ul li { display: flex; gap: 12px; align-items: center; } +.mstrip ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 24px; height: 24px; flex: none; } +.phones.two { display: flex; gap: 16px; align-items: flex-start; } +.phones.two .phone { --pwn: 196; } +.phones.two .phone:nth-child(2) { margin-top: 30px; } +@media (max-width: 980px) { .mstrip { grid-template-columns: 1fr; } .phones.two { justify-content: center; } .phones.two .phone:nth-child(2) { display: none; } } From 4fdb0d69150dc36ea37e378f05e50bd6513d919a Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 17 Sep 2026 03:27:37 +0100 Subject: [PATCH 12/44] design(web): phone mockups drawn at true device scale The first pass squeezed the app into a small frame: type shrank to eleven pixels, rows crowded, the tab bar was missing and the amounts clipped at the screen edge. The mockups are now authored at a real device size, a 393 by 852 point screen inside a 12 point bezel, and scaled as a unit, so every size is the app's own. They gain what makes a device read as one: the status bar, the Dynamic Island, the home indicator and the bottom tab bar with its pending badge. Content matches the app screen for screen, including the five assets with their marks and the sticky sign bar. --- web/src/components/PhoneMockup.tsx | 136 +++++++++++++++++++---------- web/src/styles.css | 132 ++++++++++++++++------------ 2 files changed, 165 insertions(+), 103 deletions(-) diff --git a/web/src/components/PhoneMockup.tsx b/web/src/components/PhoneMockup.tsx index ba27ab7..8bc36b9 100644 --- a/web/src/components/PhoneMockup.tsx +++ b/web/src/components/PhoneMockup.tsx @@ -2,48 +2,82 @@ import { tokenMark } from "../lib/tokens"; type Variant = "home" | "queue" | "confirm"; -const TOKENS: Array<[string, string]> = [ - ["sUSD", "250,000"], - ["KASH", "3"], - ["sEUR", "84,500"], - ["sBTC", "3.42"], - ["sETH", "12.4"], +const TOKENS: Array<[string, string, string]> = [ + ["sUSD", "250,000", "0 of 100,000 today"], + ["KASH", "3", "0 of 5,000 today"], + ["sEUR", "84,500", "0 of 100,000 today"], + ["sBTC", "3.42", "0 of 50 today"], ]; -/** The phone app, drawn rather than screenshotted, so it stays sharp and follows the design system. */ -export function PhoneMockup({ variant = "home", label }: { variant?: Variant; label?: string }) { +/** + * The phone app, drawn at true device scale (393 x 852) and scaled as a unit, so the type sizes and + * spacing are the app's own rather than a squeezed approximation. + */ +export function PhoneMockup({ variant = "home", width = 268, label }: { variant?: Variant; width?: number; label?: string }) { return ( -
      -
      - -
      {variant === "home" ? : variant === "queue" ? : }
      +
      +
      +
      + +
      {variant === "home" ? : variant === "queue" ? : }
      + {variant === "confirm" ? null : } + +
      +
      ); } -function Mark({ symbol, size = 26 }: { symbol: string; size?: number }) { +function StatusBar() { + return ( +
      + 9:41 + + + + + +
      + ); +} + +function TabBar({ active }: { active: number }) { + return ( +
      + {["⌂", "⇄", "⚙"].map((g, i) => ( + + {g} + {i === 1 ? 1 : null} + + ))} +
      + ); +} + +function Mark({ symbol, size = 40 }: { symbol: string; size?: number }) { const m = tokenMark(symbol); - return {m.glyph}; + return {m.glyph}; } function Home() { return ( <> -
      - Treasury vault⌄ - +
      + 1/2 + Treasury vault⌄ +
      -
      1Pending transactions›
      -
      AArk devnet0xD3f0…ED52
      -
      250,000sUSD
      -
      ↗ Send↙ Receive
      -
      Tokens
      - {TOKENS.slice(0, 4).map(([sym, amt]) => ( -
      +
      1Pending transactions›
      +
      AArk devnet0xD3f0…ED52
      +
      250,000sUSD
      +
      ↗ Send↙ Receive
      +
      Tokens
      + {TOKENS.map(([sym, amt, sub]) => ( +
      - {tokenMark(sym).name}0 of cap today - {amt} + {tokenMark(sym).name}{sub} + {amt}
      ))} @@ -53,17 +87,20 @@ function Home() { function Queue() { return ( <> -
      Transactions+
      -
      Queue · 2History
      -
      All typesTransfersGovernance
      -
      Sep 17, 2026
      - {[["↗", "Send", "12,000 sUSD to 0x7c4f…41e2", "1 of 2", "warn"], ["≡", "Policy update", "tightens every control", "0 of 1", "warn"]].map(([g, t, d, s, tone]) => ( -
      - {g} - {t}{d} - {s} -
      - ))} +
      Transactions+
      +
      Queue · 2History
      +
      All typesTransfersGovernance
      +
      Sep 17, 2026
      +
      + {[["↗", "Send", "12,000 sUSD to 0x7c4f…41e2", "1 of 2"], ["≡", "Policy update", "tightens every control", "0 of 1"]].map(([g, t, d, s], i) => ( +
      + {g} + {t}{d} + {s} + › +
      + ))} +
      ); } @@ -71,20 +108,23 @@ function Queue() { function Confirm() { return ( <> -
      ←Confirm
      -
      - +
      ←Confirm transaction
      +
      + ↗ −12,000 sUSD - to 0x7c4f…41e2 · just now - 1 of 2 + Send · to 0x7c4f…41e2 + 1 of 2 confirmations +
      +
      +
      To0x7c4f…41e2
      +
      PurposeInvoice 1042
      +
      NetworkArk devnet · 9000
      -
      -
      To0x7c4f…41e2
      -
      NetworkArk devnet
      +
      +
      ⛨Risk reviewnever paid · above routineHigh›
      +
      ◎Confirmationsone more signer needed1/2›
      -
      ⛨Risk reviewnew recipient · above routineHigh
      -
      ◎Confirmationswaiting for one more1/2
      -
      ✎ Confirm0x4FEA…EEc0›
      +
      ✎Confirm0x4FEA…EEc0›
      ); } diff --git a/web/src/styles.css b/web/src/styles.css index 2300d8e..2ca38ef 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -719,61 +719,83 @@ input:read-only { color: var(--text-2); } .mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } @media (prefers-reduced-motion: reduce) { .tape.run, .mark-hl, .ticker .prog.on i, .ticker .why li, .ticker .tier { animation: none; } .mark-hl { background-size: 100% 100%; } .ticker .prog.on i { width: 100%; } } -/* ================================================================== phone mockups (marketing) */ -/* One intrinsic size, scaled as a whole, so the content never reflows or clips at smaller sizes. */ -/* --pwn is unitless: dividing two lengths in calc() yields a length, and scale() would reject it. */ -.phone { --pwn: 268; --scale: calc(var(--pwn) / 268); position: relative; width: calc(var(--pwn) * 1px); height: calc(548px * var(--scale)); flex: none; } -.phone-frame { position: absolute; top: 0; left: 0; width: 268px; height: 548px; transform: scale(var(--scale)); transform-origin: top left; border-radius: 40px; background: #101418; padding: 9px; box-shadow: 0 30px 70px rgba(16,20,24,0.28); } -.phone-frame .notch { position: absolute; top: 9px; left: 50%; transform: translateX(-50%); width: 92px; height: 24px; background: #101418; border-radius: 0 0 14px 14px; z-index: 2; } -.phone-screen { width: 100%; height: 100%; border-radius: 32px; background: #fff; overflow: hidden; padding: 34px 14px 10px; font-size: 11px; color: #101418; display: flex; flex-direction: column; gap: 7px; } -.phone-screen b { font-weight: 700; } -.p-top { display: flex; align-items: center; gap: 7px; font-size: 12px; } -.p-ident { width: 22px; height: 22px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #2ec27e); flex: none; } -.p-chev { color: #98a2b3; margin-left: auto; } -.p-icons { display: flex; gap: 5px; margin-left: 4px; } -.p-icons i { width: 20px; height: 20px; border-radius: 50%; background: #f1f3f5; display: block; } -.p-icons i.dot { position: relative; } -.p-icons i.dot::after { content: ""; position: absolute; top: 1px; right: 1px; width: 6px; height: 6px; border-radius: 50%; background: #ffd000; } -.p-banner { display: flex; align-items: center; gap: 7px; background: #fff6cc; color: #8a6d00; border-radius: 10px; padding: 7px 9px; font-weight: 700; } -.p-banner .n { width: 16px; height: 16px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 10px; } -.p-chain { display: flex; align-items: center; gap: 6px; font-weight: 700; } -.p-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-weight: 400; } -.p-a { width: 15px; height: 15px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 9px; font-weight: 800; } -.p-balance { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; } -.p-balance small { font-size: 13px; color: #667085; margin-left: 6px; } -.p-actions { display: flex; gap: 6px; } -.p-actions span { flex: 1; text-align: center; padding: 8px 0; border-radius: 10px; background: #f1f3f5; font-weight: 700; } -.p-actions .go { background: #ffd000; } -.p-label { font-family: "DM Mono", monospace; font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 2px; } -.p-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid #f1f3f5; } -.p-row.tight { border-bottom: 0; background: #f6f7f9; border-radius: 10px; padding: 7px 8px; } -.p-mark, .p-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } -.p-circle { width: 24px; height: 24px; background: #f1f3f5; font-size: 11px; } -.p-circle.sm { width: 20px; height: 20px; } -.p-name { display: flex; flex-direction: column; flex: 1; font-weight: 700; min-width: 0; } -.p-name small { font-weight: 400; color: #667085; font-size: 10px; } -.p-badge { background: #f1f3f5; color: #667085; border-radius: 99px; padding: 2px 7px; font-weight: 700; font-size: 10px; } -.p-badge.warn { background: #fff3d6; color: #a86a00; } -.p-title { font-family: "Space Grotesk", sans-serif; font-size: 18px; font-weight: 700; display: flex; align-items: center; gap: 8px; } -.p-title .p-plus { margin-left: auto; width: 22px; height: 22px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 13px; } -.p-tabs { display: flex; gap: 14px; border-bottom: 1px solid #f1f3f5; padding-bottom: 5px; } -.p-tabs b { border-bottom: 2px solid #ffd000; padding-bottom: 4px; } -.p-tabs span { color: #98a2b3; } -.p-chips { display: flex; gap: 5px; } -.p-chips b, .p-chips span { border-radius: 99px; padding: 3px 8px; font-size: 10px; background: #f1f3f5; color: #667085; } -.p-chips b { background: #ffd000; color: #101418; } -.p-hero { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 2px 0; } -.p-hero b { font-family: "Space Grotesk", sans-serif; font-size: 20px; letter-spacing: -0.02em; } -.p-hero small { color: #667085; } -.p-card { background: #f6f7f9; border-radius: 12px; padding: 4px 10px; } -.p-kv { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eceef2; } -.p-kv:last-child { border-bottom: 0; } -.p-kv span { color: #667085; } -.p-sign { margin-top: auto; margin-bottom: 2px; background: #ffd000; border-radius: 12px; padding: 11px 12px; display: flex; align-items: center; gap: 8px; font-weight: 700; } -.p-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 2px 7px; font-family: "DM Mono", monospace; font-size: 9px; } -.phones { display: flex; gap: 28px; justify-content: center; align-items: flex-end; flex-wrap: wrap; } -.phones .phone:nth-child(2) { transform: translateY(-22px); } -@media (max-width: 860px) { .phones .phone:nth-child(2) { transform: none; } .phone { --pwn: 232; } } +/* ================================================================== phone mockups (marketing) + Authored at true device scale (393 x 852 points) and scaled as a unit, so the app's own type sizes + and spacing survive. --pwn is unitless: calc() dividing two lengths yields a length, which scale() + would reject. */ +.phone { --pwn: 268; --scale: calc(var(--pwn) / 417); position: relative; width: calc(var(--pwn) * 1px); height: calc(876px * var(--scale)); flex: none; } +.phone-device { position: absolute; top: 0; left: 0; width: 417px; height: 876px; transform: scale(var(--scale)); transform-origin: top left; background: #0b0d10; border-radius: 58px; padding: 12px; box-shadow: 0 40px 90px rgba(16,20,24,0.3), 0 0 0 1px rgba(255,255,255,0.08) inset; } +.ph-island { position: absolute; top: 24px; left: 50%; transform: translateX(-50%); width: 122px; height: 35px; background: #0b0d10; border-radius: 20px; z-index: 3; } +.phone-screen { position: relative; width: 100%; height: 100%; border-radius: 46px; background: #fff; overflow: hidden; display: flex; flex-direction: column; color: #101418; font-size: 15px; } +.ph-home-ind { position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%); width: 140px; height: 5px; border-radius: 3px; background: #101418; opacity: 0.85; } +.ph-status { height: 56px; padding: 16px 30px 0; display: flex; align-items: center; justify-content: space-between; font-size: 16px; } +.ph-status b { font-family: "DM Sans", sans-serif; font-weight: 700; letter-spacing: -0.2px; } +.ph-status-icons { display: flex; align-items: center; gap: 6px; fill: #101418; color: #101418; } +.ph-body { flex: 1; padding: 6px 16px 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; } + +.ph-top { display: flex; align-items: center; gap: 10px; height: 44px; } +.ph-top > b { font-size: 17px; font-weight: 700; } +.ph-ident { position: relative; width: 36px; height: 36px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #7dd3fc, #2ec27e); flex: none; } +.ph-ident i { position: absolute; top: -6px; left: 16px; background: #ffd000; color: #101418; font-style: normal; font-size: 10px; font-weight: 800; border-radius: 8px; padding: 1px 5px; border: 2px solid #fff; } +.ph-caret { color: #98a2b3; font-size: 13px; } +.ph-caret.r { margin-left: auto; } +.ph-top-btns { margin-left: auto; display: flex; gap: 8px; } +.ph-top-btns i { width: 40px; height: 40px; border-radius: 50%; background: #f6f7f9; display: block; position: relative; } +.ph-top-btns i::before { content: ""; position: absolute; inset: 13px; border: 2px solid #101418; border-radius: 3px; -webkit-mask: linear-gradient(#000 0 0) top/100% 4px no-repeat, linear-gradient(#000 0 0) bottom/100% 4px no-repeat, linear-gradient(#000 0 0) left/4px 100% no-repeat, linear-gradient(#000 0 0) right/4px 100% no-repeat; } +.ph-top-btns i.bell::before { inset: 11px 13px 12px; border: 0; background: #101418; -webkit-mask: none; border-radius: 7px 7px 2px 2px; } +.ph-top-btns i.bell::after { content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px; border-radius: 50%; background: #ffd000; } +.ph-pending { display: flex; align-items: center; gap: 10px; background: #fff6cc; color: #8a6d00; border-radius: 14px; padding: 0 14px; height: 48px; font-weight: 700; font-size: 15px; } +.ph-pending .n { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 12px; } +.ph-chain { display: flex; align-items: center; gap: 8px; font-size: 14px; } +.ph-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-size: 13px; } +.ph-ark { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 11px; font-weight: 800; } +.ph-balance { font-family: "Space Grotesk", sans-serif; font-size: 44px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } +.ph-balance small { font-size: 20px; color: #667085; margin-left: 8px; letter-spacing: -0.02em; } +.ph-actions { display: flex; gap: 10px; } +.ph-actions span { flex: 1; height: 48px; display: grid; place-items: center; border-radius: 14px; background: #f6f7f9; font-weight: 700; font-size: 15px; } +.ph-actions .go { background: #ffd000; } +.ph-label { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 4px; } +.ph-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #eceef2; } +.ph-row.last, .ph-card .ph-row:last-child { border-bottom: 0; } +.ph-card { background: #f6f7f9; border-radius: 16px; padding: 0 14px; } +.ph-card.pad { padding: 4px 14px; } +.ph-mark, .ph-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } +.ph-circle { width: 40px; height: 40px; background: #eceef2; font-size: 16px; } +.ph-circle.sm { width: 34px; height: 34px; font-size: 15px; } +.ph-name { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } +.ph-name b { font-size: 15px; font-weight: 700; } +.ph-name small { font-size: 13px; color: #667085; } +.ph-amt { font-size: 15px; font-weight: 700; } +.ph-badge { background: #eceef2; color: #667085; border-radius: 99px; padding: 4px 9px; font-weight: 700; font-size: 12px; } +.ph-badge.warn { background: #fff3d6; color: #a86a00; } +.ph-title { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 700; display: flex; align-items: center; gap: 10px; height: 44px; } +.ph-title.back { font-size: 18px; } +.ph-title .ph-plus { margin-left: auto; width: 40px; height: 40px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 20px; } +.ph-tabsline { display: flex; gap: 22px; border-bottom: 1px solid #eceef2; font-size: 15px; } +.ph-tabsline b { border-bottom: 2px solid #ffd000; padding-bottom: 9px; } +.ph-tabsline span { color: #98a2b3; padding-bottom: 9px; } +.ph-chips { display: flex; gap: 8px; } +.ph-chips b, .ph-chips span { border-radius: 99px; padding: 6px 12px; font-size: 12px; font-weight: 700; background: #f6f7f9; color: #667085; } +.ph-chips b { background: #ffd000; color: #101418; } +.ph-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0 4px; } +.ph-hero-mark { position: relative; } +.ph-hero-mark i { position: absolute; right: -4px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #b42318; color: #fff; font-style: normal; font-size: 12px; display: grid; place-items: center; border: 3px solid #fff; } +.ph-hero b { font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -0.03em; } +.ph-hero small { color: #667085; font-size: 14px; } +.ph-kv { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eceef2; font-size: 14px; } +.ph-kv.last { border-bottom: 0; } +.ph-kv span { color: #667085; } +.ph-sign { margin-top: auto; margin-bottom: 12px; background: #ffd000; border-radius: 16px; height: 56px; padding: 0 18px; display: flex; align-items: center; gap: 10px; font-size: 16px; } +.ph-sign b { font-weight: 700; } +.ph-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 5px 10px; font-family: "DM Mono", monospace; font-size: 12px; } +.ph-tabs { height: 84px; border-top: 1px solid #eceef2; display: flex; align-items: flex-start; padding-top: 14px; } +.ph-tabs span { flex: 1; text-align: center; font-size: 24px; color: #98a2b3; position: relative; } +.ph-tabs span.on { color: #ffd000; } +.ph-tab-badge { position: absolute; top: -4px; left: 55%; background: #ffd000; color: #101418; font-style: normal; font-size: 11px; font-weight: 800; border-radius: 99px; padding: 1px 6px; } +.phones { display: flex; gap: 30px; justify-content: center; align-items: flex-start; flex-wrap: wrap; } +.phones .phone:nth-child(2) { margin-top: -26px; } +@media (max-width: 900px) { .phones .phone:nth-child(2) { margin-top: 0; } .phone { --pwn: 240; } } + /* The landing's mobile strip: copy on the left, two phones on the right, the card sized by both. */ .mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } .mstrip h2 { text-align: left; margin-bottom: 16px; } From 977a79ed4990eaf2f61dbf5e3bbd30013d05dd8d Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 17 Sep 2026 03:46:14 +0100 Subject: [PATCH 13/44] feat(web): documentation on the site instead of a link to the repository Every 'read the docs' link sent people to a markdown file on GitHub. The site now has its own documentation section. Fourteen pages under four groups: Start (introduction, quick start), Model (roles, risk tiers), Reference (policy, recipients, limits and the circuit breaker, security modes, changing the policy, recovery, the phone app, contracts and addresses) and Assurance (invariants and testing, known limitations). A sticky sidebar, breadcrumb, prev and next paging, and tables built for reading a rule rather than scanning prose. The policy reference and the template table are generated from the same definitions the editor uses, and the address table from the deployment record, so they cannot drift from what the contracts do. The validation rules are the contract's own. Docs, Security model and the in-app Docs entry now open this section. Known limitations are stated on their own page rather than buried in a decisions log. --- web/src/App.tsx | 14 +- web/src/components/AppShell.tsx | 2 +- web/src/components/MarketingShell.tsx | 10 +- web/src/pages/Docs.tsx | 291 ++++++++++++++++++++++++++ web/src/pages/Product.tsx | 2 +- web/src/pages/Welcome.tsx | 2 +- web/src/styles.css | 37 ++++ 7 files changed, 346 insertions(+), 12 deletions(-) create mode 100644 web/src/pages/Docs.tsx diff --git a/web/src/App.tsx b/web/src/App.tsx index 0895075..7a0e425 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -15,6 +15,7 @@ import { Product } from "./pages/Product"; import { Security } from "./pages/Security"; import { SecurityPage } from "./pages/SecurityPage"; import { Mobile } from "./pages/Mobile"; +import { Docs, DOC_SLUGS, type DocSlug } from "./pages/Docs"; import { Settings } from "./pages/Settings"; import { Simulator } from "./pages/Simulator"; import { Solutions } from "./pages/Solutions"; @@ -29,7 +30,7 @@ import { useVaultAddress } from "./state/vaultAddress"; * #/welcome #/new-vault onboarding * #/app/ the vault app */ -type Route = { kind: "landing" } | { kind: "product" } | { kind: "solutions" } | { kind: "securitypage" } | { kind: "mobile" } | { kind: "welcome" } | { kind: "create" } | { kind: "app"; page: AppPage }; +type Route = { kind: "landing" } | { kind: "product" } | { kind: "solutions" } | { kind: "securitypage" } | { kind: "mobile" } | { kind: "docs"; slug: DocSlug } | { kind: "welcome" } | { kind: "create" } | { kind: "app"; page: AppPage }; const APP_PAGES: AppPage[] = ["overview", "assets", "transactions", "addressbook", "members", "settings", "policies", "security", "simulator"]; const LEGACY: Record = { home: "overview", recipients: "addressbook" }; @@ -41,6 +42,10 @@ function readRoute(): Route { if (raw === "solutions") return { kind: "solutions" }; if (raw === "security") return { kind: "securitypage" }; if (raw === "mobile") return { kind: "mobile" }; + if (raw === "docs" || raw.startsWith("docs/")) { + const slug = raw.slice(5) as DocSlug; + return { kind: "docs", slug: DOC_SLUGS.includes(slug) ? slug : "introduction" }; + } if (raw === "welcome") return { kind: "welcome" }; if (raw === "new-vault") return { kind: "create" }; const seg = raw.replace(/^app\//, ""); @@ -50,7 +55,7 @@ function readRoute(): Route { } function go(route: Route) { - const hash = route.kind === "landing" ? "#/" : route.kind === "product" ? "#/product" : route.kind === "solutions" ? "#/solutions" : route.kind === "securitypage" ? "#/security" : route.kind === "mobile" ? "#/mobile" : route.kind === "welcome" ? "#/welcome" : route.kind === "create" ? "#/new-vault" : `#/app/${route.page}`; + const hash = route.kind === "landing" ? "#/" : route.kind === "product" ? "#/product" : route.kind === "solutions" ? "#/solutions" : route.kind === "securitypage" ? "#/security" : route.kind === "mobile" ? "#/mobile" : route.kind === "docs" ? `#/docs/${route.slug}` : route.kind === "welcome" ? "#/welcome" : route.kind === "create" ? "#/new-vault" : `#/app/${route.page}`; if (window.location.hash !== hash) window.location.hash = hash; window.scrollTo({ top: 0 }); } @@ -84,8 +89,8 @@ export default function App() { return () => window.removeEventListener("hashchange", onHash); }, []); - useEffect(() => { window.scrollTo(0, 0); }, [route.kind, "page" in route ? route.page : ""]); - const marketing = route.kind === "landing" || route.kind === "product" || route.kind === "solutions" || route.kind === "securitypage" || route.kind === "mobile"; + useEffect(() => { window.scrollTo(0, 0); }, [route.kind, "page" in route ? route.page : "", "slug" in route ? route.slug : ""]); + const marketing = route.kind === "landing" || route.kind === "product" || route.kind === "solutions" || route.kind === "securitypage" || route.kind === "mobile" || route.kind === "docs"; useEffect(() => { document.documentElement.setAttribute("data-theme", marketing ? "light" : themeState.theme); }, [marketing, themeState.theme]); @@ -100,6 +105,7 @@ export default function App() { if (route.kind === "solutions") return ; if (route.kind === "securitypage") return ; if (route.kind === "mobile") return ; + if (route.kind === "docs") return { window.location.hash = `#/docs/${s}`; }} />; return ( diff --git a/web/src/components/AppShell.tsx b/web/src/components/AppShell.tsx index f9d281d..e925dd1 100644 --- a/web/src/components/AppShell.tsx +++ b/web/src/components/AppShell.tsx @@ -85,7 +85,7 @@ export function AppShell({ page, onNavigate, onHome, vault, vaultAddress, onNewT
      )}
      diff --git a/web/src/components/MarketingShell.tsx b/web/src/components/MarketingShell.tsx index 55491a4..39d3425 100644 --- a/web/src/components/MarketingShell.tsx +++ b/web/src/components/MarketingShell.tsx @@ -2,7 +2,7 @@ import type { ReactNode } from "react"; import { useScrolled } from "../lib/motion"; import { IconChevronRight } from "./icons"; -export type MarketingPage = "landing" | "product" | "solutions" | "security" | "mobile"; +export type MarketingPage = "landing" | "product" | "solutions" | "security" | "mobile" | "docs"; /** Nav, closing CTA and footer shared by every marketing page. */ export function MarketingShell({ page, onLaunch, children, hideCta = false }: { page: MarketingPage; onLaunch: () => void; children: ReactNode; hideCta?: boolean }) { @@ -17,7 +17,7 @@ export function MarketingShell({ page, onLaunch, children, hideCta = false }: { Solutions Security Mobile - FAQ + Docs GitHub ↗
      @@ -34,7 +34,7 @@ export function MarketingShell({ page, onLaunch, children, hideCta = false }: {

      Put a firewall in front of
      your treasury

      Self-custodial, enforced onchain, and readable by the people who sign.

      - Read the docs + Read the docs
      @@ -47,8 +47,8 @@ export function MarketingShell({ page, onLaunch, children, hideCta = false }: {
      Skur

      Programmable treasury security for onchain businesses.

      - - + +
      Social
      Skur V1 · Ark Constellation devnetMIT licensed. Skur limits and delays damage; it is not a guarantee against loss.
      diff --git a/web/src/pages/Docs.tsx b/web/src/pages/Docs.tsx new file mode 100644 index 0000000..81b4dd9 --- /dev/null +++ b/web/src/pages/Docs.tsx @@ -0,0 +1,291 @@ +import { useEffect } from "react"; +import { MarketingShell } from "../components/MarketingShell"; +import { DEPLOYMENTS, ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC } from "../config/chain"; +import { POLICY_GROUPS } from "../lib/policyFields"; +import { TEMPLATES } from "../lib/templates"; +import { fmtDuration } from "../lib/format"; + +export type DocSlug = + | "introduction" | "quick-start" | "roles" | "risk-tiers" | "policy" | "recipients" + | "limits" | "modes" | "changes" | "recovery" | "mobile" | "contracts" | "invariants" | "limitations"; + +type Doc = { slug: DocSlug; title: string; group: string; body: () => React.ReactNode }; + +const H = ({ children }: { children: React.ReactNode }) =>

      {children}

      ; +const Note = ({ children }: { children: React.ReactNode }) =>
      {children}
      ; + +function Table({ head, rows }: { head: string[]; rows: React.ReactNode[][] }) { + return ( +
      + + {head.map((h) => )} + {rows.map((r, i) => {r.map((c, j) => )})} +
      {h}
      {c}
      +
      + ); +} + +const DOCS: Doc[] = [ + { + slug: "introduction", title: "Introduction", group: "Start", + body: () => ( + <> +

      Skur is a self-custodial treasury vault whose security requirements rise and fall with the risk of each transaction.

      +

      A multisignature wallet asks one question: did enough people sign? Skur asks a second one: should this transaction be allowed right now? Between a valid approval and the money sit amount tiers, recipient trust, velocity caps, a loss envelope, guardian veto and a firewall around policy changes. Every one is enforced by the vault contract, not by a server.

      + What Skur does not claim +

      Skur does not make signer compromise harmless. It limits and delays the damage when authorised credentials are misused. A stolen key alone cannot reach a tier's threshold unless you set that tier to one, and even then it is bounded by the per-transaction cap, the daily cap and the loss envelope.

      + Skur V1 runs on the Ark Constellation devnet, chain 9000. It has not been audited. Do not put real value behind it until an independent audit is complete. + + ), + }, + { + slug: "quick-start", title: "Quick start", group: "Start", + body: () => ( + <> +

      Three ways in, none of which require a deployment of your own.

      + Read the demo vault +

      Open the app and choose the demo vault. No wallet is needed to read a vault: balances, the queue, the policy and the security posture all come from the chain.

      + Create your own +
        +
      1. Connect a wallet on the Ark devnet. The app will offer to switch networks if you are on another chain.
      2. +
      3. Name the vault and pick the template closest to your organisation. Every value can be changed later through governance.
      4. +
      5. List the members and their roles. Owners govern, approvers confirm payments, executors execute, guardians hold the brake.
      6. +
      7. Review the policy the vault will enforce from its first block, then sign once.
      8. +
      + Send a payment +

      Enter the recipient, asset and amount. Before the wallet opens, the vault itself classifies the payment: the tier, the approvals it needs, whether a guardian must sign, how long it waits and why. Approvals are recounted against live membership at execution, and the caps are checked again.

      + + ), + }, + { + slug: "roles", title: "Roles", group: "Model", + body: () => ( + <> +

      Four roles, held as a bitmask. A member can hold several treasury roles; a guardian can hold none.

      + + Why guardians are exclusive +

      The contract refuses to give a guardian a treasury role, and refuses to give a treasury member the guardian role. That makes guardians a second control plane an attacker must breach separately, and one they cannot profit from: there is no withdrawal path from guardian authority.

      + + ), + }, + { + slug: "risk-tiers", title: "Risk tiers", group: "Model", + body: () => ( + <> +

      Every transfer is scored when it is proposed. The score sets the requirements, and the requirements are pinned to the proposal.

      + What the vault reads +
      + What the tier decides +

      The number of approvals, whether a guardian must confirm, and how long the proposal waits before it can execute. A proposal carries its requirements from the moment it is created, so a later policy change cannot lower the bar for something already in the queue.

      + The same rules run in the interface only to preview. The contract classifies independently at proposal time and checks the caps again at execution. + + ), + }, + { + slug: "policy", title: "Policy reference", group: "Reference", + body: () => ( + <> +

      Every control a vault enforces, and the rules a policy must satisfy to be valid.

      + {POLICY_GROUPS.map((g) => ( +
      + {g.title} +

      {g.sub}

      +
      [f.label, f.unit === "bps" ? "percent" : f.unit === "hours" ? "duration" : f.unit === "bool" ? "on or off" : "count", f.hint || "—"])} /> + + ))} + Validation +

      A policy the contract will not accept:

      +
        +
      • Routine approvals below one, or a tier requiring fewer approvals than the tier beneath it.
      • +
      • A governance threshold of zero, or above the number of owners.
      • +
      • A guardian requirement for critical transfers with a guardian threshold of zero.
      • +
      • A critical delay shorter than the high delay.
      • +
      • Exposure thresholds above 100%, out of order, or a hard block below the critical threshold.
      • +
      • An envelope window under one hour, or a proposal lifetime that does not exceed the longest delay by at least one hour.
      • +
      + Templates +
      [t.name, t.tagline, fmtDuration(t.policy.delayCritical), fmtDuration(t.policy.recipientActivationDelay), `${t.policy.envelopeBps / 100}% per ${fmtDuration(t.policy.envelopeWindow)}`])} /> + + ), + }, + { + slug: "recipients", title: "Recipients and trust", group: "Reference", + body: () => ( + <> +

      A recipient is a security object, not a string in a form.

      +
      +

      Registering a supplier early starts its activation clock, so its first real payment does not have to wait. Raising a recipient's trust loosens security: it waits out the policy-change delay and any guardian can veto it. Restricting or blocking takes effect as soon as owners approve.

      + + ), + }, + { + slug: "limits", title: "Limits and the circuit breaker", group: "Reference", + body: () => ( + <> +

      Caps are per asset and cumulative, so splitting a payment changes nothing.

      +
      + The breaker latches +

      The transfer that would cross the envelope is not paid. Instead the vault moves to Lockdown, where outgoing execution stops and only tightening changes, deposits, recovery and guardian actions still work. Leaving Lockdown needs owners and guardians together, and waits out the policy-change delay.

      + Buckets are anchored to a fixed window rather than a rolling one. An attacker who waits for a boundary gets two windows' worth in quick succession; the envelope is the backstop for that case. + + ), + }, + { + slug: "modes", title: "Security modes", group: "Reference", + body: () => ( + <> +
      +

      Raising the mode is instant and unilateral by design: in an incident, the cost of a false alarm is far lower than the cost of a delay. Lowering it is governance.

      + + ), + }, + { + slug: "changes", title: "Changing the policy", group: "Reference", + body: () => ( + <> +

      Changing the rules is as dangerous as moving the money, so it goes through its own firewall.

      +

      Every proposed change is classified. If it loosens any control, it is security-reducing and:

      +
        +
      • waits out the policy-change delay before it can execute,
      • +
      • can be vetoed by any single guardian at any point,
      • +
      • cannot be proposed at all while the vault is in Lockdown.
      • +
      +

      A change that tightens or keeps every control applies as soon as owners approve. Loosening includes fewer approvals, shorter delays, higher caps, a wider envelope, a higher exposure threshold, raising a recipient's trust, approving a new asset, adding authority to a member and weakening the guardian layer.

      + Proposals in flight keep the requirements pinned when they were created, so a loosening that activates later cannot lower the bar for something already queued. + + ), + }, + { + slug: "recovery", title: "Recovery", group: "Reference", + body: () => ( + <> +

      Replacing a lost or compromised signer without giving anyone a backdoor.

      +
        +
      1. Guardians propose replacing an address with a new one holding the same roles.
      2. +
      3. The proposal waits out the recovery delay. Any owner can cancel it during that window.
      4. +
      5. On execution the roles move across. The policy is untouched, and the vault moves to Elevated.
      6. +
      +

      Recovery cannot change thresholds, delays, caps or anyone else's roles. It is the narrowest possible operation: one address for another.

      + + ), + }, + { + slug: "mobile", title: "The phone app", group: "Reference", + body: () => ( + <> +

      iOS and Android, sharing this site's risk engine, policy rules and contract reads.

      +

      There is no wallet connection. A signer key is created on the phone or imported, kept in the device keychain, and used after a Face ID or Touch ID prompt. Give that address a role in a vault and it signs; without a role the app is a reader.

      +

      Everything the desktop does is there: balances, the queue, the confirm screen with the vault's own review, the policy editor, members, the address book, the attack simulator, security modes and recovery. Notifications are local: when the app reads the vault and finds a proposal that newly needs you, it raises one. Nothing is sent to a server.

      +

      It is not on the app stores. Build it from the repository with Expo.

      + + ), + }, + { + slug: "contracts", title: "Contracts and addresses", group: "Reference", + body: () => ( + <> +

      Skur V1 on the Ark Constellation devnet, chain 9000. Every address below is verified on the explorer.

      +
      {DEPLOYMENTS.factory}], + ["Vault implementation", {DEPLOYMENTS.vaultImplementation}], + ["Demo vault", {DEPLOYMENTS.demoVault}], + ["Skur Test USD", {DEPLOYMENTS.testUsd}], + ]} /> + Endpoints +
      {ARK_DEVNET_RPC}], ["Explorer", {ARK_DEVNET_EXPLORER.replace("https://", "")}]]} /> +

      Each vault is a minimal proxy over one verified implementation. The factory keeps no authority over the vaults it creates, and a vault has no admin and no upgrade path. Moving to a new version means creating a new vault and transferring funds under the old vault's own policy.

      + + ), + }, + { + slug: "invariants", title: "Invariants and testing", group: "Assurance", + body: () => ( + <> +

      Twelve properties, each with a test.

      +
        + {["No proposal executes before every active condition is met", "A guardian cannot move treasury assets through guardian authority alone", "Lockdown blocks ordinary outgoing execution", "Security-reducing policy changes never take effect immediately", "Cumulative outflow accounting cannot be bypassed by splitting", "A proposal cannot execute twice", "Removed signers cannot approve new actions", "Approvals cannot be duplicated or replayed", "New recipients cannot skip their activation delay", "Recovery cannot quietly weaken the policy", "Native and ERC-20 accounting reconciles", "External calls cannot re-enter an unsafe state"].map((t) =>
      1. {t}
      2. )} +
      +

      The suite is 95 tests: a unit test per control, fuzzed monotonicity properties, and a stateful handler driving random actors against the vault. Static analysis reports nothing above informational, sources are verified on the explorer, and the repository builds to byte-identical runtime bytecode.

      + + ), + }, + { + slug: "limitations", title: "Known limitations", group: "Assurance", + body: () => ( + <> +

      What Skur V1 does not do, stated plainly.

      +
        +
      • No audit. The contracts have not been reviewed by an independent firm.
      • +
      • No price oracle. Exposure is measured per asset, as a share of that asset's holdings, not of the treasury's value.
      • +
      • Anchored windows. Velocity and envelope buckets are anchored rather than rolling, so a boundary allows two windows in quick succession.
      • +
      • The breaker latches. Crossing the envelope stops the payment and freezes the vault; it does not reverse anything already paid.
      • +
      • Single-guardian vaults. Permitted, and a single point of failure for veto and recovery. Use more than one.
      • +
      • Devnet only. Endpoints and deployments target the Ark Constellation devnet.
      • +
      + + ), + }, +]; + +const GROUPS = ["Start", "Model", "Reference", "Assurance"]; + +export function Docs({ slug, onLaunch, onNavigate }: { slug: DocSlug; onLaunch: () => void; onNavigate: (s: DocSlug) => void }) { + const doc = DOCS.find((d) => d.slug === slug) ?? DOCS[0]; + const i = DOCS.indexOf(doc); + useEffect(() => { window.scrollTo(0, 0); }, [slug]); + return ( + +
      + +
      +
      Docs / {doc.group}
      +

      {doc.title}

      + {doc.body()} + +
      +
      +
      + ); +} + +export const DOC_SLUGS = DOCS.map((d) => d.slug); diff --git a/web/src/pages/Product.tsx b/web/src/pages/Product.tsx index 24f1e9b..f33ee29 100644 --- a/web/src/pages/Product.tsx +++ b/web/src/pages/Product.tsx @@ -7,7 +7,7 @@ export function Product({ onLaunch }: { onLaunch: () => void }) { return ( Multisig approvals,
      plus a firewall} sub="Keep the N-of-M you already trust. Add the controls that decide whether a valid approval should move money right now." onLaunch={onLaunch}> - Read the security model + Read the security model
      diff --git a/web/src/pages/Welcome.tsx b/web/src/pages/Welcome.tsx index 5fce065..78497ef 100644 --- a/web/src/pages/Welcome.tsx +++ b/web/src/pages/Welcome.tsx @@ -112,7 +112,7 @@ export function Welcome({ onOpen, onCreate, onLanding }: { onOpen: (a: `0x${stri
      Skur V1 · Ark devnet GitHub - Security model + Documentation Explorer Faucet
      diff --git a/web/src/styles.css b/web/src/styles.css index 2ca38ef..9bcba5b 100644 --- a/web/src/styles.css +++ b/web/src/styles.css @@ -807,3 +807,40 @@ input:read-only { color: var(--text-2); } .phones.two .phone { --pwn: 196; } .phones.two .phone:nth-child(2) { margin-top: 30px; } @media (max-width: 980px) { .mstrip { grid-template-columns: 1fr; } .phones.two { justify-content: center; } .phones.two .phone:nth-child(2) { display: none; } } + +/* ================================================================== documentation */ +.docs { max-width: 1216px; margin: 0 auto; padding: 0 24px; display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; align-items: start; } +.docs-nav { position: sticky; top: 96px; padding: 40px 0 60px; display: flex; flex-direction: column; gap: 22px; } +.docs-group { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 8px; } +.docs-nav button { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 7px 12px; margin-left: -12px; border-radius: 8px; font: inherit; font-size: 15px; color: #6c757d; cursor: pointer; } +.docs-nav button:hover { background: #f1f3f5; color: #212529; } +.docs-nav button.on { background: #fff6cc; color: #212529; font-weight: 700; } +.docs-body { padding: 40px 0 96px; min-width: 0; } +.docs-crumb { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 12px; } +.docs-body h1 { font-family: "Space Grotesk", sans-serif; font-size: 44px; line-height: 48px; letter-spacing: -0.03em; margin-bottom: 20px; } +.docs-body h3 { font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -0.02em; margin: 40px 0 10px; scroll-margin-top: 96px; } +.docs-body p { font-size: 17px; line-height: 27px; color: #495057; margin-bottom: 16px; max-width: 70ch; } +.docs-body .doc-lead { font-size: 20px; line-height: 30px; color: #212529; margin-bottom: 24px; } +.docs-body ul, .docs-body ol { margin: 0 0 20px 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 26px; color: #495057; max-width: 70ch; } +.docs-body li b { color: #212529; } +.docs-body ol.doc-inv { counter-reset: inv; list-style: none; margin-left: 0; } +.docs-body ol.doc-inv li { counter-increment: inv; padding-left: 40px; position: relative; color: #212529; font-weight: 500; } +.docs-body ol.doc-inv li::before { content: counter(inv); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; border-radius: 6px; background: #ffd000; color: #212529; display: grid; place-items: center; font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; } +.doc-note { border-left: 3px solid #ffd000; background: #fffdf2; padding: 14px 18px; border-radius: 0 8px 8px 0; font-size: 16px; line-height: 25px; color: #495057; margin: 22px 0; max-width: 70ch; } +.doc-table { overflow-x: auto; margin: 0 0 24px; } +.doc-table table { border-collapse: collapse; width: 100%; font-size: 15px; } +.doc-table th { text-align: left; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #98a2b3; font-weight: 400; padding: 0 16px 10px 0; border-bottom: 1px solid #e9ecef; } +.doc-table td { padding: 12px 16px 12px 0; border-bottom: 1px solid #f1f3f5; color: #495057; vertical-align: top; line-height: 23px; } +.doc-table td:first-child { color: #212529; font-weight: 700; white-space: nowrap; } +.doc-table code { font-family: "DM Mono", monospace; font-size: 13px; background: #f1f3f5; padding: 2px 6px; border-radius: 4px; color: #212529; } +.docs-paging { display: flex; justify-content: space-between; gap: 16px; margin-top: 56px; padding-top: 24px; border-top: 1px solid #e9ecef; } +.docs-paging button { background: none; border: 0; font: inherit; font-weight: 700; color: #212529; cursor: pointer; padding: 8px 0; } +.docs-paging button:hover { color: #6c757d; } +@media (max-width: 900px) { + .docs { grid-template-columns: 1fr; gap: 0; } + .docs-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 24px 0 0; } + .docs-nav > div { display: contents; } + .docs-group { display: none; } + .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } + .docs-body h1 { font-size: 34px; line-height: 38px; } +} From 2d3940b2f6aa2b856fe035b6b656aab949a43370 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 09:27:40 +0100 Subject: [PATCH 14/44] feat(sui): Move core, SDK and indexer for the authorization layer Redirects the build from EVM to Sui, carrying over the engines a threshold product does not have. Move core (sui/): - types, policy and risk as separate auditable modules - the vault: seven proposal kinds through one lifecycle, requirements pinned at proposal and tighten-only at execution, approvals recounted against the live roster - cumulative velocity per asset, and a loss envelope measured against the balance when the window opened so a drain cannot shrink its denominator - the breaker refuses the payment and latches to Lockdown without reverting, because a latch that reverts is not a latch - a guardian that the contract refuses to give any treasury role - a proposer role for automation: can open a proposal, nothing else - creation as a PTB hot potato, so a half-configured vault is never reachable TypeScript (sdk/): - gRPC and GraphQL only; no JSON-RPC, directly or transitively - BCS layouts mirroring the Move structs, parsed from content rather than json - PTB builders for every action, with the policy built on chain by policy::new - the chain-agnostic engines ported to milliseconds: risk, policy rules, templates, maximum loss, posture and the attack simulator - 39 tests pinning the same vectors as the Move suite Backend (server/): - PostgreSQL projections rebuilt from events, idempotent on ledger position - notification rules addressed by role, so a guardian hears what only a guardian can stop - advisory services that can inform a signer and can never override the vault Docs: the competitive pass on what Sui has today, and the funding narrative. --- docs/SUI_LANDSCAPE.md | 130 ++ docs/SUI_POSITIONING.md | 196 ++ sdk/dist/bcs.d.ts | 203 ++ sdk/dist/bcs.d.ts.map | 1 + sdk/dist/bcs.js | 117 ++ sdk/dist/bcs.js.map | 1 + sdk/dist/engine/format.d.ts | 17 + sdk/dist/engine/format.d.ts.map | 1 + sdk/dist/engine/format.js | 83 + sdk/dist/engine/format.js.map | 1 + sdk/dist/engine/index.d.ts | 18 + sdk/dist/engine/index.d.ts.map | 1 + sdk/dist/engine/index.js | 18 + sdk/dist/engine/index.js.map | 1 + sdk/dist/engine/maxLoss.d.ts | 23 + sdk/dist/engine/maxLoss.d.ts.map | 1 + sdk/dist/engine/maxLoss.js | 80 + sdk/dist/engine/maxLoss.js.map | 1 + sdk/dist/engine/policy.d.ts | 14 + sdk/dist/engine/policy.d.ts.map | 1 + sdk/dist/engine/policy.js | 165 ++ sdk/dist/engine/policy.js.map | 1 + sdk/dist/engine/policyFields.d.ts | 20 + sdk/dist/engine/policyFields.d.ts.map | 1 + sdk/dist/engine/policyFields.js | 49 + sdk/dist/engine/policyFields.js.map | 1 + sdk/dist/engine/posture.d.ts | 19 + sdk/dist/engine/posture.d.ts.map | 1 + sdk/dist/engine/posture.js | 66 + sdk/dist/engine/posture.js.map | 1 + sdk/dist/engine/risk.d.ts | 40 + sdk/dist/engine/risk.d.ts.map | 1 + sdk/dist/engine/risk.js | 75 + sdk/dist/engine/risk.js.map | 1 + sdk/dist/engine/simulator.d.ts | 25 + sdk/dist/engine/simulator.d.ts.map | 1 + sdk/dist/engine/simulator.js | 210 ++ sdk/dist/engine/simulator.js.map | 1 + sdk/dist/engine/templates.d.ts | 26 + sdk/dist/engine/templates.d.ts.map | 1 + sdk/dist/engine/templates.js | 228 ++ sdk/dist/engine/templates.js.map | 1 + sdk/dist/errors.d.ts | 13 + sdk/dist/errors.d.ts.map | 1 + sdk/dist/errors.js | 95 + sdk/dist/errors.js.map | 1 + sdk/dist/events.d.ts | 186 ++ sdk/dist/events.d.ts.map | 1 + sdk/dist/events.js | 311 +++ sdk/dist/events.js.map | 1 + sdk/dist/index.d.ts | 15 + sdk/dist/index.d.ts.map | 1 + sdk/dist/index.js | 15 + sdk/dist/index.js.map | 1 + sdk/dist/network.d.ts | 43 + sdk/dist/network.d.ts.map | 1 + sdk/dist/network.js | 30 + sdk/dist/network.js.map | 1 + sdk/dist/tx.d.ts | 128 ++ sdk/dist/tx.d.ts.map | 1 + sdk/dist/tx.js | 282 +++ sdk/dist/tx.js.map | 1 + sdk/dist/types.d.ts | 209 ++ sdk/dist/types.d.ts.map | 1 + sdk/dist/types.js | 145 ++ sdk/dist/types.js.map | 1 + sdk/dist/vault.d.ts | 59 + sdk/dist/vault.d.ts.map | 1 + sdk/dist/vault.js | 273 +++ sdk/dist/vault.js.map | 1 + sdk/package-lock.json | 1936 +++++++++++++++++ sdk/package.json | 37 + sdk/scripts/seed.ts | 129 ++ sdk/src/bcs.ts | 133 ++ sdk/src/engine/format.ts | 80 + sdk/src/engine/index.ts | 17 + sdk/src/engine/maxLoss.ts | 112 + sdk/src/engine/policy.ts | 131 ++ sdk/src/engine/policyFields.ts | 60 + sdk/src/engine/posture.ts | 78 + sdk/src/engine/risk.ts | 108 + sdk/src/engine/simulator.ts | 266 +++ sdk/src/engine/templates.ts | 255 +++ sdk/src/errors.ts | 91 + sdk/src/events.ts | 432 ++++ sdk/src/index.ts | 14 + sdk/src/network.ts | 71 + sdk/src/tx.ts | 382 ++++ sdk/src/types.ts | 288 +++ sdk/src/vault.ts | 364 ++++ sdk/test/engine.test.ts | 370 ++++ sdk/tsconfig.build.json | 21 + sdk/tsconfig.json | 28 + server/.env.example | 14 + server/migrations/001_init.sql | 182 ++ server/package-lock.json | 2795 +++++++++++++++++++++++++ server/package.json | 26 + server/src/advisory.ts | 216 ++ server/src/api.ts | 223 ++ server/src/config.ts | 18 + server/src/db.ts | 35 + server/src/indexer.ts | 113 + server/src/main.ts | 25 + server/src/migrate.ts | 49 + server/src/notify.ts | 360 ++++ server/src/project.ts | 296 +++ server/tsconfig.json | 15 + sui/.gitignore | 3 + sui/Move.toml | 15 + sui/scripts/publish.sh | 57 + sui/scripts/test.sh | 6 + sui/sources/policy.move | 341 +++ sui/sources/risk.move | 168 ++ sui/sources/types.move | 143 ++ sui/sources/vault.move | 1639 +++++++++++++++ sui/tests/engine_tests.move | 369 ++++ sui/tests/vault_tests.move | 935 +++++++++ 117 files changed, 17106 insertions(+) create mode 100644 docs/SUI_LANDSCAPE.md create mode 100644 docs/SUI_POSITIONING.md create mode 100644 sdk/dist/bcs.d.ts create mode 100644 sdk/dist/bcs.d.ts.map create mode 100644 sdk/dist/bcs.js create mode 100644 sdk/dist/bcs.js.map create mode 100644 sdk/dist/engine/format.d.ts create mode 100644 sdk/dist/engine/format.d.ts.map create mode 100644 sdk/dist/engine/format.js create mode 100644 sdk/dist/engine/format.js.map create mode 100644 sdk/dist/engine/index.d.ts create mode 100644 sdk/dist/engine/index.d.ts.map create mode 100644 sdk/dist/engine/index.js create mode 100644 sdk/dist/engine/index.js.map create mode 100644 sdk/dist/engine/maxLoss.d.ts create mode 100644 sdk/dist/engine/maxLoss.d.ts.map create mode 100644 sdk/dist/engine/maxLoss.js create mode 100644 sdk/dist/engine/maxLoss.js.map create mode 100644 sdk/dist/engine/policy.d.ts create mode 100644 sdk/dist/engine/policy.d.ts.map create mode 100644 sdk/dist/engine/policy.js create mode 100644 sdk/dist/engine/policy.js.map create mode 100644 sdk/dist/engine/policyFields.d.ts create mode 100644 sdk/dist/engine/policyFields.d.ts.map create mode 100644 sdk/dist/engine/policyFields.js create mode 100644 sdk/dist/engine/policyFields.js.map create mode 100644 sdk/dist/engine/posture.d.ts create mode 100644 sdk/dist/engine/posture.d.ts.map create mode 100644 sdk/dist/engine/posture.js create mode 100644 sdk/dist/engine/posture.js.map create mode 100644 sdk/dist/engine/risk.d.ts create mode 100644 sdk/dist/engine/risk.d.ts.map create mode 100644 sdk/dist/engine/risk.js create mode 100644 sdk/dist/engine/risk.js.map create mode 100644 sdk/dist/engine/simulator.d.ts create mode 100644 sdk/dist/engine/simulator.d.ts.map create mode 100644 sdk/dist/engine/simulator.js create mode 100644 sdk/dist/engine/simulator.js.map create mode 100644 sdk/dist/engine/templates.d.ts create mode 100644 sdk/dist/engine/templates.d.ts.map create mode 100644 sdk/dist/engine/templates.js create mode 100644 sdk/dist/engine/templates.js.map create mode 100644 sdk/dist/errors.d.ts create mode 100644 sdk/dist/errors.d.ts.map create mode 100644 sdk/dist/errors.js create mode 100644 sdk/dist/errors.js.map create mode 100644 sdk/dist/events.d.ts create mode 100644 sdk/dist/events.d.ts.map create mode 100644 sdk/dist/events.js create mode 100644 sdk/dist/events.js.map create mode 100644 sdk/dist/index.d.ts create mode 100644 sdk/dist/index.d.ts.map create mode 100644 sdk/dist/index.js create mode 100644 sdk/dist/index.js.map create mode 100644 sdk/dist/network.d.ts create mode 100644 sdk/dist/network.d.ts.map create mode 100644 sdk/dist/network.js create mode 100644 sdk/dist/network.js.map create mode 100644 sdk/dist/tx.d.ts create mode 100644 sdk/dist/tx.d.ts.map create mode 100644 sdk/dist/tx.js create mode 100644 sdk/dist/tx.js.map create mode 100644 sdk/dist/types.d.ts create mode 100644 sdk/dist/types.d.ts.map create mode 100644 sdk/dist/types.js create mode 100644 sdk/dist/types.js.map create mode 100644 sdk/dist/vault.d.ts create mode 100644 sdk/dist/vault.d.ts.map create mode 100644 sdk/dist/vault.js create mode 100644 sdk/dist/vault.js.map create mode 100644 sdk/package-lock.json create mode 100644 sdk/package.json create mode 100644 sdk/scripts/seed.ts create mode 100644 sdk/src/bcs.ts create mode 100644 sdk/src/engine/format.ts create mode 100644 sdk/src/engine/index.ts create mode 100644 sdk/src/engine/maxLoss.ts create mode 100644 sdk/src/engine/policy.ts create mode 100644 sdk/src/engine/policyFields.ts create mode 100644 sdk/src/engine/posture.ts create mode 100644 sdk/src/engine/risk.ts create mode 100644 sdk/src/engine/simulator.ts create mode 100644 sdk/src/engine/templates.ts create mode 100644 sdk/src/errors.ts create mode 100644 sdk/src/events.ts create mode 100644 sdk/src/index.ts create mode 100644 sdk/src/network.ts create mode 100644 sdk/src/tx.ts create mode 100644 sdk/src/types.ts create mode 100644 sdk/src/vault.ts create mode 100644 sdk/test/engine.test.ts create mode 100644 sdk/tsconfig.build.json create mode 100644 sdk/tsconfig.json create mode 100644 server/.env.example create mode 100644 server/migrations/001_init.sql create mode 100644 server/package-lock.json create mode 100644 server/package.json create mode 100644 server/src/advisory.ts create mode 100644 server/src/api.ts create mode 100644 server/src/config.ts create mode 100644 server/src/db.ts create mode 100644 server/src/indexer.ts create mode 100644 server/src/main.ts create mode 100644 server/src/migrate.ts create mode 100644 server/src/notify.ts create mode 100644 server/src/project.ts create mode 100644 server/tsconfig.json create mode 100644 sui/.gitignore create mode 100644 sui/Move.toml create mode 100755 sui/scripts/publish.sh create mode 100755 sui/scripts/test.sh create mode 100644 sui/sources/policy.move create mode 100644 sui/sources/risk.move create mode 100644 sui/sources/types.move create mode 100644 sui/sources/vault.move create mode 100644 sui/tests/engine_tests.move create mode 100644 sui/tests/vault_tests.move diff --git a/docs/SUI_LANDSCAPE.md b/docs/SUI_LANDSCAPE.md new file mode 100644 index 0000000..6eb690e --- /dev/null +++ b/docs/SUI_LANDSCAPE.md @@ -0,0 +1,130 @@ +# What already exists on Sui, and what it does not do + +Research pass: 2026-10-05. Purpose: decide what V1 has to be so that it is not a second +multisig, and so that the grant application can say precisely what is missing from the ecosystem +today. + +## The three things a Sui organization can use today + +### 1. Sui native multisig (protocol-level) + +Built into the protocol. A multisig address is a committee of up to **10 public keys**, each with +a weight, and a threshold. It can mix key schemes (Ed25519, ECDSA Secp256k1, Secp256r1), which is +genuinely useful — a Ledger, a passkey and a hot key can sit in the same committee. + +What it is: **signature aggregation**. The chain checks that the weights of the supplied +signatures reach the threshold, and then the transaction executes exactly as any other. + +What it cannot express, at all: + +- any dependence on **what** the transaction does — the same threshold clears a $10 invoice and + the entire treasury; +- any dependence on **who receives** it; +- any dependence on **what has already happened today**; +- any delay, any freeze, any veto, any recovery. + +There is also no onchain proposal object: coordination happens offchain, by passing partial +signatures around. There is nothing to query, index, or show a reviewer. + +### 2. account.tech (formerly Kraken) — Smart Account Framework + +The most serious piece of engineering in this space, and the real benchmark. A shared, programmable +account object with an **intent-based architecture**: an intent is created, resolved against the +account's `Config`, and then executed. + +Implemented: configurable ownership rules, **role-based permissions**, asset and object management, +**payments and vestings** (recurring transfer intents), currency control (locking a `TreasuryCap`), +package upgrade control (locking `UpgradeCap`s) with **an optional time-lock on upgrades**, and +dependency whitelisting so only approved packages can touch account state. + +Not implemented, by its own documentation: spending limits or transaction caps, recipient +allowlists or denylists, risk scoring, emergency freeze, social recovery. + +The shape of it matters: account.tech is an **extensibility** framework. Its security story is +"only approved packages may act, and the config decides who may act." That is a different axis +from ours. It makes a treasury *programmable*; it does not make a treasury *defended*. The upgrade +timelock is the only time-based control, and it protects code, not money. + +### 3. Maven, by the MSafe team + +The incumbent product: "the first and only multi-signature non-custodial digital assets management +solution on Sui," live on mainnet since day one. Multi-signature approval, **weighted voting power** +for co-managers, granular role assignment, and **co-signer account recovery**. + +Its published documentation does not describe spending limits, recipient allowlists, timelocks, +risk scoring or an emergency freeze. + +Maven is the closest thing to a Safe on Sui, and like Safe it is a *threshold* product. Safe's own +answer to policy is a module ecosystem bolted on afterwards; Maven does not have even that yet. + +### Also present, worth naming + +- **Streamflow** — multichain treasury management (Solana, Aptos, Sui) from one dashboard. Payment + streaming and vesting, not authorization policy. +- **MPCVault** — multi-chain MPC custody with one approval workflow and an audit log across + Ethereum, Bitcoin, Solana, TRON, TON, Aptos and Sui. Closest to us on *process* (approval + workflow, audit log), but it is **offchain policy over MPC custody**: the rules live in a + company's backend, not in a contract you can read. If their service is compromised or goes away, + the rules go with it. + +## The gap, stated as one sentence + +Every option on Sui today answers one question — *did enough of the right keys sign?* — and nothing +answers the question that actually decides whether a treasury survives a compromise: **given the +amount, the destination, the recent outflow and the vault's current posture, how much authorization +should this payment need, and should it be allowed to settle at all right now?** + +Concretely, nothing on Sui provides: + +| Control | Native multisig | account.tech | Maven | MPCVault | Skur | +|---|---|---|---|---|---| +| k-of-n threshold | yes | yes | yes | yes | yes | +| Roles beyond signer | no | yes | yes | yes | yes | +| Onchain proposal object | no | yes | yes | no | yes | +| Approvals that scale with amount | no | no | no | offchain | **yes** | +| Approvals that scale with share of treasury | no | no | no | no | **yes** | +| Per-transaction and 24-hour caps | no | no | no | offchain | **yes** | +| Cumulative accounting (split-proof) | no | no | no | unclear | **yes** | +| Recipient trust levels | no | no | no | allowlist | **yes** | +| New-recipient activation delay | no | no | no | no | **yes** | +| Risk-tiered timelocks | no | code upgrades only | no | no | **yes** | +| Loss-envelope circuit breaker | no | no | no | no | **yes** | +| Emergency freeze | no | no | no | yes (operator) | **yes (guardian)** | +| Guardian role with no spend path | no | no | no | no | **yes** | +| Tightening-only policy changes | no | no | no | no | **yes** | +| Guardian veto on weakening | no | no | no | no | **yes** | +| Signer recovery with delay + owner cancel | no | no | co-signers | yes (operator) | **yes** | +| Agent/automation role that cannot execute | no | no | no | no | **yes** | +| Rules enforced in Move, readable onchain | n/a | yes | yes | **no** | **yes** | + +## What this means for V1 + +1. **Do not compete on being a multisig.** Native multisig is free and in the protocol; Maven + already ships the product. Competing there is competing on UI. + +2. **Compete on the layer above it.** The pitch is a *programmable authorization and treasury + security layer*: the thing that decides how much authorization a payment needs and whether it + may settle now. A Skur vault can sit behind a native multisig or a Maven account as one of its + owners — we are not asking anyone to abandon the committee they already trust. + +3. **Interoperate with account.tech rather than duplicate it.** They own extensibility; we own + policy. A Skur policy object is a legitimate thing for an account.tech intent resolver to + consult, and that is a partnership conversation, not a competitive one. + +4. **The differentiators that no one can answer quickly** are the ones that require state over + time, not just a config: cumulative velocity accounting, the loss envelope measured against the + balance when the window opened, recipient probation, and tightening-only policy changes. Those + are the four to lead with. + +5. **Enforcement in Move is the honest claim against MPCVault.** Their controls are real but they + are somebody's backend. Ours are in a shared object anyone can read. That is the sentence for + the funding application. + +## Sources + +- https://docs.sui.io/develop/transactions/transaction-auth/multisig +- https://github.com/account-tech/move-framework +- https://github.com/account-tech +- https://doc.m-safe.io/sui +- https://sui.directory/project/maven/ +- https://blog.sui.io/write-multi-signature-multisig-move-contracts/ diff --git a/docs/SUI_POSITIONING.md b/docs/SUI_POSITIONING.md new file mode 100644 index 0000000..2dc7835 --- /dev/null +++ b/docs/SUI_POSITIONING.md @@ -0,0 +1,196 @@ +# Skur: a programmable authorization and treasury security layer for Sui + +Positioning and funding narrative. Written for grant reviewers, RFP committees and prospective +investors — people who will read one page before deciding whether to read the code. + +--- + +## The one sentence + +**Skur decides how much authorization a payment needs, and whether it may settle right now, from +the amount, the destination, the recent outflow and the vault's own security posture — enforced in +Move, in a shared object anyone can read.** + +It is not a wallet. It is the authorization layer a treasury sits behind. + +## Why this is not a multisig pitch + +A multisig answers one question: *did k of n sign?* + +That question is necessary and insufficient. Every large onchain treasury loss of the last three +years happened with **valid signatures**. The keys were real, the threshold was met, the contract +did exactly what it was told. The failure was never the signature check. It was that nothing +between the signature and the money asked a second question: + +> Given the amount, the destination, what has already left today and what the organization knows +> right now, *should* this payment settle? + +Sui already has signature aggregation in the protocol — native multisig, up to ten keys, mixed +schemes, free. Building a nicer interface over it is a design project, not an infrastructure one. +The layer that is genuinely missing is the one that answers the second question. + +## What exists on Sui today, and what it does not do + +A detailed pass is in [`SUI_LANDSCAPE.md`](./SUI_LANDSCAPE.md). The short version: + +| | Native multisig | account.tech | Maven (MSafe) | MPCVault | **Skur** | +|---|---|---|---|---|---| +| k-of-n threshold | yes | yes | yes | yes | yes | +| Onchain proposal object | no | yes | yes | no | yes | +| Approvals that scale with amount | no | no | no | offchain | **yes** | +| Approvals that scale with share of treasury | no | no | no | no | **yes** | +| Cumulative, split-proof outflow accounting | no | no | no | unclear | **yes** | +| Recipient trust and a new-recipient delay | no | no | no | allowlist | **yes** | +| Risk-tiered timelocks | no | code upgrades only | no | no | **yes** | +| Loss-envelope circuit breaker | no | no | no | no | **yes** | +| Guardian role with no spend path | no | no | no | no | **yes** | +| Tightening-only policy changes with a veto | no | no | no | no | **yes** | +| Rules enforced in Move, readable onchain | n/a | yes | yes | **no** | **yes** | + +**account.tech** is the serious engineering in this space and the right benchmark. It is an +*extensibility* framework: an intent-based smart account where only approved packages may act. Its +one time-based control is an upgrade timelock, which protects code rather than money. It makes a +treasury programmable; it does not make a treasury defended. These are different axes, and we would +rather be a policy module it can consult than a competing account standard. + +**MPCVault** has real approval workflows and audit logs across chains — and they live in a +company's backend. Ours live in a shared object. That is the whole difference, and it is the +sentence we are willing to be judged on. + +## What the Move core actually enforces + +Six controls stand between a valid approval and the money. All of them are in +[`sui/sources/`](../sui/sources/), and every one has a test named after the attack it defends +against in [`sui/tests/`](../sui/tests/). + +1. **Risk-tiered authorization.** Five independent signals — the absolute amount against the + asset's own limits, the payment's share of holdings, the recipient's standing, the day's + outflow so far, and the vault's security mode — each able to raise the tier and none able to + lower it. The tier sets the approvals, the guardian sign-off and the wait. + +2. **Recipient trust with an activation delay.** An address the vault has never paid is scored + higher, every time. A newly registered one serves a delay before it can be paid at all. Raising + an address's trust is a governance action with a timelock; a guardian can restrict or block one + instantly, alone. + +3. **Cumulative velocity accounting.** Per-transaction and per-day caps, counted against what has + already left. Crossing half the day's allowance escalates every further payment, so a drain + split into twenty pieces meets a higher bar partway through instead of never. + +4. **A loss-envelope circuit breaker.** A share of the balance that may leave per window. The + payment that would cross it **is not made**: the vault latches into Lockdown and the transaction + still succeeds, because a latch that reverts with the transaction is not a latch. The envelope + is measured against the balance when the window *opened*, so a drain cannot shrink its own + denominator. + +5. **A guardian role with no path to the money.** The contract refuses to give a guardian any + treasury role, and refuses to give a treasury member the guardian role. A guardian can freeze, + veto, block a recipient and start a recovery. It can never propose, approve or execute a + payment. It is the second control plane an attacker has to breach and the one they cannot profit + from. + +6. **A policy-change firewall.** Any change that gives up a control is detected by comparing the + old and new policy field by field — including the cases that look like tightening and are not, + such as setting a threshold to zero to disable it, or extending a proposal's lifetime. A + weakening waits out the policy-change delay, can be vetoed by any guardian, and cannot be + proposed at all while the vault is in Lockdown. + +Plus the things that make the above hold under adversarial conditions: + +- **Requirements are pinned, then tighten-only.** At execution the payment is reclassified and the + *stricter* of the pinned and live requirements applies. Tightening the policy affects payments + already in flight; loosening it cannot rescue one. +- **Approvals are recounted against the live roster.** A signer removed after approving stops + counting. The tally is never trusted as a number frozen at approval time. +- **Deposits are never gated.** Even in Lockdown, even from a stranger. The controls exist to + govern money leaving; refusing money arriving would only strand it. + +## The agent case, which is where this is going + +An organization increasingly wants software to *request* payments — an invoice processor, a +rebalancer, an LLM agent reading a vendor inbox. Nobody sensibly wants software to *authorize* +them. + +Skur has a `PROPOSER` role that can open a proposal and do nothing else. It cannot approve, cannot +confirm, cannot execute, and cannot be a guardian. A fully compromised agent key produces a queue +of proposals that no human approved. That is the difference between an automation incident and a +loss, and no threshold product can express it, because to a threshold every key is the same kind of +key. + +## Why Sui, specifically + +This is not a port looking for a chain. + +- **A vault is a shared object**, not an account with a nonce. Its policy, its roster, its + recipients and its proposals are fields on one object, so "what are the rules right now" is a + single read and not an archaeology exercise across storage slots. +- **Programmable transaction blocks** make a hot-potato setup flow possible: creating a vault + hands back a value with no abilities, so the same transaction must configure the assets and + finish, and there is no window in which a half-configured vault is reachable. +- **`sui::clock`** gives millisecond time in the transaction, so timelocks are expressed directly + rather than inferred from block numbers. +- **Typed coins** mean the treasury is keyed by type. One vault holds SUI, stablecoins and any + other coin, each with its own limits, its own day and its own envelope — without an allowlist of + token addresses to maintain or get wrong. +- **Move's abilities** make the guardian separation structural rather than conventional. + +## V1 scope + +Done and under test: + +- the Move core: types, policy, risk engine, vault, with the seven proposal kinds and the full + lifecycle; +- a TypeScript SDK on `@mysten/sui` v2 over **gRPC and GraphQL**; +- a Node/PostgreSQL indexer, notification service and advisory API; +- the chain-agnostic engines — risk classifier, policy rules, templates, maximum-loss calculation, + posture report and attack simulator — shared by every interface; +- seven starting policies, one per kind of organization: startup, operating team, protocol/DAO, + fund, payments company, nonprofit, family office. + +Explicitly not done, and we will not claim otherwise: + +- **no independent audit.** Do not put real value behind Skur until one is complete. Part of what + we are asking for is the audit. +- **no mainnet deployment.** +- **no oracle.** Exposure is per asset, as a share of that asset's own balance. A vault holding two + assets does not know their relative value, and we would rather state that than imply a + portfolio-wide number we cannot compute honestly. +- **anchored, not sliding, windows.** A day bucket anchors on its first spend. It is explained in + the security model rather than hidden. + +## On not building around JSON-RPC + +JSON-RPC was switched off on Sui Foundation mainnet full nodes in the week of 27 July 2026, with +full decommissioning — code removal included — scheduled for mid-October 2026. + +Nothing in this project depends on it, directly or transitively. That is why the frontend uses +`@mysten/dapp-kit-react` 2.x rather than `@mysten/dapp-kit` 1.x, which is deprecated precisely +because it is JSON-RPC only. The SDK's read layer is written against the transport-agnostic Core +API, so the same code runs over gRPC today and over anything that implements that contract +tomorrow. + +## Where the funding goes + +| Route | The ask | What it buys | +|---|---|---| +| **Sui Foundation RFP / grant** | Audit and testnet-to-mainnet hardening | An audited, public authorization layer any Sui organization can use, and the only onchain one with velocity and breaker controls | +| **Hackathon** | Proof under a deadline | The agent-proposer demo: an automated agent that can request payments and provably cannot take them | +| **Hydropower accelerator** | Go-to-market with real treasuries | Pilots with three to five Sui organizations; the policy templates come from what they actually need | +| **Academic Research Award** | Formal treatment of the policy algebra | A proof that "tightening-only" is sound: that no sequence of permitted changes reaches a weaker policy without the delay and the veto | +| **Strategic investment** | The product around the core | Mobile, notifications, the organization dashboard, and the integrations | + +The audit is the first ask and the honest one. Everything else is easier to fund after it. + +## What we want a reviewer to check + +Not the pitch. These: + +- [`sui/sources/vault.move`](../sui/sources/vault.move) — `execute_transfer` is where every control + is re-evaluated against live state. If that function is right, the product is right. +- [`sui/sources/policy.move`](../sui/sources/policy.move) — `reductions` is the policy firewall. The + interesting cases are the ones where a number going *down* is a loosening. +- [`sui/tests/vault_tests.move`](../sui/tests/vault_tests.move) — each test is named after the + attack. `crossing_the_loss_envelope_freezes_the_vault_instead_of_paying` is the one to read + first. +- [`docs/SUI_LANDSCAPE.md`](./SUI_LANDSCAPE.md) — the competitive pass, with what the incumbents do + and do not implement, by their own documentation. diff --git a/sdk/dist/bcs.d.ts b/sdk/dist/bcs.d.ts new file mode 100644 index 0000000..48a8af2 --- /dev/null +++ b/sdk/dist/bcs.d.ts @@ -0,0 +1,203 @@ +import { bcs } from '@mysten/sui/bcs'; +export declare const PolicyBcs: import("@mysten/sui/bcs").BcsStruct<{ + approvals_low: import("@mysten/sui/bcs").BcsType; + approvals_high: import("@mysten/sui/bcs").BcsType; + approvals_critical: import("@mysten/sui/bcs").BcsType; + governance_threshold: import("@mysten/sui/bcs").BcsType; + guardian_threshold: import("@mysten/sui/bcs").BcsType; + guardian_required_critical: import("@mysten/sui/bcs").BcsType; + delay_high: import("@mysten/sui/bcs").BcsType; + delay_critical: import("@mysten/sui/bcs").BcsType; + recipient_activation_delay: import("@mysten/sui/bcs").BcsType; + policy_change_delay: import("@mysten/sui/bcs").BcsType; + recovery_delay: import("@mysten/sui/bcs").BcsType; + proposal_ttl: import("@mysten/sui/bcs").BcsType; + high_exposure_bps: import("@mysten/sui/bcs").BcsType; + critical_exposure_bps: import("@mysten/sui/bcs").BcsType; + hard_block_exposure_bps: import("@mysten/sui/bcs").BcsType; + envelope_bps: import("@mysten/sui/bcs").BcsType; + envelope_window: import("@mysten/sui/bcs").BcsType; +}, string>; +export declare const AssetLimitsBcs: import("@mysten/sui/bcs").BcsStruct<{ + approved: import("@mysten/sui/bcs").BcsType; + low_max: import("@mysten/sui/bcs").BcsType; + high_max: import("@mysten/sui/bcs").BcsType; + per_tx_max: import("@mysten/sui/bcs").BcsType; + daily_max: import("@mysten/sui/bcs").BcsType; +}, string>; +export declare const VelocityBcs: import("@mysten/sui/bcs").BcsStruct<{ + day_anchor: import("@mysten/sui/bcs").BcsType; + day_spent: import("@mysten/sui/bcs").BcsType; + envelope_anchor: import("@mysten/sui/bcs").BcsType; + envelope_spent: import("@mysten/sui/bcs").BcsType; + envelope_basis: import("@mysten/sui/bcs").BcsType; +}, string>; +export declare const RecipientBcs: import("@mysten/sui/bcs").BcsStruct<{ + trust: import("@mysten/sui/bcs").BcsType; + registered_at: import("@mysten/sui/bcs").BcsType; + activates_at: import("@mysten/sui/bcs").BcsType; + paid_count: import("@mysten/sui/bcs").BcsType; + last_paid: import("@mysten/sui/bcs").BcsType; + label: import("@mysten/sui/bcs").BcsType; +}, string>; +export declare const ProposalBcs: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType; + kind: import("@mysten/sui/bcs").BcsType; + status: import("@mysten/sui/bcs").BcsType; + proposer: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + created_at: import("@mysten/sui/bcs").BcsType; + executable_at: import("@mysten/sui/bcs").BcsType; + expires_at: import("@mysten/sui/bcs").BcsType; + req_approvals: import("@mysten/sui/bcs").BcsType; + req_guardians: import("@mysten/sui/bcs").BcsType; + tier: import("@mysten/sui/bcs").BcsType; + reasons: import("@mysten/sui/bcs").BcsType; + exposure_bps: import("@mysten/sui/bcs").BcsType; + policy_version: import("@mysten/sui/bcs").BcsType; + reduction_mask: import("@mysten/sui/bcs").BcsType; + approvals: import("@mysten/sui/bcs").BcsStruct<{ + contents: import("@mysten/sui/bcs").BcsType> & { + length: number; + }, string>; + }, string>; + confirmations: import("@mysten/sui/bcs").BcsStruct<{ + contents: import("@mysten/sui/bcs").BcsType> & { + length: number; + }, string>; + }, string>; + asset: import("@mysten/sui/bcs").BcsType<{ + name: string; + } | null, { + name: string; + } | null | undefined, `Option<${string}>`>; + amount: import("@mysten/sui/bcs").BcsType; + recipient: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + memo: import("@mysten/sui/bcs").BcsType; + new_policy: import("@mysten/sui/bcs").BcsType<{ + approvals_low: number; + approvals_high: number; + approvals_critical: number; + governance_threshold: number; + guardian_threshold: number; + guardian_required_critical: boolean; + delay_high: string; + delay_critical: string; + recipient_activation_delay: string; + policy_change_delay: string; + recovery_delay: string; + proposal_ttl: string; + high_exposure_bps: string; + critical_exposure_bps: string; + hard_block_exposure_bps: string; + envelope_bps: string; + envelope_window: string; + } | null, { + approvals_low: number; + approvals_high: number; + approvals_critical: number; + governance_threshold: number; + guardian_threshold: number; + guardian_required_critical: boolean; + delay_high: string | number | bigint; + delay_critical: string | number | bigint; + recipient_activation_delay: string | number | bigint; + policy_change_delay: string | number | bigint; + recovery_delay: string | number | bigint; + proposal_ttl: string | number | bigint; + high_exposure_bps: string | number | bigint; + critical_exposure_bps: string | number | bigint; + hard_block_exposure_bps: string | number | bigint; + envelope_bps: string | number | bigint; + envelope_window: string | number | bigint; + } | null | undefined, `Option<${string}>`>; + new_limits: import("@mysten/sui/bcs").BcsType<{ + approved: boolean; + low_max: string; + high_max: string; + per_tx_max: string; + daily_max: string; + } | null, { + approved: boolean; + low_max: string | number | bigint; + high_max: string | number | bigint; + per_tx_max: string | number | bigint; + daily_max: string | number | bigint; + } | null | undefined, `Option<${string}>`>; + member: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + member_prev: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + member_roles: import("@mysten/sui/bcs").BcsType; + trust_level: import("@mysten/sui/bcs").BcsType; + target_mode: import("@mysten/sui/bcs").BcsType; +}, string>; +export declare const VaultBcs: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + name: import("@mysten/sui/bcs").BcsType; + policy: import("@mysten/sui/bcs").BcsStruct<{ + approvals_low: import("@mysten/sui/bcs").BcsType; + approvals_high: import("@mysten/sui/bcs").BcsType; + approvals_critical: import("@mysten/sui/bcs").BcsType; + governance_threshold: import("@mysten/sui/bcs").BcsType; + guardian_threshold: import("@mysten/sui/bcs").BcsType; + guardian_required_critical: import("@mysten/sui/bcs").BcsType; + delay_high: import("@mysten/sui/bcs").BcsType; + delay_critical: import("@mysten/sui/bcs").BcsType; + recipient_activation_delay: import("@mysten/sui/bcs").BcsType; + policy_change_delay: import("@mysten/sui/bcs").BcsType; + recovery_delay: import("@mysten/sui/bcs").BcsType; + proposal_ttl: import("@mysten/sui/bcs").BcsType; + high_exposure_bps: import("@mysten/sui/bcs").BcsType; + critical_exposure_bps: import("@mysten/sui/bcs").BcsType; + hard_block_exposure_bps: import("@mysten/sui/bcs").BcsType; + envelope_bps: import("@mysten/sui/bcs").BcsType; + envelope_window: import("@mysten/sui/bcs").BcsType; + }, string>; + policy_version: import("@mysten/sui/bcs").BcsType; + mode: import("@mysten/sui/bcs").BcsType; + posture_reasons: import("@mysten/sui/bcs").BcsType; + members: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + owner_count: import("@mysten/sui/bcs").BcsType; + approver_count: import("@mysten/sui/bcs").BcsType; + executor_count: import("@mysten/sui/bcs").BcsType; + guardian_count: import("@mysten/sui/bcs").BcsType; + limits: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + funds: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + velocity: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + recipients: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + proposals: import("@mysten/sui/bcs").BcsStruct<{ + id: import("@mysten/sui/bcs").BcsType, "bytes[32]">; + size: import("@mysten/sui/bcs").BcsType; + }, string>; + next_proposal: import("@mysten/sui/bcs").BcsType; + pending_count: import("@mysten/sui/bcs").BcsType; + created_at: import("@mysten/sui/bcs").BcsType; +}, string>; +/** `sui::balance::Balance` is a single u64 on the wire. */ +export declare const BalanceBcs: import("@mysten/sui/bcs").BcsStruct<{ + value: import("@mysten/sui/bcs").BcsType; +}, string>; +/** A `Table` entry is stored as `Field` under the table's own id. */ +export declare function fieldBcs(key: ReturnType, value: { + parse: (bytes: Uint8Array) => V; +}): { + key: import("@mysten/sui/bcs").BcsType; + value: { + parse: (bytes: Uint8Array) => V; + }; +}; +export { bcs }; +//# sourceMappingURL=bcs.d.ts.map \ No newline at end of file diff --git a/sdk/dist/bcs.d.ts.map b/sdk/dist/bcs.d.ts.map new file mode 100644 index 0000000..9efdca3 --- /dev/null +++ b/sdk/dist/bcs.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"bcs.d.ts","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwBtC,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;UAkBpB,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;UAMzB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;UAMtB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;UAOvB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BtB,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoBnB,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,UAAU;;UAA8C,CAAC;AAEtE,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,GAAG,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,EAC/B,KAAK,EAAE;IAAE,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC,CAAA;CAAE;;;eAA1B,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC;;EAGzC;AAED,OAAO,EAAE,GAAG,EAAE,CAAC"} \ No newline at end of file diff --git a/sdk/dist/bcs.js b/sdk/dist/bcs.js new file mode 100644 index 0000000..2b7edf0 --- /dev/null +++ b/sdk/dist/bcs.js @@ -0,0 +1,117 @@ +import { bcs } from '@mysten/sui/bcs'; +/** + * BCS layouts for the Move structs, in declaration order. BCS is positional, so these must match + * `sui/sources/*.move` field for field — reordering a field in Move without reordering it here + * silently misreads every vault. + * + * Parsed over the `content` bytes from `getObject({ include: { content: true } })`, which is the + * stable representation. The `json` include is explicitly documented as not guaranteed across + * clients, so nothing here uses it. + */ +/** `sui::object::UID` is a single 32-byte id on the wire. */ +const UID = bcs.Address; +/** `sui::table::Table` and `sui::bag::Bag` both serialise as a handle plus a count. */ +const Handle = bcs.struct('Handle', { id: UID, size: bcs.u64() }); +const TypeNameBcs = bcs.struct('TypeName', { name: bcs.string() }); +const VecSetAddress = bcs.struct('VecSet
      ', { + contents: bcs.vector(bcs.Address), +}); +export const PolicyBcs = bcs.struct('Policy', { + approvals_low: bcs.u8(), + approvals_high: bcs.u8(), + approvals_critical: bcs.u8(), + governance_threshold: bcs.u8(), + guardian_threshold: bcs.u8(), + guardian_required_critical: bcs.bool(), + delay_high: bcs.u64(), + delay_critical: bcs.u64(), + recipient_activation_delay: bcs.u64(), + policy_change_delay: bcs.u64(), + recovery_delay: bcs.u64(), + proposal_ttl: bcs.u64(), + high_exposure_bps: bcs.u64(), + critical_exposure_bps: bcs.u64(), + hard_block_exposure_bps: bcs.u64(), + envelope_bps: bcs.u64(), + envelope_window: bcs.u64(), +}); +export const AssetLimitsBcs = bcs.struct('AssetLimits', { + approved: bcs.bool(), + low_max: bcs.u64(), + high_max: bcs.u64(), + per_tx_max: bcs.u64(), + daily_max: bcs.u64(), +}); +export const VelocityBcs = bcs.struct('Velocity', { + day_anchor: bcs.u64(), + day_spent: bcs.u64(), + envelope_anchor: bcs.u64(), + envelope_spent: bcs.u64(), + envelope_basis: bcs.u64(), +}); +export const RecipientBcs = bcs.struct('Recipient', { + trust: bcs.u8(), + registered_at: bcs.u64(), + activates_at: bcs.u64(), + paid_count: bcs.u64(), + last_paid: bcs.u64(), + label: bcs.string(), +}); +export const ProposalBcs = bcs.struct('Proposal', { + id: bcs.u64(), + kind: bcs.u8(), + status: bcs.u8(), + proposer: bcs.Address, + created_at: bcs.u64(), + executable_at: bcs.u64(), + expires_at: bcs.u64(), + req_approvals: bcs.u8(), + req_guardians: bcs.u8(), + tier: bcs.u8(), + reasons: bcs.u16(), + exposure_bps: bcs.u64(), + policy_version: bcs.u64(), + reduction_mask: bcs.u32(), + approvals: VecSetAddress, + confirmations: VecSetAddress, + asset: bcs.option(TypeNameBcs), + amount: bcs.u64(), + recipient: bcs.Address, + memo: bcs.string(), + new_policy: bcs.option(PolicyBcs), + new_limits: bcs.option(AssetLimitsBcs), + member: bcs.Address, + member_prev: bcs.Address, + member_roles: bcs.u8(), + trust_level: bcs.u8(), + target_mode: bcs.u8(), +}); +export const VaultBcs = bcs.struct('Vault', { + id: UID, + name: bcs.string(), + policy: PolicyBcs, + policy_version: bcs.u64(), + mode: bcs.u8(), + posture_reasons: bcs.u16(), + members: Handle, + owner_count: bcs.u64(), + approver_count: bcs.u64(), + executor_count: bcs.u64(), + guardian_count: bcs.u64(), + limits: Handle, + funds: Handle, + velocity: Handle, + recipients: Handle, + proposals: Handle, + next_proposal: bcs.u64(), + pending_count: bcs.u64(), + created_at: bcs.u64(), +}); +/** `sui::balance::Balance` is a single u64 on the wire. */ +export const BalanceBcs = bcs.struct('Balance', { value: bcs.u64() }); +/** A `Table` entry is stored as `Field` under the table's own id. */ +export function fieldBcs(key, value) { + return { key, value }; +} +export { bcs }; +//# sourceMappingURL=bcs.js.map \ No newline at end of file diff --git a/sdk/dist/bcs.js.map b/sdk/dist/bcs.js.map new file mode 100644 index 0000000..d4a74cb --- /dev/null +++ b/sdk/dist/bcs.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bcs.js","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/format.d.ts b/sdk/dist/engine/format.d.ts new file mode 100644 index 0000000..a192e75 --- /dev/null +++ b/sdk/dist/engine/format.d.ts @@ -0,0 +1,17 @@ +/** + * Formatting for amounts, durations and shares. No chain dependency: the EVM build imported these + * from viem, which is why they are implemented here instead. + * + * Durations are milliseconds throughout, matching `sui::clock`. + */ +export declare function formatUnits(value: bigint, decimals: number): string; +export declare function parseUnits(text: string, decimals: number): bigint | null; +export declare function short(addr: string, n?: number): string; +export declare function fmtAmount(value: bigint, decimals: number, symbol?: string, maxFrac?: number): string; +export declare function parseAmount(text: string, decimals: number): bigint | null; +export declare function fmtBps(bps: number): string; +/** Milliseconds to something a person reads. */ +export declare function fmtDuration(ms: number): string; +export declare function fmtTimestamp(ms: number | bigint): string; +export declare function fmtRelative(ms: number | bigint, now?: number): string; +//# sourceMappingURL=format.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/format.d.ts.map b/sdk/dist/engine/format.d.ts.map new file mode 100644 index 0000000..2c7384e --- /dev/null +++ b/sdk/dist/engine/format.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/engine/format.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQnE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASxE;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,MAAM,CAIjD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAO/F;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzE;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAW9C;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAIxD;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAa,GAAG,MAAM,CAOzE"} \ No newline at end of file diff --git a/sdk/dist/engine/format.js b/sdk/dist/engine/format.js new file mode 100644 index 0000000..6c09f10 --- /dev/null +++ b/sdk/dist/engine/format.js @@ -0,0 +1,83 @@ +/** + * Formatting for amounts, durations and shares. No chain dependency: the EVM build imported these + * from viem, which is why they are implemented here instead. + * + * Durations are milliseconds throughout, matching `sui::clock`. + */ +export function formatUnits(value, decimals) { + const neg = value < 0n; + const abs = neg ? -value : value; + const base = 10n ** BigInt(decimals); + const int = abs / base; + const frac = abs % base; + const fracText = decimals === 0 ? '' : frac.toString().padStart(decimals, '0').replace(/0+$/, ''); + return `${neg ? '-' : ''}${int}${fracText ? `.${fracText}` : ''}`; +} +export function parseUnits(text, decimals) { + const cleaned = text.replace(/[, _]/g, '').trim(); + if (!cleaned || !/^-?\d*(\.\d*)?$/.test(cleaned)) + return null; + const neg = cleaned.startsWith('-'); + const body = neg ? cleaned.slice(1) : cleaned; + const [int = '0', frac = ''] = body.split('.'); + if (frac.length > decimals) + return null; + const scaled = BigInt(int || '0') * 10n ** BigInt(decimals) + BigInt((frac || '0').padEnd(decimals, '0') || '0'); + return neg ? -scaled : scaled; +} +export function short(addr, n = 4) { + if (!addr) + return ''; + if (addr.length <= 2 * n + 3) + return addr; + return `${addr.slice(0, 2 + n)}…${addr.slice(-n)}`; +} +export function fmtAmount(value, decimals, symbol, maxFrac = 2) { + const s = formatUnits(value, decimals); + const [int, frac = ''] = s.split('.'); + const intFmt = Number(int).toLocaleString('en-US'); + const fracTrim = frac.slice(0, maxFrac).replace(/0+$/, ''); + const out = fracTrim ? `${intFmt}.${fracTrim}` : intFmt; + return symbol ? `${out} ${symbol}` : out; +} +export function parseAmount(text, decimals) { + const v = parseUnits(text, decimals); + return v === null || v < 0n ? null : v; +} +export function fmtBps(bps) { + return `${(bps / 100).toFixed(bps % 100 === 0 ? 0 : 2)}%`; +} +/** Milliseconds to something a person reads. */ +export function fmtDuration(ms) { + if (ms <= 0) + return 'none'; + const totalMinutes = Math.floor(ms / 60_000); + const d = Math.floor(totalMinutes / 1440); + const h = Math.floor((totalMinutes % 1440) / 60); + const m = totalMinutes % 60; + const parts = []; + if (d) + parts.push(`${d}d`); + if (h) + parts.push(`${h}h`); + if (m && !d) + parts.push(`${m}m`); + return parts.join(' ') || `${Math.round(ms / 1000)}s`; +} +export function fmtTimestamp(ms) { + const n = Number(ms); + if (!n) + return '—'; + return new Date(n).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' }); +} +export function fmtRelative(ms, now = Date.now()) { + const n = Number(ms); + if (!n) + return '—'; + const diff = n - now; + if (Math.abs(diff) < 60_000) + return diff >= 0 ? 'now' : 'just now'; + const abs = fmtDuration(Math.abs(diff)); + return diff > 0 ? `in ${abs}` : `${abs} ago`; +} +//# sourceMappingURL=format.js.map \ No newline at end of file diff --git a/sdk/dist/engine/format.js.map b/sdk/dist/engine/format.js.map new file mode 100644 index 0000000..dd1f9da --- /dev/null +++ b/sdk/dist/engine/format.js.map @@ -0,0 +1 @@ +{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/engine/format.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/index.d.ts b/sdk/dist/engine/index.d.ts new file mode 100644 index 0000000..22517a8 --- /dev/null +++ b/sdk/dist/engine/index.d.ts @@ -0,0 +1,18 @@ +/** + * The chain-agnostic core. These are the engines that make a Skur vault more than a threshold: + * the risk classifier, the policy rules and what counts as weakening them, the organization + * templates, the maximum-loss calculation, the posture report and the attack simulator. + * + * Every one of them mirrors a Move module and is pinned against the Move tests. They exist in + * TypeScript so an interface can preview a policy that is not deployed yet; for a live vault the + * chain is always authoritative. + */ +export * from './format.js'; +export * from './maxLoss.js'; +export * from './policy.js'; +export * from './policyFields.js'; +export * from './posture.js'; +export * from './risk.js'; +export * from './simulator.js'; +export * from './templates.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/index.d.ts.map b/sdk/dist/engine/index.d.ts.map new file mode 100644 index 0000000..8e64f37 --- /dev/null +++ b/sdk/dist/engine/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"} \ No newline at end of file diff --git a/sdk/dist/engine/index.js b/sdk/dist/engine/index.js new file mode 100644 index 0000000..c576dad --- /dev/null +++ b/sdk/dist/engine/index.js @@ -0,0 +1,18 @@ +/** + * The chain-agnostic core. These are the engines that make a Skur vault more than a threshold: + * the risk classifier, the policy rules and what counts as weakening them, the organization + * templates, the maximum-loss calculation, the posture report and the attack simulator. + * + * Every one of them mirrors a Move module and is pinned against the Move tests. They exist in + * TypeScript so an interface can preview a policy that is not deployed yet; for a live vault the + * chain is always authoritative. + */ +export * from './format.js'; +export * from './maxLoss.js'; +export * from './policy.js'; +export * from './policyFields.js'; +export * from './posture.js'; +export * from './risk.js'; +export * from './simulator.js'; +export * from './templates.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/sdk/dist/engine/index.js.map b/sdk/dist/engine/index.js.map new file mode 100644 index 0000000..dcb53af --- /dev/null +++ b/sdk/dist/engine/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"} \ No newline at end of file diff --git a/sdk/dist/engine/maxLoss.d.ts b/sdk/dist/engine/maxLoss.d.ts new file mode 100644 index 0000000..b6b406d --- /dev/null +++ b/sdk/dist/engine/maxLoss.d.ts @@ -0,0 +1,23 @@ +import { Mode, type AssetLimits, type Policy } from '../types.js'; +/** + * Maximum possible loss per asset, turned from a policy into numbers a finance team can act on. + * + * Conservative by construction: it assumes every signer a tier needs is compromised and + * cooperating, and that the attacker picks amounts optimally. It is an upper bound under the + * stated assumptions and never a guarantee — the assumptions are returned alongside the numbers + * so they cannot be quoted without them. + */ +export type MaxLoss = { + /** The most that can leave with no delay at all. */ + immediate: bigint; + /** The most that can leave within a day if no guardian acts. */ + day: bigint; + criticalDelay: number; + highDelay: number; + /** Which control produced each number. */ + immediateBinding: string; + dayBinding: string; + assumptions: string[]; +}; +export declare function computeMaxLoss(policy: Policy, limits: AssetLimits, balance: bigint, mode: Mode): MaxLoss; +//# sourceMappingURL=maxLoss.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/maxLoss.d.ts.map b/sdk/dist/engine/maxLoss.d.ts.map new file mode 100644 index 0000000..4364608 --- /dev/null +++ b/sdk/dist/engine/maxLoss.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"maxLoss.d.ts","sourceRoot":"","sources":["../../src/engine/maxLoss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,IAAI,EAAE,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAIvE;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,oDAAoD;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,CAAC;AAMF,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,GACT,OAAO,CA6ET"} \ No newline at end of file diff --git a/sdk/dist/engine/maxLoss.js b/sdk/dist/engine/maxLoss.js new file mode 100644 index 0000000..37a6270 --- /dev/null +++ b/sdk/dist/engine/maxLoss.js @@ -0,0 +1,80 @@ +import { DAY, Mode } from '../types.js'; +import { effectiveCaps } from './risk.js'; +import { fmtDuration } from './format.js'; +function min(...xs) { + return xs.reduce((a, b) => (b < a ? b : a)); +} +export function computeMaxLoss(policy, limits, balance, mode) { + const caps = effectiveCaps(limits.perTxMax, limits.dailyMax, mode); + const assumptions = [ + 'Enough approvers to satisfy each tier are compromised and cooperate.', + 'Executors are compromised or colluding.', + 'No guardian vetoes or freezes the vault during any delay window.', + 'The attacker pays addresses that are already activated, not in probation.', + 'Limits are per asset: each asset has its own caps and its own envelope.', + ]; + // Immediate: the routine tier needs no delay, so an attacker repeats it until a cumulative + // control binds. In Elevated there is no undelayed tier at all. + let immediate = 0n; + let immediateBinding = 'no undelayed tier'; + if (mode === Mode.NORMAL) { + const exposureLow = policy.highExposureBps === 0 + ? balance + : (balance * BigInt(Math.max(policy.highExposureBps - 1, 0))) / 10000n; + const perTransfer = min(limits.lowMax, caps.perTxMax || limits.lowMax, exposureLow); + if (perTransfer > 0n) { + immediate = balance; + immediateBinding = 'the entire balance (no daily cap and no envelope)'; + const envelope = policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10000n; + if (caps.dailyMax !== 0n && caps.dailyMax < immediate) { + immediate = caps.dailyMax; + immediateBinding = 'the daily cap'; + } + if (envelope !== 0n && envelope < immediate) { + immediate = envelope; + immediateBinding = `the loss envelope per ${fmtDuration(policy.envelopeWindow)}`; + } + } + else { + immediateBinding = 'the routine tier is disabled by the limits'; + } + } + // Within a day: the high tier is also reachable if its delay is under a day. Either way the + // attacker can straddle a bucket boundary and get two windows' worth. + const envelope = policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10000n; + const perTx = caps.perTxMax === 0n ? balance : caps.perTxMax; + const highCeiling = policy.criticalExposureBps === 0 + ? balance + : (balance * BigInt(Math.max(policy.criticalExposureBps - 1, 0))) / 10000n; + const candidates = [[balance, 'the entire balance']]; + if (caps.dailyMax !== 0n) + candidates.push([caps.dailyMax * 2n, 'two daily buckets across a boundary']); + if (envelope !== 0n) + candidates.push([envelope * 2n, 'two envelope windows across a boundary']); + if (policy.delayHigh >= DAY) { + candidates.push([immediate * 2n, 'the routine tier only, across two buckets']); + } + else { + candidates.push([ + min(perTx, highCeiling) === 0n ? 0n : balance, + 'the high tier, reachable within a day', + ]); + } + let [day, dayBinding] = candidates.reduce((a, b) => (b[0] < a[0] ? b : a)); + if (mode === Mode.LOCKDOWN) { + immediate = 0n; + day = 0n; + immediateBinding = 'the vault is in Lockdown'; + dayBinding = 'the vault is in Lockdown'; + } + return { + immediate, + day, + criticalDelay: policy.delayCritical, + highDelay: policy.delayHigh, + immediateBinding, + dayBinding, + assumptions, + }; +} +//# sourceMappingURL=maxLoss.js.map \ No newline at end of file diff --git a/sdk/dist/engine/maxLoss.js.map b/sdk/dist/engine/maxLoss.js.map new file mode 100644 index 0000000..8c4b870 --- /dev/null +++ b/sdk/dist/engine/maxLoss.js.map @@ -0,0 +1 @@ +{"version":3,"file":"maxLoss.js","sourceRoot":"","sources":["../../src/engine/maxLoss.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/policy.d.ts b/sdk/dist/engine/policy.d.ts new file mode 100644 index 0000000..de68607 --- /dev/null +++ b/sdk/dist/engine/policy.d.ts @@ -0,0 +1,14 @@ +import { Trust, type AssetLimits, type Policy } from '../types.js'; +export declare const OK = 0; +export declare function validatePolicyCode(p: Policy): number; +export declare function longestDelay(p: Policy): number; +/** Every failing rule, not just the first, so an editor can mark all of them at once. */ +export declare function validatePolicy(p: Policy): string[]; +export declare function validateLimits(l: AssetLimits): string[]; +export declare function validateCounts(p: Policy, owners: number, approvers: number, executors: number, guardians: number): string[]; +/** The fields `b` gives up relative to `a`. Empty means the change only tightens. */ +export declare function policyReductions(a: Policy, b: Policy): string[]; +export declare function limitReductions(a: AssetLimits, b: AssetLimits): string[]; +/** Raising trust, or lifting a restriction, is security-reducing; tightening is not. */ +export declare function trustReduces(from: Trust, to: Trust): boolean; +//# sourceMappingURL=policy.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/policy.d.ts.map b/sdk/dist/engine/policy.d.ts.map new file mode 100644 index 0000000..6549188 --- /dev/null +++ b/sdk/dist/engine/policy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/engine/policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,EAAE,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAS9E,eAAO,MAAM,EAAE,IAAI,CAAC;AAEpB,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAepD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAiBlD;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,CAKvD;AAED,wBAAgB,cAAc,CAC5B,CAAC,EAAE,MAAM,EACT,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAWV;AASD,qFAAqF;AACrF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B/D;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,CAQxE;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAK5D"} \ No newline at end of file diff --git a/sdk/dist/engine/policy.js b/sdk/dist/engine/policy.js new file mode 100644 index 0000000..6e5a81e --- /dev/null +++ b/sdk/dist/engine/policy.js @@ -0,0 +1,165 @@ +import { BPS, HOUR, Trust } from '../types.js'; +import { POLICY_ERRORS } from '../errors.js'; +/** + * Mirror of `sui/sources/policy.move`. The codes are the Move abort codes, so a draft validated + * here fails for the same reason and with the same number as it would on chain. + */ +const MIN_EXECUTION_WINDOW = HOUR; +export const OK = 0; +export function validatePolicyCode(p) { + if (p.approvalsLow === 0) + return 1; + if (p.approvalsHigh < p.approvalsLow) + return 2; + if (p.approvalsCritical < p.approvalsHigh) + return 3; + if (p.governanceThreshold === 0) + return 4; + if (p.guardianRequiredCritical && p.guardianThreshold === 0) + return 5; + if (p.delayCritical < p.delayHigh) + return 6; + if (p.criticalExposureBps !== 0 && p.highExposureBps > p.criticalExposureBps) + return 7; + if (p.criticalExposureBps > Number(BPS) || p.highExposureBps > Number(BPS)) + return 8; + if (p.hardBlockExposureBps !== 0 && p.hardBlockExposureBps < p.criticalExposureBps) + return 9; + if (p.hardBlockExposureBps > Number(BPS)) + return 10; + if (p.envelopeBps > Number(BPS)) + return 11; + if (p.envelopeBps !== 0 && p.envelopeWindow < MIN_EXECUTION_WINDOW) + return 12; + if (p.proposalTtl < longestDelay(p) + MIN_EXECUTION_WINDOW) + return 13; + return OK; +} +export function longestDelay(p) { + return Math.max(p.delayCritical, p.policyChangeDelay, p.recoveryDelay, p.recipientActivationDelay); +} +/** Every failing rule, not just the first, so an editor can mark all of them at once. */ +export function validatePolicy(p) { + const errs = []; + const push = (code) => errs.push(POLICY_ERRORS[code]); + if (p.approvalsLow === 0) + push(1); + if (p.approvalsHigh < p.approvalsLow) + push(2); + if (p.approvalsCritical < p.approvalsHigh) + push(3); + if (p.governanceThreshold === 0) + push(4); + if (p.guardianRequiredCritical && p.guardianThreshold === 0) + push(5); + if (p.delayCritical < p.delayHigh) + push(6); + if (p.criticalExposureBps !== 0 && p.highExposureBps > p.criticalExposureBps) + push(7); + if (p.criticalExposureBps > Number(BPS) || p.highExposureBps > Number(BPS)) + push(8); + if (p.hardBlockExposureBps !== 0 && p.hardBlockExposureBps < p.criticalExposureBps) + push(9); + if (p.hardBlockExposureBps > Number(BPS)) + push(10); + if (p.envelopeBps > Number(BPS)) + push(11); + if (p.envelopeBps !== 0 && p.envelopeWindow < MIN_EXECUTION_WINDOW) + push(12); + if (p.proposalTtl < longestDelay(p) + MIN_EXECUTION_WINDOW) + push(13); + return errs; +} +export function validateLimits(l) { + const errs = []; + if (l.lowMax > l.highMax) + errs.push(POLICY_ERRORS[20]); + if (l.perTxMax !== 0n && l.dailyMax !== 0n && l.perTxMax > l.dailyMax) + errs.push(POLICY_ERRORS[21]); + return errs; +} +export function validateCounts(p, owners, approvers, executors, guardians) { + const errs = []; + if (owners < 1) + errs.push(POLICY_ERRORS[30]); + if (executors < 1) + errs.push(POLICY_ERRORS[31]); + if (owners < p.governanceThreshold) + errs.push(`The governance threshold (${p.governanceThreshold}) exceeds the number of owners (${owners}).`); + if (approvers < p.approvalsCritical) + errs.push(`Critical approvals (${p.approvalsCritical}) exceed the number of approvers (${approvers}).`); + if (guardians < p.guardianThreshold) + errs.push(`The guardian threshold (${p.guardianThreshold}) exceeds the number of guardians (${guardians}).`); + return errs; +} +/** Where zero means "disabled", going to zero is the loosest move available. */ +function thresholdLoosens(a, b) { + if (a === 0 || a === 0n) + return false; + if (b === 0 || b === 0n) + return true; + return b > a; +} +/** The fields `b` gives up relative to `a`. Empty means the change only tightens. */ +export function policyReductions(a, b) { + const out = []; + if (b.approvalsLow < a.approvalsLow) + out.push('fewer approvals for routine payments'); + if (b.approvalsHigh < a.approvalsHigh) + out.push('fewer approvals for high-risk payments'); + if (b.approvalsCritical < a.approvalsCritical) + out.push('fewer approvals for critical payments'); + if (b.governanceThreshold < a.governanceThreshold) + out.push('a lower governance threshold'); + if (b.guardianThreshold < a.guardianThreshold) + out.push('fewer guardian confirmations'); + if (a.guardianRequiredCritical && !b.guardianRequiredCritical) + out.push('no guardian required for critical payments'); + if (b.delayHigh < a.delayHigh) + out.push('a shorter high-risk delay'); + if (b.delayCritical < a.delayCritical) + out.push('a shorter critical delay'); + if (b.recipientActivationDelay < a.recipientActivationDelay) + out.push('a shorter new-recipient delay'); + if (b.policyChangeDelay < a.policyChangeDelay) + out.push('a shorter policy-change delay'); + if (b.recoveryDelay < a.recoveryDelay) + out.push('a shorter recovery delay'); + if (b.proposalTtl > a.proposalTtl) + out.push('a longer proposal lifetime'); + if (thresholdLoosens(a.highExposureBps, b.highExposureBps)) + out.push('a higher exposure threshold before escalation'); + if (thresholdLoosens(a.criticalExposureBps, b.criticalExposureBps)) + out.push('a higher exposure threshold before critical'); + if (thresholdLoosens(a.hardBlockExposureBps, b.hardBlockExposureBps)) + out.push('a weaker exposure hard block'); + if (thresholdLoosens(a.envelopeBps, b.envelopeBps)) + out.push('a larger loss envelope'); + if (a.envelopeBps !== 0 && b.envelopeWindow < a.envelopeWindow) + out.push('a shorter envelope window'); + return out; +} +export function limitReductions(a, b) { + const out = []; + if (!a.approved && b.approved) + out.push('approving a new asset'); + if (b.lowMax > a.lowMax) + out.push('a higher routine maximum'); + if (b.highMax > a.highMax) + out.push('a higher high-tier maximum'); + if (thresholdLoosens(a.perTxMax, b.perTxMax)) + out.push('a weaker per-transaction cap'); + if (thresholdLoosens(a.dailyMax, b.dailyMax)) + out.push('a weaker daily cap'); + return out; +} +/** Raising trust, or lifting a restriction, is security-reducing; tightening is not. */ +export function trustReduces(from, to) { + const heldBack = from === Trust.RESTRICTED || from === Trust.BLOCKED || from === Trust.UNKNOWN; + if (heldBack && to !== Trust.RESTRICTED && to !== Trust.BLOCKED) + return true; + if (to === Trust.BLOCKED || to === Trust.RESTRICTED) + return false; + return to > from; +} +//# sourceMappingURL=policy.js.map \ No newline at end of file diff --git a/sdk/dist/engine/policy.js.map b/sdk/dist/engine/policy.js.map new file mode 100644 index 0000000..ae4a3df --- /dev/null +++ b/sdk/dist/engine/policy.js.map @@ -0,0 +1 @@ +{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/engine/policy.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/policyFields.d.ts b/sdk/dist/engine/policyFields.d.ts new file mode 100644 index 0000000..e742ff9 --- /dev/null +++ b/sdk/dist/engine/policyFields.d.ts @@ -0,0 +1,20 @@ +import { type Policy } from '../types.js'; +/** Field metadata for the policy editor, shared by every interface. */ +export type Unit = 'count' | 'hours' | 'bps' | 'bool'; +export type PolicyField = { + key: keyof Policy; + label: string; + hint: string; + unit: Unit; + max?: number; +}; +/** Editors show hours; the policy stores milliseconds. */ +export declare const HOUR_MS: number; +export declare const toHours: (ms: number) => number; +export declare const fromHours: (h: number) => number; +export declare const POLICY_GROUPS: { + title: string; + sub: string; + fields: PolicyField[]; +}[]; +//# sourceMappingURL=policyFields.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/policyFields.d.ts.map b/sdk/dist/engine/policyFields.d.ts.map new file mode 100644 index 0000000..eccac30 --- /dev/null +++ b/sdk/dist/engine/policyFields.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"policyFields.d.ts","sourceRoot":"","sources":["../../src/engine/policyFields.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEhD,uEAAuE;AACvE,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AACtD,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,0DAA0D;AAC1D,eAAO,MAAM,OAAO,QAAO,CAAC;AAC5B,eAAO,MAAM,OAAO,GAAI,IAAI,MAAM,WAAc,CAAC;AACjD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,WAAyB,CAAC;AAE7D,eAAO,MAAM,aAAa,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,EAAE,CAAA;CAAE,EA0ChF,CAAC"} \ No newline at end of file diff --git a/sdk/dist/engine/policyFields.js b/sdk/dist/engine/policyFields.js new file mode 100644 index 0000000..7bb8fd4 --- /dev/null +++ b/sdk/dist/engine/policyFields.js @@ -0,0 +1,49 @@ +import { HOUR } from '../types.js'; +/** Editors show hours; the policy stores milliseconds. */ +export const HOUR_MS = HOUR; +export const toHours = (ms) => ms / HOUR; +export const fromHours = (h) => Math.round(h * HOUR); +export const POLICY_GROUPS = [ + { + title: 'Approvals', + sub: 'How many confirmations each tier needs. Guardians confirm critical payments in addition to approvers.', + fields: [ + { key: 'approvalsLow', label: 'Routine', hint: 'Payments under the routine maximum.', unit: 'count' }, + { key: 'approvalsHigh', label: 'High risk', hint: 'Larger payments, new recipients, elevated posture.', unit: 'count' }, + { key: 'approvalsCritical', label: 'Critical', hint: 'Very large or high-exposure payments.', unit: 'count' }, + { key: 'guardianRequiredCritical', label: 'Guardian required for critical', hint: 'An independent sign-off on the largest payments.', unit: 'bool' }, + { key: 'guardianThreshold', label: 'Guardian confirmations', hint: 'For critical payments, leaving Lockdown, and recovery.', unit: 'count' }, + { key: 'governanceThreshold', label: 'Owner approvals for governance', hint: 'Policy, limits, signers, trust and mode changes.', unit: 'count' }, + ], + }, + { + title: 'Delays', + sub: 'A delay gives guardians a veto window and gives the organization time to notice.', + fields: [ + { key: 'delayHigh', label: 'High-risk delay', hint: 'Between full approval and execution.', unit: 'hours' }, + { key: 'delayCritical', label: 'Critical delay', hint: 'Also the guardian veto window.', unit: 'hours' }, + { key: 'recipientActivationDelay', label: 'New-recipient activation', hint: 'A never-paid address cannot be paid sooner.', unit: 'hours' }, + { key: 'policyChangeDelay', label: 'Security-reducing change delay', hint: 'Any loosening waits this long and can be vetoed.', unit: 'hours' }, + { key: 'recoveryDelay', label: 'Recovery delay', hint: 'Owners can cancel a recovery during it.', unit: 'hours' }, + { key: 'proposalTtl', label: 'Proposal lifetime', hint: 'Must exceed the longest delay by at least an hour.', unit: 'hours' }, + ], + }, + { + title: 'Exposure', + sub: "Share of the asset's holdings a single payment may move before it is escalated or refused.", + fields: [ + { key: 'highExposureBps', label: 'Escalate to high risk at', hint: 'Percent of holdings.', unit: 'bps', max: 100 }, + { key: 'criticalExposureBps', label: 'Escalate to critical at', hint: '', unit: 'bps', max: 100 }, + { key: 'hardBlockExposureBps', label: 'Refuse above', hint: '0 disables the hard block.', unit: 'bps', max: 100 }, + ], + }, + { + title: 'Circuit breaker', + sub: 'Cumulative outflow per window, as a share of the balance when the window opened. The payment that would cross it is not made; the vault enters Lockdown.', + fields: [ + { key: 'envelopeBps', label: 'Loss envelope', hint: '0 disables the breaker.', unit: 'bps', max: 100 }, + { key: 'envelopeWindow', label: 'Envelope window', hint: 'At least one hour.', unit: 'hours' }, + ], + }, +]; +//# sourceMappingURL=policyFields.js.map \ No newline at end of file diff --git a/sdk/dist/engine/policyFields.js.map b/sdk/dist/engine/policyFields.js.map new file mode 100644 index 0000000..0dca1bc --- /dev/null +++ b/sdk/dist/engine/policyFields.js.map @@ -0,0 +1 @@ +{"version":3,"file":"policyFields.js","sourceRoot":"","sources":["../../src/engine/policyFields.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/posture.d.ts b/sdk/dist/engine/posture.d.ts new file mode 100644 index 0000000..5ee0fbe --- /dev/null +++ b/sdk/dist/engine/posture.d.ts @@ -0,0 +1,19 @@ +import { type AssetLimits, type Policy } from '../types.js'; +/** + * Plain-language posture checks. This reports confirmed controls and obvious weaknesses; it does + * not claim to measure absolute security, and it deliberately produces no score. + */ +export type PostureItem = { + ok: 'ok' | 'warn' | 'bad'; + text: string; +}; +export type PostureInput = { + policy: Policy; + guardians: number; + assets: { + symbol: string; + limits: AssetLimits; + }[]; +}; +export declare function postureItems({ policy: p, guardians: g, assets }: PostureInput): PostureItem[]; +//# sourceMappingURL=posture.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/posture.d.ts.map b/sdk/dist/engine/posture.d.ts.map new file mode 100644 index 0000000..f50b8c2 --- /dev/null +++ b/sdk/dist/engine/posture.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"posture.d.ts","sourceRoot":"","sources":["../../src/engine/posture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAGjE;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,CAAC;CACnD,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,YAAY,GAAG,WAAW,EAAE,CA8D7F"} \ No newline at end of file diff --git a/sdk/dist/engine/posture.js b/sdk/dist/engine/posture.js new file mode 100644 index 0000000..3dda6a4 --- /dev/null +++ b/sdk/dist/engine/posture.js @@ -0,0 +1,66 @@ +import { DAY } from '../types.js'; +import { fmtDuration } from './format.js'; +export function postureItems({ policy: p, guardians: g, assets }) { + const everyAssetCapped = assets.length > 0 && assets.every((a) => a.limits.dailyMax > 0n); + return [ + { + ok: g > 0 ? 'ok' : 'bad', + text: g > 0 + ? `${g} independent guardian${g === 1 ? '' : 's'} configured` + : 'No guardian: nobody independent can veto or freeze the vault', + }, + { + ok: p.guardianRequiredCritical ? 'ok' : 'warn', + text: p.guardianRequiredCritical + ? 'Critical payments need guardian confirmation' + : 'Critical payments do not need a guardian', + }, + { + ok: p.delayCritical >= DAY ? 'ok' : 'warn', + text: `Critical payments wait ${fmtDuration(p.delayCritical)}`, + }, + { + ok: p.recipientActivationDelay > 0 ? 'ok' : 'bad', + text: p.recipientActivationDelay > 0 + ? `New recipients wait ${fmtDuration(p.recipientActivationDelay)}` + : 'New recipients can be paid immediately', + }, + { + ok: everyAssetCapped ? 'ok' : 'warn', + text: everyAssetCapped + ? 'A 24-hour outflow cap on every approved asset' + : 'Some approved assets have no 24-hour cap', + }, + { + ok: p.envelopeBps > 0 ? 'ok' : 'warn', + text: p.envelopeBps > 0 + ? `Circuit breaker at ${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}` + : 'No loss envelope configured', + }, + { + ok: p.policyChangeDelay > 0 ? 'ok' : 'bad', + text: p.policyChangeDelay > 0 + ? `Weakening the policy waits ${fmtDuration(p.policyChangeDelay)} and can be vetoed` + : 'The policy can be weakened immediately', + }, + { + ok: p.recoveryDelay > 0 && g > 0 ? 'ok' : 'warn', + text: p.recoveryDelay > 0 && g > 0 + ? `Signer recovery available after ${fmtDuration(p.recoveryDelay)}` + : 'No usable recovery path', + }, + { + ok: p.approvalsLow >= 2 ? 'ok' : 'warn', + text: p.approvalsLow >= 2 + ? 'Routine payments need two approvals' + : 'Routine payments need a single approval', + }, + { + ok: p.hardBlockExposureBps > 0 ? 'ok' : 'warn', + text: p.hardBlockExposureBps > 0 + ? `No single payment may exceed ${p.hardBlockExposureBps / 100}% of an asset` + : 'No hard block: a single payment could take the whole balance if approved', + }, + ]; +} +//# sourceMappingURL=posture.js.map \ No newline at end of file diff --git a/sdk/dist/engine/posture.js.map b/sdk/dist/engine/posture.js.map new file mode 100644 index 0000000..c13764c --- /dev/null +++ b/sdk/dist/engine/posture.js.map @@ -0,0 +1 @@ +{"version":3,"file":"posture.js","sourceRoot":"","sources":["../../src/engine/posture.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/risk.d.ts b/sdk/dist/engine/risk.d.ts new file mode 100644 index 0000000..7cb60f3 --- /dev/null +++ b/sdk/dist/engine/risk.d.ts @@ -0,0 +1,40 @@ +import { Mode, Tier, Trust, type Policy } from '../types.js'; +/** + * Mirror of `sui/sources/risk.move`. Used to preview a transfer against a policy that is not + * deployed yet, and to drive the simulator. + * + * For a live vault, prefer `previewTransfer` from `../vault`, which simulates the chain's own + * `preview_transfer` so the answer is the contract's and not this file's. These vectors are pinned + * against the Move tests in `sui/tests/engine_tests.move`. + */ +export type RiskInput = { + amount: bigint; + assetBalance: bigint; + lowMax: bigint; + highMax: bigint; + dailyMax: bigint; + daySpent: bigint; + trust: Trust; + inProbation: boolean; + mode: Mode; + highExposureBps: number; + criticalExposureBps: number; +}; +export type RiskOutput = { + tier: Tier; + reasons: number; + exposureBps: number; +}; +export declare function exposureBps(amount: bigint, balance: bigint): number; +export declare function classify(i: RiskInput): RiskOutput; +export declare function requirements(p: Policy, tier: Tier): { + approvals: number; + guardians: number; + delay: number; +}; +/** Elevated halves the caps, floored at one unit. No cap stays no cap. */ +export declare function effectiveCaps(perTxMax: bigint, dailyMax: bigint, mode: Mode): { + perTxMax: bigint; + dailyMax: bigint; +}; +//# sourceMappingURL=risk.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/risk.d.ts.map b/sdk/dist/engine/risk.d.ts.map new file mode 100644 index 0000000..0941939 --- /dev/null +++ b/sdk/dist/engine/risk.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"risk.d.ts","sourceRoot":"","sources":["../../src/engine/risk.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,IAAI,EAAU,IAAI,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAInE;AAUD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,GAAG,UAAU,CA2CjD;AAED,wBAAgB,YAAY,CAC1B,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,IAAI,GACT;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAQzD;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,IAAI,GACT;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAIxC"} \ No newline at end of file diff --git a/sdk/dist/engine/risk.js b/sdk/dist/engine/risk.js new file mode 100644 index 0000000..425d0a6 --- /dev/null +++ b/sdk/dist/engine/risk.js @@ -0,0 +1,75 @@ +import { BPS, Mode, Reason, Tier, Trust } from '../types.js'; +export function exposureBps(amount, balance) { + if (amount === 0n) + return 0; + if (balance === 0n || amount >= balance) + return Number(BPS); + return Number((amount * BPS) / balance); +} +function bump(t) { + return t === Tier.LOW ? Tier.HIGH : Tier.CRITICAL; +} +function atLeast(t, floor) { + return t >= floor ? t : floor; +} +export function classify(i) { + let tier = Tier.LOW; + let reasons = 0; + if (i.amount > i.highMax) { + tier = Tier.CRITICAL; + reasons |= Reason.AMOUNT_CRITICAL; + } + else if (i.amount > i.lowMax) { + tier = Tier.HIGH; + reasons |= Reason.AMOUNT_HIGH; + } + const exposure = exposureBps(i.amount, i.assetBalance); + if (i.criticalExposureBps !== 0 && exposure >= i.criticalExposureBps) { + tier = Tier.CRITICAL; + reasons |= Reason.EXPOSURE_CRITICAL; + } + else if (i.highExposureBps !== 0 && exposure >= i.highExposureBps) { + tier = atLeast(tier, Tier.HIGH); + reasons |= Reason.EXPOSURE_HIGH; + } + if (i.trust === Trust.RESTRICTED) { + tier = Tier.CRITICAL; + reasons |= Reason.RECIPIENT_RESTRICTED; + } + else if (i.trust === Trust.UNKNOWN) { + tier = bump(tier); + reasons |= Reason.RECIPIENT_UNKNOWN | Reason.RECIPIENT_PROBATION; + } + else if (i.trust === Trust.NEW && i.inProbation) { + tier = bump(tier); + reasons |= Reason.RECIPIENT_PROBATION; + } + if (i.dailyMax !== 0n && (i.daySpent + i.amount) * 2n > i.dailyMax) { + tier = atLeast(tier, Tier.HIGH); + reasons |= Reason.VELOCITY_PRESSURE; + } + if (i.mode === Mode.ELEVATED) { + tier = bump(tier); + reasons |= Reason.MODE_ELEVATED; + } + return { tier, reasons, exposureBps: exposure }; +} +export function requirements(p, tier) { + if (tier === Tier.LOW) + return { approvals: p.approvalsLow, guardians: 0, delay: 0 }; + if (tier === Tier.HIGH) + return { approvals: p.approvalsHigh, guardians: 0, delay: p.delayHigh }; + return { + approvals: p.approvalsCritical, + guardians: p.guardianRequiredCritical ? p.guardianThreshold : 0, + delay: p.delayCritical, + }; +} +/** Elevated halves the caps, floored at one unit. No cap stays no cap. */ +export function effectiveCaps(perTxMax, dailyMax, mode) { + if (mode !== Mode.ELEVATED) + return { perTxMax, dailyMax }; + const half = (x) => (x === 0n ? 0n : x / 2n === 0n ? 1n : x / 2n); + return { perTxMax: half(perTxMax), dailyMax: half(dailyMax) }; +} +//# sourceMappingURL=risk.js.map \ No newline at end of file diff --git a/sdk/dist/engine/risk.js.map b/sdk/dist/engine/risk.js.map new file mode 100644 index 0000000..cb3286f --- /dev/null +++ b/sdk/dist/engine/risk.js.map @@ -0,0 +1 @@ +{"version":3,"file":"risk.js","sourceRoot":"","sources":["../../src/engine/risk.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/engine/simulator.d.ts b/sdk/dist/engine/simulator.d.ts new file mode 100644 index 0000000..765dce9 --- /dev/null +++ b/sdk/dist/engine/simulator.d.ts @@ -0,0 +1,25 @@ +import { type AssetLimits, type Policy } from '../types.js'; +/** + * Runs a policy against the attacks that actually happen, before the policy is live. Every verdict + * is the deterministic risk engine plus the vault's own limit checks — nothing here is heuristic, + * and nothing here is a score. + */ +export type Verdict = 'blocked' | 'delayed' | 'escalated' | 'allowed' | 'impossible'; +export type ScenarioResult = { + id: string; + title: string; + narrative: string; + verdict: Verdict; + detail: string[]; +}; +export type SimContext = { + policy: Policy; + limits: AssetLimits; + balance: bigint; + decimals: number; + symbol: string; + approverCount: number; + guardianCount: number; +}; +export declare function runScenarios(ctx: SimContext): ScenarioResult[]; +//# sourceMappingURL=simulator.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/simulator.d.ts.map b/sdk/dist/engine/simulator.d.ts.map new file mode 100644 index 0000000..77077ae --- /dev/null +++ b/sdk/dist/engine/simulator.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"simulator.d.ts","sourceRoot":"","sources":["../../src/engine/simulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAI5F;;;;GAIG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AAErF,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AA2GF,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,cAAc,EAAE,CAmI9D"} \ No newline at end of file diff --git a/sdk/dist/engine/simulator.js b/sdk/dist/engine/simulator.js new file mode 100644 index 0000000..161e2f2 --- /dev/null +++ b/sdk/dist/engine/simulator.js @@ -0,0 +1,210 @@ +import { Mode, TIER_LABELS, Tier, Trust } from '../types.js'; +import { classify, effectiveCaps, requirements } from './risk.js'; +import { fmtDuration } from './format.js'; +function fmt(v, ctx) { + const s = Number(v) / 10 ** ctx.decimals; + return `${s.toLocaleString('en-US', { maximumFractionDigits: 2 })} ${ctx.symbol}`; +} +function single(ctx, amount, trust, inProbation, mode, compromised) { + const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, mode); + const detail = []; + if (mode === Mode.LOCKDOWN) + return { verdict: 'blocked', detail: ['The vault is in Lockdown: nothing outgoing executes.'] }; + if (trust === Trust.BLOCKED) + return { verdict: 'blocked', detail: ['The recipient is blocked.'] }; + if (caps.perTxMax !== 0n && amount > caps.perTxMax) + return { + verdict: 'blocked', + detail: [ + `The per-transaction cap is ${fmt(caps.perTxMax, ctx)}, so the proposal is refused when it is opened.`, + ], + }; + const r = classify({ + amount, + assetBalance: ctx.balance, + lowMax: ctx.limits.lowMax, + highMax: ctx.limits.highMax, + dailyMax: caps.dailyMax, + daySpent: 0n, + trust, + inProbation, + mode, + highExposureBps: ctx.policy.highExposureBps, + criticalExposureBps: ctx.policy.criticalExposureBps, + }); + if (ctx.policy.hardBlockExposureBps !== 0 && r.exposureBps >= ctx.policy.hardBlockExposureBps) + return { + verdict: 'blocked', + detail: [ + `Exposure of ${(r.exposureBps / 100).toFixed(1)}% is at or above the hard block of ${ctx.policy.hardBlockExposureBps / 100}%, which no amount of approval can clear.`, + ], + }; + if (caps.dailyMax !== 0n && amount > caps.dailyMax) + return { + verdict: 'blocked', + detail: [`The daily cap is ${fmt(caps.dailyMax, ctx)}, so this cannot be opened today.`], + }; + const envelope = ctx.policy.envelopeBps === 0 ? 0n : (ctx.balance * BigInt(ctx.policy.envelopeBps)) / 10000n; + if (envelope !== 0n && amount > envelope) + return { + verdict: 'blocked', + detail: [ + `The loss envelope is ${fmt(envelope, ctx)} per ${fmtDuration(ctx.policy.envelopeWindow)}. The breaker trips and the vault enters Lockdown instead of paying.`, + ], + }; + const req = requirements(ctx.policy, r.tier); + detail.push(`Risk tier: ${TIER_LABELS[r.tier]}, at ${(r.exposureBps / 100).toFixed(2)}% of holdings.`); + detail.push(`Needs ${req.approvals} approval${req.approvals === 1 ? '' : 's'}${req.guardians + ? ` and ${req.guardians} guardian confirmation${req.guardians === 1 ? '' : 's'}` + : ''}${req.delay ? `, then waits ${fmtDuration(req.delay)}` : ', with no delay'}.`); + let delay = req.delay; + if (inProbation) { + delay = Math.max(delay, ctx.policy.recipientActivationDelay); + detail.push(`The recipient's activation delay forces a wait of at least ${fmtDuration(ctx.policy.recipientActivationDelay)}.`); + } + if (r.tier === Tier.CRITICAL || inProbation || mode !== Mode.NORMAL) + detail.push('Any guardian can veto it before it executes.'); + if (req.guardians > ctx.guardianCount) + return { + verdict: 'impossible', + detail: [...detail, 'More guardian confirmations are required than there are guardians.'], + }; + if (compromised < req.approvals) { + detail.push(`The attacker holds ${compromised} approver key${compromised === 1 ? '' : 's'}, fewer than required.`); + return { verdict: 'blocked', detail }; + } + if (req.guardians > 0) { + detail.push('Guardian confirmation is an independent control the attacker does not hold.'); + return { verdict: 'blocked', detail }; + } + if (delay > 0) + return { verdict: 'delayed', detail }; + if (r.tier > Tier.LOW) + return { verdict: 'escalated', detail }; + return { verdict: 'allowed', detail }; +} +export function runScenarios(ctx) { + const out = []; + const pct = (bps) => (ctx.balance * BigInt(bps)) / 10000n; + const unit = 10n ** BigInt(ctx.decimals); + { + const amount = 100000n * unit; + const r = single(ctx, amount, Trust.UNKNOWN, true, Mode.NORMAL, 1); + out.push({ + id: 'single-signer-new-address', + title: 'One finance signer compromised', + narrative: `An attacker with a single approver key opens ${fmt(amount, ctx)} to an address the vault has never paid.`, + ...r, + }); + } + { + const amount = pct(4_000); + const r = single(ctx, amount, Trust.VERIFIED, false, Mode.NORMAL, 3); + out.push({ + id: 'three-signers-40pct', + title: 'Three signers compromised, 40% of the treasury', + narrative: `An attacker with three approver keys opens ${fmt(amount, ctx)} — 40% of holdings — to a recipient the vault has already verified.`, + ...r, + }); + } + { + const each = 9900n * unit; + const total = each * 20n; + const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, Mode.NORMAL); + const envelope = ctx.policy.envelopeBps === 0 ? 0n : pct(ctx.policy.envelopeBps); + const detail = []; + let verdict = 'allowed'; + const tierEach = classify({ + amount: each, + assetBalance: ctx.balance, + lowMax: ctx.limits.lowMax, + highMax: ctx.limits.highMax, + dailyMax: caps.dailyMax, + daySpent: 0n, + trust: Trust.VERIFIED, + inProbation: false, + mode: Mode.NORMAL, + highExposureBps: ctx.policy.highExposureBps, + criticalExposureBps: ctx.policy.criticalExposureBps, + }); + detail.push(`On its own each payment is ${TIER_LABELS[tierEach.tier]} tier.`); + if (caps.dailyMax !== 0n && total > caps.dailyMax) { + const n = Number(caps.dailyMax / each); + detail.push(`The daily cap of ${fmt(caps.dailyMax, ctx)} stops execution after ${n} payment${n === 1 ? '' : 's'}, at ${fmt(each * BigInt(n), ctx)}.`); + verdict = 'blocked'; + } + if (envelope !== 0n && total > envelope) { + const n = Number(envelope / each); + detail.push(`The loss envelope of ${fmt(envelope, ctx)} trips the breaker after ${n} payment${n === 1 ? '' : 's'}, and the vault latches into Lockdown.`); + verdict = 'blocked'; + } + if (caps.dailyMax !== 0n && each * 2n > caps.dailyMax / 2n) { + detail.push("Once half the day's allowance is gone, every further payment is scored high risk."); + if (verdict === 'allowed') + verdict = 'escalated'; + } + if (verdict === 'allowed') + detail.push('No cumulative control is configured, so the split drain would succeed. Set a daily cap or a loss envelope.'); + out.push({ + id: 'split-drain', + title: 'A drain split into twenty payments', + narrative: `Twenty payments of ${fmt(each, ctx)}, ${fmt(total, ctx)} in total, inside one day.`, + verdict, + detail, + }); + } + { + const detail = [ + `Lowering any threshold, delay or cap is a security-reducing change: it waits ${fmtDuration(ctx.policy.policyChangeDelay)} and any guardian can veto it.`, + `It needs ${ctx.policy.governanceThreshold} owner approval${ctx.policy.governanceThreshold === 1 ? '' : 's'}, and cannot be opened at all while the vault is in Lockdown.`, + 'Until it takes effect, payments already in flight keep the requirements pinned when they were opened.', + ]; + const verdict = ctx.policy.policyChangeDelay > 0 ? 'delayed' : 'allowed'; + if (verdict === 'allowed') + detail.push('The policy-change delay is zero, so a compromised owner quorum could weaken the vault at once. Set a delay.'); + out.push({ + id: 'policy-weaken', + title: 'An attacker weakens the policy first', + narrative: 'A compromised owner quorum lowers approvals and caps before trying to drain the vault.', + verdict, + detail, + }); + } + { + out.push({ + id: 'guardian-compromised', + title: 'A guardian key is compromised', + narrative: 'An attacker holding a guardian key tries to take funds.', + verdict: 'impossible', + detail: [ + 'A guardian holds no treasury role: it cannot open, approve or execute a payment, and the contract refuses to give a guardian any treasury role.', + `The worst it can do is freeze the vault, or open a recovery that waits ${fmtDuration(ctx.policy.recoveryDelay)} and that any owner can cancel.`, + ], + }); + } + { + const r = single(ctx, ctx.limits.lowMax, Trust.VERIFIED, false, Mode.ELEVATED, 2); + out.push({ + id: 'elevated-routine', + title: 'A routine payment during an incident', + narrative: `The vault is in Elevated mode and a ${fmt(ctx.limits.lowMax, ctx)} routine payment is opened.`, + ...r, + }); + } + { + const detail = [ + 'An agent holds the proposer role only. It can open a payment and nothing else.', + `Whatever it opens still needs ${ctx.policy.approvalsLow} approval${ctx.policy.approvalsLow === 1 ? '' : 's'} from a human approver for a routine amount, and more above it.`, + 'A compromised agent is a queue full of proposals nobody approves, not a withdrawal.', + ]; + out.push({ + id: 'agent-compromised', + title: 'An automated agent is compromised', + narrative: 'An attacker takes over the key an automation uses to request payments.', + verdict: 'blocked', + detail, + }); + } + return out; +} +//# sourceMappingURL=simulator.js.map \ No newline at end of file diff --git a/sdk/dist/engine/simulator.js.map b/sdk/dist/engine/simulator.js.map new file mode 100644 index 0000000..cbda17a --- /dev/null +++ b/sdk/dist/engine/simulator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"simulator.js","sourceRoot":"","sources":["../../src/engine/simulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAiC,MAAM,aAAa,CAAC;AAC5F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA2B1C,SAAS,GAAG,CAAC,CAAS,EAAE,GAAe;IACrC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC;IACzC,OAAO,GAAG,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,qBAAqB,EAAE,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;AACpF,CAAC;AAED,SAAS,MAAM,CACb,GAAe,EACf,MAAc,EACd,KAAY,EACZ,WAAoB,EACpB,IAAU,EACV,WAAmB;IAEnB,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,IAAI,KAAK,IAAI,CAAC,QAAQ;QACxB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,sDAAsD,CAAC,EAAE,CAAC;IAClG,IAAI,KAAK,KAAK,KAAK,CAAC,OAAO;QAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,2BAA2B,CAAC,EAAE,CAAC;IAClG,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ;QAChD,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE;gBACN,8BAA8B,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,iDAAiD;aACvG;SACF,CAAC;IAEJ,MAAM,CAAC,GAAG,QAAQ,CAAC;QACjB,MAAM;QACN,YAAY,EAAE,GAAG,CAAC,OAAO;QACzB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM;QACzB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO;QAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,EAAE;QACZ,KAAK;QACL,WAAW;QACX,IAAI;QACJ,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,eAAe;QAC3C,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,mBAAmB;KACpD,CAAC,CAAC;IAEH,IAAI,GAAG,CAAC,MAAM,CAAC,oBAAoB,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,CAAC,oBAAoB;QAC3F,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE;gBACN,eAAe,CAAC,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sCAAsC,GAAG,CAAC,MAAM,CAAC,oBAAoB,GAAG,GAAG,2CAA2C;aACtK;SACF,CAAC;IACJ,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,IAAI,MAAM,GAAG,IAAI,CAAC,QAAQ;QAChD,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,CAAC,oBAAoB,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,mCAAmC,CAAC;SACzF,CAAC;IAEJ,MAAM,QAAQ,GACZ,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,GAAG,MAAO,CAAC;IAC/F,IAAI,QAAQ,KAAK,EAAE,IAAI,MAAM,GAAG,QAAQ;QACtC,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE;gBACN,wBAAwB,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,sEAAsE;aAC/J;SACF,CAAC;IAEJ,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CACT,cAAc,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAC1F,CAAC;IACF,MAAM,CAAC,IAAI,CACT,SAAS,GAAG,CAAC,SAAS,YAAY,GAAG,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAC9D,GAAG,CAAC,SAAS;QACX,CAAC,CAAC,QAAQ,GAAG,CAAC,SAAS,yBAAyB,GAAG,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE;QAChF,CAAC,CAAC,EACN,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,GAAG,CAC/E,CAAC;IAEF,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IACtB,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,wBAAwB,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CACT,8DAA8D,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,wBAAwB,CAAC,GAAG,CAClH,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,QAAQ,IAAI,WAAW,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM;QACjE,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAE9D,IAAI,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,aAAa;QACnC,OAAO;YACL,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,oEAAoE,CAAC;SAC1F,CAAC;IACJ,IAAI,WAAW,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CACT,sBAAsB,WAAW,gBAAgB,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,wBAAwB,CACtG,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACxC,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;QAC3F,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACxC,CAAC;IACD,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IACrD,IAAI,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAC/D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAe;IAC1C,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAO,CAAC;IACnE,MAAM,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEzC,CAAC;QACC,MAAM,MAAM,GAAG,OAAQ,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACnE,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,2BAA2B;YAC/B,KAAK,EAAE,gCAAgC;YACvC,SAAS,EAAE,gDAAgD,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,0CAA0C;YACrH,GAAG,CAAC;SACL,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACrE,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,qBAAqB;YACzB,KAAK,EAAE,gDAAgD;YACvD,SAAS,EAAE,8CAA8C,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,qEAAqE;YAC9I,GAAG,CAAC;SACL,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,MAAM,IAAI,GAAG,KAAM,GAAG,IAAI,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,GAAG,GAAG,CAAC;QACzB,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClF,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACjF,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,OAAO,GAAY,SAAS,CAAC;QACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC;YACxB,MAAM,EAAE,IAAI;YACZ,YAAY,EAAE,GAAG,CAAC,OAAO;YACzB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM;YACzB,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO;YAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,KAAK,CAAC,QAAQ;YACrB,WAAW,EAAE,KAAK;YAClB,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,eAAe;YAC3C,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,mBAAmB;SACpD,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,8BAA8B,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9E,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,IAAI,KAAK,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,IAAI,CACT,oBAAoB,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,0BAA0B,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CACzI,CAAC;YACF,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC;QACD,IAAI,QAAQ,KAAK,EAAE,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;YACxC,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CACT,wBAAwB,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,4BAA4B,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,wCAAwC,CAC7I,CAAC;YACF,OAAO,GAAG,SAAS,CAAC;QACtB,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,IAAI,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,GAAG,EAAE,EAAE,CAAC;YAC3D,MAAM,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;YACjG,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO,GAAG,WAAW,CAAC;QACnD,CAAC;QACD,IAAI,OAAO,KAAK,SAAS;YACvB,MAAM,CAAC,IAAI,CACT,4GAA4G,CAC7G,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,aAAa;YACjB,KAAK,EAAE,oCAAoC;YAC3C,SAAS,EAAE,sBAAsB,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,4BAA4B;YAC/F,OAAO;YACP,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,MAAM,MAAM,GAAG;YACb,gFAAgF,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,gCAAgC;YACzJ,YAAY,GAAG,CAAC,MAAM,CAAC,mBAAmB,kBAAkB,GAAG,CAAC,MAAM,CAAC,mBAAmB,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,+DAA+D;YAC1K,uGAAuG;SACxG,CAAC;QACF,MAAM,OAAO,GAAY,GAAG,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;QAClF,IAAI,OAAO,KAAK,SAAS;YACvB,MAAM,CAAC,IAAI,CACT,6GAA6G,CAC9G,CAAC;QACJ,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,sCAAsC;YAC7C,SAAS,EAAE,wFAAwF;YACnG,OAAO;YACP,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,sBAAsB;YAC1B,KAAK,EAAE,+BAA+B;YACtC,SAAS,EAAE,yDAAyD;YACpE,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE;gBACN,iJAAiJ;gBACjJ,0EAA0E,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,iCAAiC;aACjJ;SACF,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAClF,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,kBAAkB;YACtB,KAAK,EAAE,sCAAsC;YAC7C,SAAS,EAAE,uCAAuC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,6BAA6B;YAC1G,GAAG,CAAC;SACL,CAAC,CAAC;IACL,CAAC;IACD,CAAC;QACC,MAAM,MAAM,GAAG;YACb,gFAAgF;YAChF,iCAAiC,GAAG,CAAC,MAAM,CAAC,YAAY,YAAY,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,iEAAiE;YAC7K,qFAAqF;SACtF,CAAC;QACF,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,mBAAmB;YACvB,KAAK,EAAE,mCAAmC;YAC1C,SAAS,EAAE,wEAAwE;YACnF,OAAO,EAAE,SAAS;YAClB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"} \ No newline at end of file diff --git a/sdk/dist/engine/templates.d.ts b/sdk/dist/engine/templates.d.ts new file mode 100644 index 0000000..0ac3c62 --- /dev/null +++ b/sdk/dist/engine/templates.d.ts @@ -0,0 +1,26 @@ +import { type AssetLimits, type Policy } from '../types.js'; +/** + * Starting policies, one per kind of organization. Nobody designs seventeen fields from first + * principles; they pick the closest fit and tighten from there, which is why every template is a + * complete and valid policy rather than a partial preset. + * + * Amounts assume a 6-decimal stablecoin (USDC on Sui) and 9-decimal SUI. + */ +export declare const USDC = 1000000n; +export declare const SUI = 1000000000n; +export type TemplateId = 'startup' | 'team' | 'protocol' | 'fund' | 'payments' | 'nonprofit' | 'familyOffice'; +export type Template = { + id: TemplateId; + name: string; + tagline: string; + /** Who this is for, in the words that organization would use. */ + audience: string; + minSigners: number; + minGuardians: number; + policy: Policy; + stable: AssetLimits; + native: AssetLimits; +}; +export declare const TEMPLATES: Template[]; +export declare function templateById(id: TemplateId): Template; +//# sourceMappingURL=templates.d.ts.map \ No newline at end of file diff --git a/sdk/dist/engine/templates.d.ts.map b/sdk/dist/engine/templates.d.ts.map new file mode 100644 index 0000000..ee7d5c0 --- /dev/null +++ b/sdk/dist/engine/templates.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/engine/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEvE;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,WAAa,CAAC;AAC/B,eAAO,MAAM,GAAG,cAAiB,CAAC;AAElC,MAAM,MAAM,UAAU,GAClB,SAAS,GACT,MAAM,GACN,UAAU,GACV,MAAM,GACN,UAAU,GACV,WAAW,GACX,cAAc,CAAC;AAEnB,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,UAAU,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAsCF,eAAO,MAAM,SAAS,EAAE,QAAQ,EAkL/B,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,GAAG,QAAQ,CAIrD"} \ No newline at end of file diff --git a/sdk/dist/engine/templates.js b/sdk/dist/engine/templates.js new file mode 100644 index 0000000..2b9f75e --- /dev/null +++ b/sdk/dist/engine/templates.js @@ -0,0 +1,228 @@ +import { DAY, HOUR } from '../types.js'; +/** + * Starting policies, one per kind of organization. Nobody designs seventeen fields from first + * principles; they pick the closest fit and tighten from there, which is why every template is a + * complete and valid policy rather than a partial preset. + * + * Amounts assume a 6-decimal stablecoin (USDC on Sui) and 9-decimal SUI. + */ +export const USDC = 1000000n; +export const SUI = 1000000000n; +const startupPolicy = { + approvalsLow: 1, + approvalsHigh: 2, + approvalsCritical: 2, + governanceThreshold: 2, + guardianThreshold: 1, + guardianRequiredCritical: true, + delayHigh: 6 * HOUR, + delayCritical: 24 * HOUR, + recipientActivationDelay: 24 * HOUR, + policyChangeDelay: 24 * HOUR, + recoveryDelay: 48 * HOUR, + proposalTtl: 7 * DAY, + highExposureBps: 500, + criticalExposureBps: 2_000, + hardBlockExposureBps: 5_000, + envelopeBps: 1_000, + envelopeWindow: 24 * HOUR, +}; +const startupStable = { + approved: true, + lowMax: 5000n * USDC, + highMax: 25000n * USDC, + perTxMax: 100000n * USDC, + dailyMax: 100000n * USDC, +}; +const startupNative = { + approved: true, + lowMax: 100n * SUI, + highMax: 1000n * SUI, + perTxMax: 0n, + dailyMax: 5000n * SUI, +}; +export const TEMPLATES = [ + { + id: 'startup', + name: 'Startup', + tagline: 'Simple thresholds, a new-recipient delay, one guardian.', + audience: 'A small team paying contractors and vendors out of a seed round.', + minSigners: 2, + minGuardians: 1, + policy: startupPolicy, + stable: startupStable, + native: startupNative, + }, + { + id: 'team', + name: 'Operating team', + tagline: 'Tiered approvals, velocity limits, supplier trust.', + audience: 'A company with a finance function and recurring suppliers.', + minSigners: 3, + minGuardians: 1, + policy: { ...startupPolicy, approvalsCritical: 3, delayHigh: 4 * HOUR, envelopeBps: 500 }, + stable: { + ...startupStable, + lowMax: 10000n * USDC, + highMax: 50000n * USDC, + perTxMax: 150000n * USDC, + dailyMax: 150000n * USDC, + }, + native: startupNative, + }, + { + id: 'protocol', + name: 'Protocol / DAO', + tagline: 'Higher quorum, long timelocks, two guardians.', + audience: 'A protocol treasury answerable to tokenholders, where every move is public.', + minSigners: 4, + minGuardians: 2, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 3, + approvalsCritical: 4, + governanceThreshold: 3, + guardianThreshold: 2, + delayHigh: 24 * HOUR, + delayCritical: 72 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 7 * DAY, + proposalTtl: 14 * DAY, + highExposureBps: 200, + criticalExposureBps: 1_000, + hardBlockExposureBps: 2_500, + envelopeBps: 500, + }, + stable: { + ...startupStable, + lowMax: 25000n * USDC, + highMax: 100000n * USDC, + perTxMax: 500000n * USDC, + dailyMax: 500000n * USDC, + }, + native: { ...startupNative, lowMax: 1000n * SUI, highMax: 10000n * SUI, dailyMax: 50000n * SUI }, + }, + { + id: 'fund', + name: 'Fund', + tagline: 'Tight exposure limits, strong guardians, long critical delays.', + audience: 'A fund managing outside capital, where a single bad transfer is existential.', + minSigners: 3, + minGuardians: 2, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 3, + approvalsCritical: 3, + guardianThreshold: 2, + delayHigh: 12 * HOUR, + delayCritical: 72 * HOUR, + recipientActivationDelay: 48 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 7 * DAY, + proposalTtl: 14 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 2_000, + envelopeBps: 300, + }, + stable: { + ...startupStable, + lowMax: 50000n * USDC, + highMax: 250000n * USDC, + perTxMax: 1000000n * USDC, + dailyMax: 1000000n * USDC, + }, + native: { ...startupNative, lowMax: 1000n * SUI, highMax: 10000n * SUI, dailyMax: 50000n * SUI }, + }, + { + id: 'payments', + name: 'Payments company', + tagline: 'High routine throughput, a tight envelope, an agent proposer.', + audience: 'A business paying many small amounts automatically, where volume is normal and a spike is not.', + minSigners: 3, + minGuardians: 1, + policy: { + ...startupPolicy, + approvalsLow: 1, + approvalsHigh: 2, + approvalsCritical: 3, + delayHigh: 1 * HOUR, + delayCritical: 12 * HOUR, + recipientActivationDelay: 6 * HOUR, + policyChangeDelay: 48 * HOUR, + proposalTtl: 3 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 1_500, + // The envelope, not the per-payment caps, is what defends a high-volume treasury. + envelopeBps: 200, + envelopeWindow: 6 * HOUR, + }, + stable: { + ...startupStable, + lowMax: 2500n * USDC, + highMax: 25000n * USDC, + perTxMax: 25000n * USDC, + dailyMax: 500000n * USDC, + }, + native: startupNative, + }, + { + id: 'nonprofit', + name: 'Nonprofit', + tagline: 'Restricted recipients, separation of duties, a full audit trail.', + audience: 'An organization spending donated money that has to account for all of it.', + minSigners: 3, + minGuardians: 1, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 2, + approvalsCritical: 3, + recipientActivationDelay: 72 * HOUR, + delayHigh: 12 * HOUR, + delayCritical: 48 * HOUR, + envelopeBps: 500, + }, + stable: startupStable, + native: startupNative, + }, + { + id: 'familyOffice', + name: 'Family office', + tagline: 'Conservative limits, a cold guardian, a long recovery path.', + audience: 'Long-term holdings that move rarely, where availability matters less than safety.', + minSigners: 2, + minGuardians: 1, + policy: { + ...startupPolicy, + delayHigh: 24 * HOUR, + delayCritical: 72 * HOUR, + recipientActivationDelay: 72 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 14 * DAY, + proposalTtl: 21 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 1_500, + envelopeBps: 200, + }, + stable: { + ...startupStable, + lowMax: 10000n * USDC, + highMax: 50000n * USDC, + perTxMax: 250000n * USDC, + dailyMax: 250000n * USDC, + }, + native: startupNative, + }, +]; +export function templateById(id) { + const t = TEMPLATES.find((x) => x.id === id); + if (!t) + throw new Error(`unknown template ${id}`); + return t; +} +//# sourceMappingURL=templates.js.map \ No newline at end of file diff --git a/sdk/dist/engine/templates.js.map b/sdk/dist/engine/templates.js.map new file mode 100644 index 0000000..ab5a3f7 --- /dev/null +++ b/sdk/dist/engine/templates.js.map @@ -0,0 +1 @@ +{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/engine/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAiC,MAAM,aAAa,CAAC;AAEvE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,QAAU,CAAC;AAC/B,MAAM,CAAC,MAAM,GAAG,GAAG,WAAc,CAAC;AAwBlC,MAAM,aAAa,GAAW;IAC5B,YAAY,EAAE,CAAC;IACf,aAAa,EAAE,CAAC;IAChB,iBAAiB,EAAE,CAAC;IACpB,mBAAmB,EAAE,CAAC;IACtB,iBAAiB,EAAE,CAAC;IACpB,wBAAwB,EAAE,IAAI;IAC9B,SAAS,EAAE,CAAC,GAAG,IAAI;IACnB,aAAa,EAAE,EAAE,GAAG,IAAI;IACxB,wBAAwB,EAAE,EAAE,GAAG,IAAI;IACnC,iBAAiB,EAAE,EAAE,GAAG,IAAI;IAC5B,aAAa,EAAE,EAAE,GAAG,IAAI;IACxB,WAAW,EAAE,CAAC,GAAG,GAAG;IACpB,eAAe,EAAE,GAAG;IACpB,mBAAmB,EAAE,KAAK;IAC1B,oBAAoB,EAAE,KAAK;IAC3B,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,EAAE,GAAG,IAAI;CAC1B,CAAC;AAEF,MAAM,aAAa,GAAgB;IACjC,QAAQ,EAAE,IAAI;IACd,MAAM,EAAE,KAAM,GAAG,IAAI;IACrB,OAAO,EAAE,MAAO,GAAG,IAAI;IACvB,QAAQ,EAAE,OAAQ,GAAG,IAAI;IACzB,QAAQ,EAAE,OAAQ,GAAG,IAAI;CAC1B,CAAC;AAEF,MAAM,aAAa,GAAgB;IACjC,QAAQ,EAAE,IAAI;IACd,MAAM,EAAE,IAAI,GAAG,GAAG;IAClB,OAAO,EAAE,KAAM,GAAG,GAAG;IACrB,QAAQ,EAAE,EAAE;IACZ,QAAQ,EAAE,KAAM,GAAG,GAAG;CACvB,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAe;IACnC;QACE,EAAE,EAAE,SAAS;QACb,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,yDAAyD;QAClE,QAAQ,EAAE,kEAAkE;QAC5E,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,aAAa;KACtB;IACD;QACE,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,oDAAoD;QAC7D,QAAQ,EAAE,4DAA4D;QACtE,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,iBAAiB,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE;QACzF,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,MAAM,EAAE,MAAO,GAAG,IAAI;YACtB,OAAO,EAAE,MAAO,GAAG,IAAI;YACvB,QAAQ,EAAE,OAAQ,GAAG,IAAI;YACzB,QAAQ,EAAE,OAAQ,GAAG,IAAI;SAC1B;QACD,MAAM,EAAE,aAAa;KACtB;IACD;QACE,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,+CAA+C;QACxD,QAAQ,EAAE,6EAA6E;QACvF,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,mBAAmB,EAAE,CAAC;YACtB,iBAAiB,EAAE,CAAC;YACpB,SAAS,EAAE,EAAE,GAAG,IAAI;YACpB,aAAa,EAAE,EAAE,GAAG,IAAI;YACxB,iBAAiB,EAAE,EAAE,GAAG,IAAI;YAC5B,aAAa,EAAE,CAAC,GAAG,GAAG;YACtB,WAAW,EAAE,EAAE,GAAG,GAAG;YACrB,eAAe,EAAE,GAAG;YACpB,mBAAmB,EAAE,KAAK;YAC1B,oBAAoB,EAAE,KAAK;YAC3B,WAAW,EAAE,GAAG;SACjB;QACD,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,MAAM,EAAE,MAAO,GAAG,IAAI;YACtB,OAAO,EAAE,OAAQ,GAAG,IAAI;YACxB,QAAQ,EAAE,OAAQ,GAAG,IAAI;YACzB,QAAQ,EAAE,OAAQ,GAAG,IAAI;SAC1B;QACD,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,KAAM,GAAG,GAAG,EAAE,OAAO,EAAE,MAAO,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAO,GAAG,GAAG,EAAE;KACpG;IACD;QACE,EAAE,EAAE,MAAM;QACV,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,gEAAgE;QACzE,QAAQ,EAAE,8EAA8E;QACxF,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,CAAC;YACpB,SAAS,EAAE,EAAE,GAAG,IAAI;YACpB,aAAa,EAAE,EAAE,GAAG,IAAI;YACxB,wBAAwB,EAAE,EAAE,GAAG,IAAI;YACnC,iBAAiB,EAAE,EAAE,GAAG,IAAI;YAC5B,aAAa,EAAE,CAAC,GAAG,GAAG;YACtB,WAAW,EAAE,EAAE,GAAG,GAAG;YACrB,eAAe,EAAE,GAAG;YACpB,mBAAmB,EAAE,GAAG;YACxB,oBAAoB,EAAE,KAAK;YAC3B,WAAW,EAAE,GAAG;SACjB;QACD,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,MAAM,EAAE,MAAO,GAAG,IAAI;YACtB,OAAO,EAAE,OAAQ,GAAG,IAAI;YACxB,QAAQ,EAAE,QAAU,GAAG,IAAI;YAC3B,QAAQ,EAAE,QAAU,GAAG,IAAI;SAC5B;QACD,MAAM,EAAE,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,KAAM,GAAG,GAAG,EAAE,OAAO,EAAE,MAAO,GAAG,GAAG,EAAE,QAAQ,EAAE,MAAO,GAAG,GAAG,EAAE;KACpG;IACD;QACE,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,kBAAkB;QACxB,OAAO,EAAE,+DAA+D;QACxE,QAAQ,EACN,gGAAgG;QAClG,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,SAAS,EAAE,CAAC,GAAG,IAAI;YACnB,aAAa,EAAE,EAAE,GAAG,IAAI;YACxB,wBAAwB,EAAE,CAAC,GAAG,IAAI;YAClC,iBAAiB,EAAE,EAAE,GAAG,IAAI;YAC5B,WAAW,EAAE,CAAC,GAAG,GAAG;YACpB,eAAe,EAAE,GAAG;YACpB,mBAAmB,EAAE,GAAG;YACxB,oBAAoB,EAAE,KAAK;YAC3B,kFAAkF;YAClF,WAAW,EAAE,GAAG;YAChB,cAAc,EAAE,CAAC,GAAG,IAAI;SACzB;QACD,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,MAAM,EAAE,KAAM,GAAG,IAAI;YACrB,OAAO,EAAE,MAAO,GAAG,IAAI;YACvB,QAAQ,EAAE,MAAO,GAAG,IAAI;YACxB,QAAQ,EAAE,OAAQ,GAAG,IAAI;SAC1B;QACD,MAAM,EAAE,aAAa;KACtB;IACD;QACE,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,kEAAkE;QAC3E,QAAQ,EAAE,2EAA2E;QACrF,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,wBAAwB,EAAE,EAAE,GAAG,IAAI;YACnC,SAAS,EAAE,EAAE,GAAG,IAAI;YACpB,aAAa,EAAE,EAAE,GAAG,IAAI;YACxB,WAAW,EAAE,GAAG;SACjB;QACD,MAAM,EAAE,aAAa;QACrB,MAAM,EAAE,aAAa;KACtB;IACD;QACE,EAAE,EAAE,cAAc;QAClB,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,6DAA6D;QACtE,QAAQ,EAAE,mFAAmF;QAC7F,UAAU,EAAE,CAAC;QACb,YAAY,EAAE,CAAC;QACf,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,SAAS,EAAE,EAAE,GAAG,IAAI;YACpB,aAAa,EAAE,EAAE,GAAG,IAAI;YACxB,wBAAwB,EAAE,EAAE,GAAG,IAAI;YACnC,iBAAiB,EAAE,EAAE,GAAG,IAAI;YAC5B,aAAa,EAAE,EAAE,GAAG,GAAG;YACvB,WAAW,EAAE,EAAE,GAAG,GAAG;YACrB,eAAe,EAAE,GAAG;YACpB,mBAAmB,EAAE,GAAG;YACxB,oBAAoB,EAAE,KAAK;YAC3B,WAAW,EAAE,GAAG;SACjB;QACD,MAAM,EAAE;YACN,GAAG,aAAa;YAChB,MAAM,EAAE,MAAO,GAAG,IAAI;YACtB,OAAO,EAAE,MAAO,GAAG,IAAI;YACvB,QAAQ,EAAE,OAAQ,GAAG,IAAI;YACzB,QAAQ,EAAE,OAAQ,GAAG,IAAI;SAC1B;QACD,MAAM,EAAE,aAAa;KACtB;CACF,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,EAAc;IACzC,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7C,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IAClD,OAAO,CAAC,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/sdk/dist/errors.d.ts b/sdk/dist/errors.d.ts new file mode 100644 index 0000000..2e6f25b --- /dev/null +++ b/sdk/dist/errors.d.ts @@ -0,0 +1,13 @@ +/** + * Move abort codes, mapped to the sentence a person should read. The numbers are the constants in + * `sui/sources/policy.move` and `sui/sources/vault.move`; a change there is a change here. + * + * A Sui abort arrives as a `MoveAbort` in the execution status, carrying the module and the code, + * so an interface can be specific about why a transaction was refused rather than saying "failed". + */ +export declare const POLICY_ERRORS: Record; +export declare const VAULT_ERRORS: Record; +export declare function describeAbort(module: string | undefined, code: number | bigint): string; +/** Pull a readable reason out of a failed execution result. */ +export declare function describeFailure(error: unknown): string; +//# sourceMappingURL=errors.d.ts.map \ No newline at end of file diff --git a/sdk/dist/errors.d.ts.map b/sdk/dist/errors.d.ts.map new file mode 100644 index 0000000..42ca0bf --- /dev/null +++ b/sdk/dist/errors.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBhD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyC/C,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAKvF;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAStD"} \ No newline at end of file diff --git a/sdk/dist/errors.js b/sdk/dist/errors.js new file mode 100644 index 0000000..5da640b --- /dev/null +++ b/sdk/dist/errors.js @@ -0,0 +1,95 @@ +/** + * Move abort codes, mapped to the sentence a person should read. The numbers are the constants in + * `sui/sources/policy.move` and `sui/sources/vault.move`; a change there is a change here. + * + * A Sui abort arrives as a `MoveAbort` in the execution status, carrying the module and the code, + * so an interface can be specific about why a transaction was refused rather than saying "failed". + */ +export const POLICY_ERRORS = { + 1: 'Routine transfers must need at least one approval.', + 2: 'High-risk transfers cannot need fewer approvals than routine ones.', + 3: 'Critical transfers cannot need fewer approvals than high-risk ones.', + 4: 'Governance must need at least one owner.', + 5: 'Guardian confirmation is required but no guardian confirmations were set.', + 6: 'The critical delay cannot be shorter than the high-risk delay.', + 7: 'The high exposure threshold cannot exceed the critical one.', + 8: 'Exposure thresholds cannot exceed 100%.', + 9: 'The hard block cannot sit below the critical exposure threshold.', + 10: 'The hard block cannot exceed 100%.', + 11: 'The loss envelope cannot exceed 100%.', + 12: 'The envelope window must be at least one hour.', + 13: 'Proposal lifetime must exceed the longest delay by at least an hour.', + 20: 'The routine maximum cannot exceed the high-tier maximum.', + 21: 'The per-transaction cap cannot exceed the daily cap.', + 30: 'A vault needs at least one owner.', + 31: 'A vault needs at least one executor.', + 32: 'The governance threshold exceeds the number of owners.', + 33: 'Critical approvals exceed the number of approvers.', + 34: 'The guardian threshold exceeds the number of guardians.', +}; +export const VAULT_ERRORS = { + 100: 'That address is not a member of this vault.', + 101: 'Only an owner can do that.', + 102: 'Only an approver can approve a payment.', + 103: 'Only an executor can execute.', + 104: 'Only a guardian can do that.', + 105: 'That role cannot open proposals.', + 106: 'Those roles are not a valid combination.', + 107: 'The vault is in Lockdown.', + 108: 'That asset is not approved for this vault.', + 109: 'No such proposal.', + 110: 'That proposal is no longer pending.', + 111: 'That proposal is of a different kind.', + 112: 'That proposal is for a different asset.', + 113: 'The waiting period has not elapsed yet.', + 114: 'That proposal has expired.', + 115: 'That proposal has not expired yet.', + 116: 'Not enough approvals from current signers.', + 117: 'Not enough guardian confirmations.', + 118: 'The recipient is blocked.', + 119: 'The recipient is still in its activation delay.', + 120: 'Above the per-transaction cap for this asset.', + 121: "Above today's remaining allowance for this asset.", + 122: 'Above the hard block: no amount of approval can clear this.', + 123: 'The vault does not hold enough of that asset.', + 124: 'The amount must be greater than zero.', + 125: 'That proposal is not one a guardian can veto.', + 126: 'That address is already registered.', + 127: 'That recipient is not registered.', + 128: 'That is not a valid trust level.', + 129: 'That is not a valid security mode.', + 130: 'That is not a relaxation of the current mode.', + 131: 'Only the proposer or an owner can cancel.', + 132: 'A vault cannot be left without an owner.', + 133: 'A guardian cannot hold a treasury role.', + 134: 'That asset was already configured.', + 135: 'The member list and the role list are different lengths.', + 136: 'A guardian cannot nominate themselves as a replacement signer.', + 137: 'No such member.', + 138: 'That signer has already voted on this proposal.', + 139: 'Those roles are already set.', +}; +export function describeAbort(module, code) { + const n = Number(code); + if (module === 'policy' && POLICY_ERRORS[n]) + return POLICY_ERRORS[n]; + if (module === 'vault' && VAULT_ERRORS[n]) + return VAULT_ERRORS[n]; + return POLICY_ERRORS[n] ?? VAULT_ERRORS[n] ?? `The vault refused the transaction (code ${n}).`; +} +/** Pull a readable reason out of a failed execution result. */ +export function describeFailure(error) { + const text = error instanceof Error ? error.message : String(error); + const abort = /MoveAbort.*?(\w+)::(\w+).*?(\d+)/.exec(text); + if (abort) + return describeAbort(abort[2], Number(abort[3])); + const bare = /MoveAbort[^0-9]*(\d+)/.exec(text); + if (bare) + return describeAbort(undefined, Number(bare[1])); + if (/InsufficientGas|GasBalanceTooLow/.test(text)) + return 'Not enough SUI to pay for gas.'; + if (/ObjectNotFound/.test(text)) + return 'That object no longer exists on this network.'; + return text; +} +//# sourceMappingURL=errors.js.map \ No newline at end of file diff --git a/sdk/dist/errors.js.map b/sdk/dist/errors.js.map new file mode 100644 index 0000000..5e4bb9e --- /dev/null +++ b/sdk/dist/errors.js.map @@ -0,0 +1 @@ +{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/events.d.ts b/sdk/dist/events.d.ts new file mode 100644 index 0000000..a605fa0 --- /dev/null +++ b/sdk/dist/events.d.ts @@ -0,0 +1,186 @@ +import type { ClientWithCoreApi } from '@mysten/sui/client'; +import { AssetLimitsBcs, PolicyBcs } from './bcs.js'; +import type { Kind, Mode, Status, Tier, Trust } from './types.js'; +export declare const EVENT_NAMES: readonly ["VaultCreated", "Deposited", "ProposalOpened", "Approved", "Confirmed", "Settled", "Executed", "BreakerTripped", "ModeChanged", "PolicyChanged", "LimitsChanged", "MemberChanged", "RecipientRegistered", "RecipientTrustChanged", "Recovered"]; +export type EventName = (typeof EVENT_NAMES)[number]; +export type SkurEvent = { + name: 'VaultCreated'; + vault: string; + vaultName: string; + creator: string; + ownerCount: number; + guardianCount: number; + at: number; +} | { + name: 'Deposited'; + vault: string; + asset: string; + amount: bigint; + balance: bigint; + from: string; + at: number; +} | { + name: 'ProposalOpened'; + vault: string; + proposal: bigint; + kind: Kind; + proposer: string; + asset: string | null; + amount: bigint; + recipient: string; + tier: Tier; + reasons: number; + exposureBps: number; + reqApprovals: number; + reqGuardians: number; + executableAt: number; + expiresAt: number; + reductionMask: number; + memo: string; + at: number; +} | { + name: 'Approved'; + vault: string; + proposal: bigint; + approver: string; + approvals: number; + reqApprovals: number; + at: number; +} | { + name: 'Confirmed'; + vault: string; + proposal: bigint; + guardian: string; + confirmations: number; + reqGuardians: number; + at: number; +} | { + name: 'Settled'; + vault: string; + proposal: bigint; + kind: Kind; + status: Status; + actor: string; + at: number; +} | { + name: 'Executed'; + vault: string; + proposal: bigint; + kind: Kind; + asset: string | null; + amount: bigint; + recipient: string; + executor: string; + tier: Tier; + balanceAfter: bigint; + daySpent: bigint; + at: number; +} | { + name: 'BreakerTripped'; + vault: string; + proposal: bigint; + asset: string; + amount: bigint; + envelopeSpent: bigint; + envelopeLimit: bigint; + envelopeBasis: bigint; + at: number; +} | { + name: 'ModeChanged'; + vault: string; + from: Mode; + to: Mode; + actor: string; + reasons: number; + at: number; +} | { + name: 'PolicyChanged'; + vault: string; + proposal: bigint; + version: bigint; + reductionMask: number; + at: number; +} | { + name: 'LimitsChanged'; + vault: string; + proposal: bigint; + asset: string; + approved: boolean; + lowMax: bigint; + highMax: bigint; + perTxMax: bigint; + dailyMax: bigint; + reductionMask: number; + at: number; +} | { + name: 'MemberChanged'; + vault: string; + proposal: bigint; + member: string; + rolesBefore: number; + rolesAfter: number; + at: number; +} | { + name: 'RecipientRegistered'; + vault: string; + recipient: string; + trust: Trust; + activatesAt: number; + label: string; + actor: string; + at: number; +} | { + name: 'RecipientTrustChanged'; + vault: string; + proposal: bigint; + recipient: string; + from: Trust; + to: Trust; + actor: string; + at: number; +} | { + name: 'Recovered'; + vault: string; + proposal: bigint; + lost: string; + replacement: string; + roles: number; + at: number; +}; +/** Ledger position, so an indexer can resume exactly where it stopped. */ +export type EventPosition = { + transactionDigest: string; + eventIndex: number; + checkpoint?: string; + timestampMs?: number; +}; +export type DecodedEvent = { + event: SkurEvent; + position: EventPosition; +}; +/** Decode one Move event into a tagged union, or null if it is not one of ours. */ +export declare function decodeEvent(eventType: string, bytes: Uint8Array): SkurEvent | null; +/** + * Page through the package's events. The filter is `emitModule`, which is one predicate and so + * works on every transport; events for other vaults are dropped client-side when `vaultId` is + * given, because a module-wide filter is the finest the portable API offers. + */ +export declare function listVaultEvents(client: ClientWithCoreApi, input: { + packageId: string; + vaultId?: string; + limit?: number; + /** Walk forwards from here. Use for indexing and for polling what is new. */ + after?: string | null; + /** Walk backwards from here. Use for an interface showing newest first. */ + before?: string | null; + order?: 'ascending' | 'descending'; +}): Promise<{ + events: DecodedEvent[]; + startCursor: string | null; + endCursor: string | null; + hasNextPage: boolean; +}>; +/** The Move type of one of our events, for a precise `eventType` filter. */ +export declare function eventType(packageId: string, name: EventName): string; +export { PolicyBcs, AssetLimitsBcs }; +//# sourceMappingURL=events.d.ts.map \ No newline at end of file diff --git a/sdk/dist/events.d.ts.map b/sdk/dist/events.d.ts.map new file mode 100644 index 0000000..4a5770e --- /dev/null +++ b/sdk/dist/events.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/events.js b/sdk/dist/events.js new file mode 100644 index 0000000..2f48737 --- /dev/null +++ b/sdk/dist/events.js @@ -0,0 +1,311 @@ +import { bcs } from '@mysten/sui/bcs'; +import { AssetLimitsBcs, PolicyBcs } from './bcs.js'; +import { moveType } from './network.js'; +/** + * The vault's events, which are the whole history. Every state change emits one, so an indexer or + * a notification service never has to diff object versions to know what happened. + * + * Parsed from `event.bcs`, not `event.json`: the SDK documents the JSON shape as varying between + * transports, and an audit trail cannot depend on which endpoint read it. + */ +const UID = bcs.Address; +const OptionTypeName = bcs.option(bcs.struct('TypeName', { name: bcs.string() })); +function typeName(v) { + if (!v) + return null; + return v.name.startsWith('0x') ? v.name : `0x${v.name}`; +} +export const EVENT_NAMES = [ + 'VaultCreated', + 'Deposited', + 'ProposalOpened', + 'Approved', + 'Confirmed', + 'Settled', + 'Executed', + 'BreakerTripped', + 'ModeChanged', + 'PolicyChanged', + 'LimitsChanged', + 'MemberChanged', + 'RecipientRegistered', + 'RecipientTrustChanged', + 'Recovered', +]; +const VaultCreatedBcs = bcs.struct('VaultCreated', { + vault: UID, + name: bcs.string(), + creator: bcs.Address, + owner_count: bcs.u64(), + guardian_count: bcs.u64(), + at: bcs.u64(), +}); +const DepositedBcs = bcs.struct('Deposited', { + vault: UID, + asset: bcs.struct('TypeName', { name: bcs.string() }), + amount: bcs.u64(), + balance: bcs.u64(), + from: bcs.Address, + at: bcs.u64(), +}); +const ProposalOpenedBcs = bcs.struct('ProposalOpened', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + proposer: bcs.Address, + asset: OptionTypeName, + amount: bcs.u64(), + recipient: bcs.Address, + tier: bcs.u8(), + reasons: bcs.u16(), + exposure_bps: bcs.u64(), + req_approvals: bcs.u8(), + req_guardians: bcs.u8(), + executable_at: bcs.u64(), + expires_at: bcs.u64(), + reduction_mask: bcs.u32(), + memo: bcs.string(), + at: bcs.u64(), +}); +const ApprovedBcs = bcs.struct('Approved', { + vault: UID, + proposal: bcs.u64(), + approver: bcs.Address, + approvals: bcs.u64(), + req_approvals: bcs.u8(), + at: bcs.u64(), +}); +const ConfirmedBcs = bcs.struct('Confirmed', { + vault: UID, + proposal: bcs.u64(), + guardian: bcs.Address, + confirmations: bcs.u64(), + req_guardians: bcs.u8(), + at: bcs.u64(), +}); +const SettledBcs = bcs.struct('Settled', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + status: bcs.u8(), + actor: bcs.Address, + at: bcs.u64(), +}); +const ExecutedBcs = bcs.struct('Executed', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + asset: OptionTypeName, + amount: bcs.u64(), + recipient: bcs.Address, + executor: bcs.Address, + tier: bcs.u8(), + balance_after: bcs.u64(), + day_spent: bcs.u64(), + at: bcs.u64(), +}); +const BreakerTrippedBcs = bcs.struct('BreakerTripped', { + vault: UID, + proposal: bcs.u64(), + asset: bcs.struct('TypeName', { name: bcs.string() }), + amount: bcs.u64(), + envelope_spent: bcs.u64(), + envelope_limit: bcs.u64(), + envelope_basis: bcs.u64(), + at: bcs.u64(), +}); +const ModeChangedBcs = bcs.struct('ModeChanged', { + vault: UID, + from: bcs.u8(), + to: bcs.u8(), + actor: bcs.Address, + reasons: bcs.u16(), + at: bcs.u64(), +}); +const PolicyChangedBcs = bcs.struct('PolicyChanged', { + vault: UID, + proposal: bcs.u64(), + version: bcs.u64(), + reduction_mask: bcs.u32(), + at: bcs.u64(), +}); +const LimitsChangedBcs = bcs.struct('LimitsChanged', { + vault: UID, + proposal: bcs.u64(), + asset: bcs.struct('TypeName', { name: bcs.string() }), + approved: bcs.bool(), + low_max: bcs.u64(), + high_max: bcs.u64(), + per_tx_max: bcs.u64(), + daily_max: bcs.u64(), + reduction_mask: bcs.u32(), + at: bcs.u64(), +}); +const MemberChangedBcs = bcs.struct('MemberChanged', { + vault: UID, + proposal: bcs.u64(), + member: bcs.Address, + roles_before: bcs.u8(), + roles_after: bcs.u8(), + at: bcs.u64(), +}); +const RecipientRegisteredBcs = bcs.struct('RecipientRegistered', { + vault: UID, + recipient: bcs.Address, + trust: bcs.u8(), + activates_at: bcs.u64(), + label: bcs.string(), + actor: bcs.Address, + at: bcs.u64(), +}); +const RecipientTrustChangedBcs = bcs.struct('RecipientTrustChanged', { + vault: UID, + proposal: bcs.u64(), + recipient: bcs.Address, + from: bcs.u8(), + to: bcs.u8(), + actor: bcs.Address, + at: bcs.u64(), +}); +const RecoveredBcs = bcs.struct('Recovered', { + vault: UID, + proposal: bcs.u64(), + lost: bcs.Address, + replacement: bcs.Address, + roles: bcs.u8(), + at: bcs.u64(), +}); +const n = (v) => Number(v); +const b = (v) => BigInt(v); +/** Decode one Move event into a tagged union, or null if it is not one of ours. */ +export function decodeEvent(eventType, bytes) { + const name = eventType.split('::').pop(); + switch (name) { + case 'VaultCreated': { + const e = VaultCreatedBcs.parse(bytes); + return { name, vault: e.vault, vaultName: e.name, creator: e.creator, ownerCount: n(e.owner_count), guardianCount: n(e.guardian_count), at: n(e.at) }; + } + case 'Deposited': { + const e = DepositedBcs.parse(bytes); + return { name, vault: e.vault, asset: typeName(e.asset), amount: b(e.amount), balance: b(e.balance), from: e.from, at: n(e.at) }; + } + case 'ProposalOpened': { + const e = ProposalOpenedBcs.parse(bytes); + return { + name, + vault: e.vault, + proposal: b(e.proposal), + kind: n(e.kind), + proposer: e.proposer, + asset: typeName(e.asset), + amount: b(e.amount), + recipient: e.recipient, + tier: n(e.tier), + reasons: n(e.reasons), + exposureBps: n(e.exposure_bps), + reqApprovals: n(e.req_approvals), + reqGuardians: n(e.req_guardians), + executableAt: n(e.executable_at), + expiresAt: n(e.expires_at), + reductionMask: n(e.reduction_mask), + memo: e.memo, + at: n(e.at), + }; + } + case 'Approved': { + const e = ApprovedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), approver: e.approver, approvals: n(e.approvals), reqApprovals: n(e.req_approvals), at: n(e.at) }; + } + case 'Confirmed': { + const e = ConfirmedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), guardian: e.guardian, confirmations: n(e.confirmations), reqGuardians: n(e.req_guardians), at: n(e.at) }; + } + case 'Settled': { + const e = SettledBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), kind: n(e.kind), status: n(e.status), actor: e.actor, at: n(e.at) }; + } + case 'Executed': { + const e = ExecutedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), kind: n(e.kind), asset: typeName(e.asset), amount: b(e.amount), recipient: e.recipient, executor: e.executor, tier: n(e.tier), balanceAfter: b(e.balance_after), daySpent: b(e.day_spent), at: n(e.at) }; + } + case 'BreakerTripped': { + const e = BreakerTrippedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), asset: typeName(e.asset), amount: b(e.amount), envelopeSpent: b(e.envelope_spent), envelopeLimit: b(e.envelope_limit), envelopeBasis: b(e.envelope_basis), at: n(e.at) }; + } + case 'ModeChanged': { + const e = ModeChangedBcs.parse(bytes); + return { name, vault: e.vault, from: n(e.from), to: n(e.to), actor: e.actor, reasons: n(e.reasons), at: n(e.at) }; + } + case 'PolicyChanged': { + const e = PolicyChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), version: b(e.version), reductionMask: n(e.reduction_mask), at: n(e.at) }; + } + case 'LimitsChanged': { + const e = LimitsChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), asset: typeName(e.asset), approved: e.approved, lowMax: b(e.low_max), highMax: b(e.high_max), perTxMax: b(e.per_tx_max), dailyMax: b(e.daily_max), reductionMask: n(e.reduction_mask), at: n(e.at) }; + } + case 'MemberChanged': { + const e = MemberChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), member: e.member, rolesBefore: n(e.roles_before), rolesAfter: n(e.roles_after), at: n(e.at) }; + } + case 'RecipientRegistered': { + const e = RecipientRegisteredBcs.parse(bytes); + return { name, vault: e.vault, recipient: e.recipient, trust: n(e.trust), activatesAt: n(e.activates_at), label: e.label, actor: e.actor, at: n(e.at) }; + } + case 'RecipientTrustChanged': { + const e = RecipientTrustChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), recipient: e.recipient, from: n(e.from), to: n(e.to), actor: e.actor, at: n(e.at) }; + } + case 'Recovered': { + const e = RecoveredBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), lost: e.lost, replacement: e.replacement, roles: n(e.roles), at: n(e.at) }; + } + default: + return null; + } +} +/** + * Page through the package's events. The filter is `emitModule`, which is one predicate and so + * works on every transport; events for other vaults are dropped client-side when `vaultId` is + * given, because a module-wide filter is the finest the portable API offers. + */ +export async function listVaultEvents(client, input) { + const page = await client.core.listEvents({ + filter: { emitModule: `${input.packageId}::vault` }, + limit: input.limit ?? 50, + ...(input.after != null ? { after: input.after } : {}), + ...(input.before != null ? { before: input.before } : {}), + ...(input.after == null && input.before == null + ? { order: input.order ?? 'descending' } + : {}), + }); + const events = []; + for (const e of page.events) { + const decoded = decodeEvent(e.eventType, e.bcs); + if (!decoded) + continue; + if (input.vaultId && decoded.vault !== input.vaultId) + continue; + events.push({ + event: decoded, + position: { + transactionDigest: e.transactionDigest, + eventIndex: e.eventIndex, + checkpoint: e.checkpoint ?? undefined, + timestampMs: decoded.at, + }, + }); + } + return { + events, + startCursor: page.startCursor, + endCursor: page.endCursor, + hasNextPage: page.hasNextPage, + }; +} +/** The Move type of one of our events, for a precise `eventType` filter. */ +export function eventType(packageId, name) { + return moveType(packageId, 'vault', name); +} +export { PolicyBcs, AssetLimitsBcs }; +//# sourceMappingURL=events.js.map \ No newline at end of file diff --git a/sdk/dist/events.js.map b/sdk/dist/events.js.map new file mode 100644 index 0000000..48bab3d --- /dev/null +++ b/sdk/dist/events.js.map @@ -0,0 +1 @@ +{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/index.d.ts b/sdk/dist/index.d.ts new file mode 100644 index 0000000..e4583ae --- /dev/null +++ b/sdk/dist/index.d.ts @@ -0,0 +1,15 @@ +/** + * The Skur SDK: everything an interface, a backend or a script needs to read and drive a vault on + * Sui. + * + * Transport is gRPC or GraphQL. JSON-RPC is not used anywhere, directly or transitively. + */ +export * from './network.js'; +export * from './types.js'; +export * from './errors.js'; +export * from './events.js'; +export * from './vault.js'; +export * as tx from './tx.js'; +export * from './engine/index.js'; +export { bcs } from '@mysten/sui/bcs'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/sdk/dist/index.d.ts.map b/sdk/dist/index.d.ts.map new file mode 100644 index 0000000..d3b1e44 --- /dev/null +++ b/sdk/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC"} \ No newline at end of file diff --git a/sdk/dist/index.js b/sdk/dist/index.js new file mode 100644 index 0000000..ec7a072 --- /dev/null +++ b/sdk/dist/index.js @@ -0,0 +1,15 @@ +/** + * The Skur SDK: everything an interface, a backend or a script needs to read and drive a vault on + * Sui. + * + * Transport is gRPC or GraphQL. JSON-RPC is not used anywhere, directly or transitively. + */ +export * from './network.js'; +export * from './types.js'; +export * from './errors.js'; +export * from './events.js'; +export * from './vault.js'; +export * as tx from './tx.js'; +export * from './engine/index.js'; +export { bcs } from '@mysten/sui/bcs'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/sdk/dist/index.js.map b/sdk/dist/index.js.map new file mode 100644 index 0000000..c1dcaa9 --- /dev/null +++ b/sdk/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC"} \ No newline at end of file diff --git a/sdk/dist/network.d.ts b/sdk/dist/network.d.ts new file mode 100644 index 0000000..4dfc557 --- /dev/null +++ b/sdk/dist/network.d.ts @@ -0,0 +1,43 @@ +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { SuiGraphQLClient } from '@mysten/sui/graphql'; +import type { ClientWithCoreApi } from '@mysten/sui/client'; +/** + * Transport policy for this project: gRPC first, GraphQL where a query needs shapes gRPC's + * unified methods do not carry. + * + * JSON-RPC is deliberately absent. It was switched off on Sui Foundation mainnet full nodes in + * the week of 27 July 2026 and is scheduled for full removal, code included, in mid-October 2026. + * Nothing here may depend on it, including transitively: `@mysten/dapp-kit` 1.x is JSON-RPC only + * and is why the frontend uses `@mysten/dapp-kit-react` 2.x instead. + */ +export type Network = 'mainnet' | 'testnet' | 'devnet' | 'localnet'; +export declare const GRPC_ENDPOINTS: Record; +export declare const GRAPHQL_ENDPOINTS: Record; +/** The shared `Clock` every time-dependent entry function reads. */ +export declare const CLOCK_ID = "0x6"; +export declare function grpcClient(network: Network, baseUrl?: string): SuiGrpcClient; +export declare function graphqlClient(network: Network, url?: string): SuiGraphQLClient<{}>; +/** + * Where the package and its vaults live. One object per environment, written by the deploy + * script, so nothing in the app hardcodes an address. + */ +export type Deployment = { + network: Network; + /** The published `skur` package. */ + packageId: string; + /** Vaults the deploy script created, for demos and for the explorer links in the docs. */ + vaults: { + id: string; + name: string; + }[]; + publishedAtDigest?: string; + publishedAtCheckpoint?: string; +}; +export type SkurConfig = { + deployment: Deployment; + client: ClientWithCoreApi; +}; +/** Fully qualified Move type for a struct in the deployed package. */ +export declare function moveType(packageId: string, module: string, name: string): string; +export declare function moveTarget(packageId: string, module: string, fn: string): `${string}::${string}::${string}`; +//# sourceMappingURL=network.d.ts.map \ No newline at end of file diff --git a/sdk/dist/network.d.ts.map b/sdk/dist/network.d.ts.map new file mode 100644 index 0000000..a971961 --- /dev/null +++ b/sdk/dist/network.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;;;;GAQG;AACH,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpE,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAKlD,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAKrD,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAE9B,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,SAA0B,iBAE7E;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,SAA6B,wBAE/E;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,iBAAiB,CAAC;CAC3B,CAAC;AAEF,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAEvE;AAED,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,GACT,GAAG,MAAM,KAAK,MAAM,KAAK,MAAM,EAAE,CAEnC"} \ No newline at end of file diff --git a/sdk/dist/network.js b/sdk/dist/network.js new file mode 100644 index 0000000..c55a634 --- /dev/null +++ b/sdk/dist/network.js @@ -0,0 +1,30 @@ +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { SuiGraphQLClient } from '@mysten/sui/graphql'; +export const GRPC_ENDPOINTS = { + mainnet: 'https://fullnode.mainnet.sui.io:443', + testnet: 'https://fullnode.testnet.sui.io:443', + devnet: 'https://fullnode.devnet.sui.io:443', + localnet: 'http://127.0.0.1:9000', +}; +export const GRAPHQL_ENDPOINTS = { + mainnet: 'https://sui-mainnet.mystenlabs.com/graphql', + testnet: 'https://sui-testnet.mystenlabs.com/graphql', + devnet: 'https://sui-devnet.mystenlabs.com/graphql', + localnet: 'http://127.0.0.1:9125/graphql', +}; +/** The shared `Clock` every time-dependent entry function reads. */ +export const CLOCK_ID = '0x6'; +export function grpcClient(network, baseUrl = GRPC_ENDPOINTS[network]) { + return new SuiGrpcClient({ network, baseUrl }); +} +export function graphqlClient(network, url = GRAPHQL_ENDPOINTS[network]) { + return new SuiGraphQLClient({ network, url }); +} +/** Fully qualified Move type for a struct in the deployed package. */ +export function moveType(packageId, module, name) { + return `${packageId}::${module}::${name}`; +} +export function moveTarget(packageId, module, fn) { + return `${packageId}::${module}::${fn}`; +} +//# sourceMappingURL=network.js.map \ No newline at end of file diff --git a/sdk/dist/network.js.map b/sdk/dist/network.js.map new file mode 100644 index 0000000..18546ad --- /dev/null +++ b/sdk/dist/network.js.map @@ -0,0 +1 @@ +{"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAcvD,MAAM,CAAC,MAAM,cAAc,GAA4B;IACrD,OAAO,EAAE,qCAAqC;IAC9C,OAAO,EAAE,qCAAqC;IAC9C,MAAM,EAAE,oCAAoC;IAC5C,QAAQ,EAAE,uBAAuB;CAClC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAA4B;IACxD,OAAO,EAAE,4CAA4C;IACrD,OAAO,EAAE,4CAA4C;IACrD,MAAM,EAAE,2CAA2C;IACnD,QAAQ,EAAE,+BAA+B;CAC1C,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC;AAE9B,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;IAC5E,OAAO,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAgB,EAAE,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAC;IAC9E,OAAO,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;AAChD,CAAC;AAqBD,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,MAAc,EAAE,IAAY;IACtE,OAAO,GAAG,SAAS,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,MAAc,EACd,EAAU;IAEV,OAAO,GAAG,SAAS,KAAK,MAAM,KAAK,EAAE,EAAE,CAAC;AAC1C,CAAC"} \ No newline at end of file diff --git a/sdk/dist/tx.d.ts b/sdk/dist/tx.d.ts new file mode 100644 index 0000000..bb8b75e --- /dev/null +++ b/sdk/dist/tx.d.ts @@ -0,0 +1,128 @@ +import { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions'; +import type { AssetLimits, Mode, Policy, Trust } from './types.js'; +/** + * Programmable transaction blocks for every vault action. + * + * Two things here are worth knowing. First, a policy is built on chain by calling + * `policy::new(...)` inside the same block, so the seventeen fields are validated by the module + * that owns them rather than packed into bytes by this file. Second, creating a vault is one + * block: `begin` hands back a value with no abilities, so the same transaction has to configure + * the assets and call `finish`, and there is no moment when a half-configured vault exists. + */ +export type Builder = { + tx: Transaction; + packageId: string; +}; +/** Build the `Policy` struct inside the block. */ +export declare function policyArg(b: Builder, p: Policy): TransactionObjectArgument; +export type MemberSeed = { + address: string; + roles: number; +}; +export type AssetSeed = { + coinType: string; + limits: AssetLimits; +}; +export type RecipientSeed = { + address: string; + label: string; +}; +/** `begin` → `setup_asset`* → `setup_recipient`* → `finish`, in one block. */ +export declare function createVault(packageId: string, input: { + name: string; + policy: Policy; + members: MemberSeed[]; + assets: AssetSeed[]; + recipients?: RecipientSeed[]; +}): Transaction; +/** + * Fund a vault. SUI comes out of the gas coin, which is the only coin a PTB always has; any other + * asset is merged from the coin objects the caller holds and then split to the exact amount, so a + * deposit never has to match a coin's balance. + */ +export declare function deposit(packageId: string, input: { + vaultId: string; + coinType: string; + amount: bigint; + coinObjectIds?: string[]; +}): Transaction; +export declare function proposeTransfer(packageId: string, input: { + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; + memo?: string; +}): Transaction; +export declare const approve: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const confirm: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const veto: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const cancel: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const expire: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const executePolicy: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const executeMember: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const executeRecipientTrust: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const executeModeRelax: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare const executeRecovery: (pkg: string, vaultId: string, id: bigint) => Transaction; +export declare function executeTransfer(packageId: string, input: { + vaultId: string; + coinType: string; + proposalId: bigint; +}): Transaction; +export declare function registerRecipient(packageId: string, input: { + vaultId: string; + recipient: string; + label: string; +}): Transaction; +/** A guardian restricting or blocking a destination, immediately and alone. */ +export declare function guardianRestrict(packageId: string, input: { + vaultId: string; + recipient: string; + trust: Trust; +}): Transaction; +export declare function raiseMode(packageId: string, input: { + vaultId: string; + mode: Mode; + reasons?: number; +}): Transaction; +export declare function proposePolicy(packageId: string, input: { + vaultId: string; + policy: Policy; +}): Transaction; +export declare function proposeAssetLimits(packageId: string, input: { + vaultId: string; + coinType: string; + limits: AssetLimits; +}): Transaction; +export declare function executeAssetLimits(packageId: string, input: { + vaultId: string; + coinType: string; + proposalId: bigint; +}): Transaction; +/** `roles` of 0 removes the member. */ +export declare function proposeMember(packageId: string, input: { + vaultId: string; + member: string; + roles: number; +}): Transaction; +export declare function proposeRecipientTrust(packageId: string, input: { + vaultId: string; + recipient: string; + trust: Trust; +}): Transaction; +export declare function proposeModeRelax(packageId: string, input: { + vaultId: string; + mode: Mode; +}): Transaction; +export declare function proposeRecovery(packageId: string, input: { + vaultId: string; + lost: string; + replacement: string; +}): Transaction; +/** The block used to read `preview_transfer` back through a simulation. */ +export declare function previewTransferTx(packageId: string, input: { + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; +}): Transaction; +//# sourceMappingURL=tx.d.ts.map \ No newline at end of file diff --git a/sdk/dist/tx.d.ts.map b/sdk/dist/tx.d.ts.map new file mode 100644 index 0000000..6d3df06 --- /dev/null +++ b/sdk/dist/tx.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"tx.d.ts","sourceRoot":"","sources":["../src/tx.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/tx.js b/sdk/dist/tx.js new file mode 100644 index 0000000..cd5810a --- /dev/null +++ b/sdk/dist/tx.js @@ -0,0 +1,282 @@ +import { Transaction } from '@mysten/sui/transactions'; +import { SUI_TYPE_ARG } from '@mysten/sui/utils'; +import { CLOCK_ID, moveTarget } from './network.js'; +function target(pkg, module, fn) { + return moveTarget(pkg, module, fn); +} +/** Build the `Policy` struct inside the block. */ +export function policyArg(b, p) { + const { tx, packageId } = b; + return tx.moveCall({ + target: target(packageId, 'policy', 'new'), + arguments: [ + tx.pure.u8(p.approvalsLow), + tx.pure.u8(p.approvalsHigh), + tx.pure.u8(p.approvalsCritical), + tx.pure.u8(p.governanceThreshold), + tx.pure.u8(p.guardianThreshold), + tx.pure.bool(p.guardianRequiredCritical), + tx.pure.u64(p.delayHigh), + tx.pure.u64(p.delayCritical), + tx.pure.u64(p.recipientActivationDelay), + tx.pure.u64(p.policyChangeDelay), + tx.pure.u64(p.recoveryDelay), + tx.pure.u64(p.proposalTtl), + tx.pure.u64(p.highExposureBps), + tx.pure.u64(p.criticalExposureBps), + tx.pure.u64(p.hardBlockExposureBps), + tx.pure.u64(p.envelopeBps), + tx.pure.u64(p.envelopeWindow), + ], + }); +} +/** `begin` → `setup_asset`* → `setup_recipient`* → `finish`, in one block. */ +export function createVault(packageId, input) { + const tx = new Transaction(); + const b = { tx, packageId }; + const setup = tx.moveCall({ + target: target(packageId, 'vault', 'begin'), + arguments: [ + tx.pure.string(input.name), + policyArg(b, input.policy), + tx.pure.vector('address', input.members.map((m) => m.address)), + tx.pure.vector('u8', input.members.map((m) => m.roles)), + tx.object(CLOCK_ID), + ], + }); + for (const a of input.assets) { + tx.moveCall({ + target: target(packageId, 'vault', 'setup_asset'), + typeArguments: [a.coinType], + arguments: [ + setup, + tx.pure.bool(a.limits.approved), + tx.pure.u64(a.limits.lowMax), + tx.pure.u64(a.limits.highMax), + tx.pure.u64(a.limits.perTxMax), + tx.pure.u64(a.limits.dailyMax), + ], + }); + } + for (const r of input.recipients ?? []) { + tx.moveCall({ + target: target(packageId, 'vault', 'setup_recipient'), + arguments: [setup, tx.pure.address(r.address), tx.pure.string(r.label)], + }); + } + tx.moveCall({ target: target(packageId, 'vault', 'finish'), arguments: [setup] }); + return tx; +} +/** + * Fund a vault. SUI comes out of the gas coin, which is the only coin a PTB always has; any other + * asset is merged from the coin objects the caller holds and then split to the exact amount, so a + * deposit never has to match a coin's balance. + */ +export function deposit(packageId, input) { + const tx = new Transaction(); + let coin; + if (input.coinType === SUI_TYPE_ARG || input.coinType === '0x2::sui::SUI') { + [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(input.amount)]); + } + else { + const ids = input.coinObjectIds ?? []; + if (ids.length === 0) + throw new Error('coinObjectIds is required for a non-SUI deposit'); + const primary = tx.object(ids[0]); + if (ids.length > 1) + tx.mergeCoins(primary, ids.slice(1).map((id) => tx.object(id))); + [coin] = tx.splitCoins(primary, [tx.pure.u64(input.amount)]); + } + tx.moveCall({ + target: target(packageId, 'vault', 'deposit'), + typeArguments: [input.coinType], + arguments: [tx.object(input.vaultId), coin, tx.object(CLOCK_ID)], + }); + return tx; +} +export function proposeTransfer(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.amount), + tx.pure.address(input.recipient), + tx.pure.string(input.memo ?? ''), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +/** `approve`, `confirm`, `veto`, `cancel` and `expire` all take the same arguments. */ +function proposalAction(packageId, fn, vaultId, proposalId) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', fn), + arguments: [tx.object(vaultId), tx.pure.u64(proposalId), tx.object(CLOCK_ID)], + }); + return tx; +} +export const approve = (pkg, vaultId, id) => proposalAction(pkg, 'approve', vaultId, id); +export const confirm = (pkg, vaultId, id) => proposalAction(pkg, 'confirm', vaultId, id); +export const veto = (pkg, vaultId, id) => proposalAction(pkg, 'veto', vaultId, id); +export const cancel = (pkg, vaultId, id) => proposalAction(pkg, 'cancel', vaultId, id); +export const expire = (pkg, vaultId, id) => proposalAction(pkg, 'expire', vaultId, id); +export const executePolicy = (pkg, vaultId, id) => proposalAction(pkg, 'execute_policy', vaultId, id); +export const executeMember = (pkg, vaultId, id) => proposalAction(pkg, 'execute_member', vaultId, id); +export const executeRecipientTrust = (pkg, vaultId, id) => proposalAction(pkg, 'execute_recipient_trust', vaultId, id); +export const executeModeRelax = (pkg, vaultId, id) => proposalAction(pkg, 'execute_mode_relax', vaultId, id); +export const executeRecovery = (pkg, vaultId, id) => proposalAction(pkg, 'execute_recovery', vaultId, id); +export function executeTransfer(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'execute_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.proposalId), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function registerRecipient(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'register_recipient'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.string(input.label), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +/** A guardian restricting or blocking a destination, immediately and alone. */ +export function guardianRestrict(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'guardian_restrict'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.u8(input.trust), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function raiseMode(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'raise_mode'), + arguments: [ + tx.object(input.vaultId), + tx.pure.u8(input.mode), + tx.pure.u16(input.reasons ?? 0), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function proposePolicy(packageId, input) { + const tx = new Transaction(); + const b = { tx, packageId }; + tx.moveCall({ + target: target(packageId, 'vault', 'propose_policy'), + arguments: [tx.object(input.vaultId), policyArg(b, input.policy), tx.object(CLOCK_ID)], + }); + return tx; +} +export function proposeAssetLimits(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_asset_limits'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.bool(input.limits.approved), + tx.pure.u64(input.limits.lowMax), + tx.pure.u64(input.limits.highMax), + tx.pure.u64(input.limits.perTxMax), + tx.pure.u64(input.limits.dailyMax), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function executeAssetLimits(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'execute_asset_limits'), + typeArguments: [input.coinType], + arguments: [tx.object(input.vaultId), tx.pure.u64(input.proposalId), tx.object(CLOCK_ID)], + }); + return tx; +} +/** `roles` of 0 removes the member. */ +export function proposeMember(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_member'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.member), + tx.pure.u8(input.roles), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function proposeRecipientTrust(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_recipient_trust'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.u8(input.trust), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +export function proposeModeRelax(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_mode_relax'), + arguments: [tx.object(input.vaultId), tx.pure.u8(input.mode), tx.object(CLOCK_ID)], + }); + return tx; +} +export function proposeRecovery(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_recovery'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.lost), + tx.pure.address(input.replacement), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +/** The block used to read `preview_transfer` back through a simulation. */ +export function previewTransferTx(packageId, input) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'preview_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.amount), + tx.pure.address(input.recipient), + tx.object(CLOCK_ID), + ], + }); + return tx; +} +//# sourceMappingURL=tx.js.map \ No newline at end of file diff --git a/sdk/dist/tx.js.map b/sdk/dist/tx.js.map new file mode 100644 index 0000000..526dfe1 --- /dev/null +++ b/sdk/dist/tx.js.map @@ -0,0 +1 @@ +{"version":3,"file":"tx.js","sourceRoot":"","sources":["../src/tx.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/types.d.ts b/sdk/dist/types.d.ts new file mode 100644 index 0000000..0d0db60 --- /dev/null +++ b/sdk/dist/types.d.ts @@ -0,0 +1,209 @@ +/** + * The vocabulary, kept identical to `sui/sources/types.move`. Anything that disagrees with the + * chain is a bug in this file, not in the contract. + * + * Durations are milliseconds everywhere, because that is what `sui::clock` reports. Amounts are + * `bigint` in the smallest unit of their coin type. + */ +export declare const Role: { + readonly OWNER: 1; + readonly APPROVER: 2; + readonly EXECUTOR: 4; + readonly GUARDIAN: 8; + /** An automated agent: may open proposals and nothing else. */ + readonly PROPOSER: 16; +}; +export type Role = (typeof Role)[keyof typeof Role]; +export declare const ROLE_TREASURY_MASK: number; +export declare const ROLE_ALL = 31; +export declare const ROLE_LABELS: Record; +export declare function hasRole(bits: number, role: Role | number): boolean; +export declare function hasAnyRole(bits: number, mask: number): boolean; +export declare function canPropose(bits: number): boolean; +/** A guardian is the second control plane and may hold no treasury role. */ +export declare function rolesValid(bits: number): boolean; +export declare function describeRoles(bits: number): string[]; +export declare const Tier: { + readonly LOW: 0; + readonly HIGH: 1; + readonly CRITICAL: 2; +}; +export type Tier = (typeof Tier)[keyof typeof Tier]; +export declare const TIER_LABELS: Record; +export declare const Trust: { + readonly UNKNOWN: 0; + readonly NEW: 1; + readonly VERIFIED: 2; + readonly TRUSTED: 3; + readonly RESTRICTED: 4; + readonly BLOCKED: 5; +}; +export type Trust = (typeof Trust)[keyof typeof Trust]; +export declare const TRUST_LABELS: Record; +export declare const Mode: { + readonly NORMAL: 0; + readonly ELEVATED: 1; + readonly LOCKDOWN: 2; +}; +export type Mode = (typeof Mode)[keyof typeof Mode]; +export declare const MODE_LABELS: Record; +export declare const Kind: { + readonly TRANSFER: 0; + readonly POLICY_UPDATE: 1; + readonly ASSET_LIMITS: 2; + readonly MEMBER_SET: 3; + readonly RECIPIENT_TRUST: 4; + readonly MODE_RELAX: 5; + readonly RECOVERY: 6; +}; +export type Kind = (typeof Kind)[keyof typeof Kind]; +export declare const KIND_LABELS: Record; +export declare const Status: { + readonly NONE: 0; + readonly PENDING: 1; + readonly EXECUTED: 2; + readonly CANCELLED: 3; + readonly VETOED: 4; + readonly EXPIRED: 5; + /** Refused by the circuit breaker. The vault latched into Lockdown instead of paying. */ + readonly BLOCKED: 6; +}; +export type Status = (typeof Status)[keyof typeof Status]; +export declare const STATUS_LABELS: Record; +export declare const Reason: { + readonly AMOUNT_HIGH: 1; + readonly AMOUNT_CRITICAL: 2; + readonly EXPOSURE_HIGH: 4; + readonly EXPOSURE_CRITICAL: 8; + readonly RECIPIENT_PROBATION: 16; + readonly RECIPIENT_RESTRICTED: 32; + readonly MODE_ELEVATED: 64; + readonly VELOCITY_PRESSURE: 128; + readonly RECIPIENT_UNKNOWN: 256; + readonly ENVELOPE_PRESSURE: 512; +}; +export type Reason = (typeof Reason)[keyof typeof Reason]; +/** Plain-language explanations, in the order a reviewer should read them. */ +export declare const REASON_TEXT: [Reason, string][]; +export declare function describeReasons(mask: number): string[]; +export declare const BPS = 10000n; +export declare const SECOND = 1000; +export declare const MINUTE: number; +export declare const HOUR: number; +export declare const DAY: number; +/** The seventeen fields. Durations in milliseconds, exposures in basis points. */ +export type Policy = { + approvalsLow: number; + approvalsHigh: number; + approvalsCritical: number; + governanceThreshold: number; + guardianThreshold: number; + guardianRequiredCritical: boolean; + delayHigh: number; + delayCritical: number; + recipientActivationDelay: number; + policyChangeDelay: number; + recoveryDelay: number; + proposalTtl: number; + highExposureBps: number; + criticalExposureBps: number; + hardBlockExposureBps: number; + envelopeBps: number; + envelopeWindow: number; +}; +export type AssetLimits = { + approved: boolean; + lowMax: bigint; + highMax: bigint; + perTxMax: bigint; + dailyMax: bigint; +}; +export type Velocity = { + dayAnchor: number; + daySpent: bigint; + envelopeAnchor: number; + envelopeSpent: bigint; + /** The balance when the window opened; the envelope is measured against this, not the live + * balance, so a drain cannot shrink its own denominator. */ + envelopeBasis: bigint; +}; +export type RecipientRecord = { + address: string; + trust: Trust; + registeredAt: number; + activatesAt: number; + paidCount: number; + lastPaid: number; + label: string; +}; +export type Proposal = { + id: bigint; + kind: Kind; + status: Status; + proposer: string; + createdAt: number; + executableAt: number; + expiresAt: number; + reqApprovals: number; + reqGuardians: number; + tier: Tier; + reasons: number; + exposureBps: number; + policyVersion: bigint; + reductionMask: number; + approvals: string[]; + confirmations: string[]; + asset: string | null; + amount: bigint; + recipient: string; + memo: string; + newPolicy: Policy | null; + newLimits: AssetLimits | null; + member: string; + memberPrev: string; + memberRoles: number; + trustLevel: Trust; + targetMode: Mode; +}; +export type VaultSummary = { + id: string; + name: string; + policy: Policy; + policyVersion: bigint; + mode: Mode; + postureReasons: number; + ownerCount: number; + approverCount: number; + executorCount: number; + guardianCount: number; + nextProposal: bigint; + pendingCount: number; + createdAt: number; + /** Table and Bag object ids, needed to read the collections by dynamic field. */ + tables: { + members: string; + limits: string; + funds: string; + velocity: string; + recipients: string; + proposals: string; + }; + sizes: { + members: number; + limits: number; + funds: number; + velocity: number; + recipients: number; + proposals: number; + }; +}; +/** What `preview_transfer` returns, in order. */ +export type TransferPreview = { + tier: Tier; + reasons: number; + exposureBps: number; + reqApprovals: number; + reqGuardians: number; + delay: number; +}; +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/sdk/dist/types.d.ts.map b/sdk/dist/types.d.ts.map new file mode 100644 index 0000000..931c98a --- /dev/null +++ b/sdk/dist/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/types.js b/sdk/dist/types.js new file mode 100644 index 0000000..904f512 --- /dev/null +++ b/sdk/dist/types.js @@ -0,0 +1,145 @@ +/** + * The vocabulary, kept identical to `sui/sources/types.move`. Anything that disagrees with the + * chain is a bug in this file, not in the contract. + * + * Durations are milliseconds everywhere, because that is what `sui::clock` reports. Amounts are + * `bigint` in the smallest unit of their coin type. + */ +export const Role = { + OWNER: 1, + APPROVER: 2, + EXECUTOR: 4, + GUARDIAN: 8, + /** An automated agent: may open proposals and nothing else. */ + PROPOSER: 16, +}; +export const ROLE_TREASURY_MASK = Role.OWNER | Role.APPROVER | Role.EXECUTOR | Role.PROPOSER; +export const ROLE_ALL = 31; +export const ROLE_LABELS = { + [Role.OWNER]: 'Owner', + [Role.APPROVER]: 'Approver', + [Role.EXECUTOR]: 'Executor', + [Role.GUARDIAN]: 'Guardian', + [Role.PROPOSER]: 'Proposer', +}; +export function hasRole(bits, role) { + return (bits & role) === role; +} +export function hasAnyRole(bits, mask) { + return (bits & mask) !== 0; +} +export function canPropose(bits) { + return hasAnyRole(bits, ROLE_TREASURY_MASK); +} +/** A guardian is the second control plane and may hold no treasury role. */ +export function rolesValid(bits) { + if (bits === 0 || bits > ROLE_ALL) + return false; + if (hasRole(bits, Role.GUARDIAN) && (bits & ROLE_TREASURY_MASK) !== 0) + return false; + return true; +} +export function describeRoles(bits) { + return Object.values(Role) + .filter((r) => hasRole(bits, r)) + .map((r) => ROLE_LABELS[r]); +} +export const Tier = { LOW: 0, HIGH: 1, CRITICAL: 2 }; +export const TIER_LABELS = { + [Tier.LOW]: 'Routine', + [Tier.HIGH]: 'High risk', + [Tier.CRITICAL]: 'Critical', +}; +export const Trust = { + UNKNOWN: 0, + NEW: 1, + VERIFIED: 2, + TRUSTED: 3, + RESTRICTED: 4, + BLOCKED: 5, +}; +export const TRUST_LABELS = { + [Trust.UNKNOWN]: 'Never paid', + [Trust.NEW]: 'New', + [Trust.VERIFIED]: 'Verified', + [Trust.TRUSTED]: 'Trusted', + [Trust.RESTRICTED]: 'Restricted', + [Trust.BLOCKED]: 'Blocked', +}; +export const Mode = { NORMAL: 0, ELEVATED: 1, LOCKDOWN: 2 }; +export const MODE_LABELS = { + [Mode.NORMAL]: 'Normal', + [Mode.ELEVATED]: 'Elevated', + [Mode.LOCKDOWN]: 'Lockdown', +}; +export const Kind = { + TRANSFER: 0, + POLICY_UPDATE: 1, + ASSET_LIMITS: 2, + MEMBER_SET: 3, + RECIPIENT_TRUST: 4, + MODE_RELAX: 5, + RECOVERY: 6, +}; +export const KIND_LABELS = { + [Kind.TRANSFER]: 'Payment', + [Kind.POLICY_UPDATE]: 'Policy change', + [Kind.ASSET_LIMITS]: 'Asset limits', + [Kind.MEMBER_SET]: 'Signer change', + [Kind.RECIPIENT_TRUST]: 'Recipient trust', + [Kind.MODE_RELAX]: 'Lower security mode', + [Kind.RECOVERY]: 'Signer recovery', +}; +export const Status = { + NONE: 0, + PENDING: 1, + EXECUTED: 2, + CANCELLED: 3, + VETOED: 4, + EXPIRED: 5, + /** Refused by the circuit breaker. The vault latched into Lockdown instead of paying. */ + BLOCKED: 6, +}; +export const STATUS_LABELS = { + [Status.NONE]: 'Unknown', + [Status.PENDING]: 'Awaiting approval', + [Status.EXECUTED]: 'Executed', + [Status.CANCELLED]: 'Cancelled', + [Status.VETOED]: 'Vetoed', + [Status.EXPIRED]: 'Expired', + [Status.BLOCKED]: 'Refused by the circuit breaker', +}; +export const Reason = { + AMOUNT_HIGH: 1, + AMOUNT_CRITICAL: 2, + EXPOSURE_HIGH: 4, + EXPOSURE_CRITICAL: 8, + RECIPIENT_PROBATION: 16, + RECIPIENT_RESTRICTED: 32, + MODE_ELEVATED: 64, + VELOCITY_PRESSURE: 128, + RECIPIENT_UNKNOWN: 256, + ENVELOPE_PRESSURE: 512, +}; +/** Plain-language explanations, in the order a reviewer should read them. */ +export const REASON_TEXT = [ + [Reason.AMOUNT_CRITICAL, 'Above the high-tier maximum for this asset'], + [Reason.AMOUNT_HIGH, 'Above the routine maximum for this asset'], + [Reason.EXPOSURE_CRITICAL, 'A critical share of what the vault holds'], + [Reason.EXPOSURE_HIGH, 'A large share of what the vault holds'], + [Reason.RECIPIENT_RESTRICTED, 'The recipient is restricted'], + [Reason.RECIPIENT_UNKNOWN, 'The vault has never paid this address'], + [Reason.RECIPIENT_PROBATION, 'The recipient is still in its activation delay'], + [Reason.VELOCITY_PRESSURE, "Past half of today's allowance for this asset"], + [Reason.ENVELOPE_PRESSURE, 'Against the loss envelope for the window'], + [Reason.MODE_ELEVATED, 'The vault is in Elevated mode'], +]; +export function describeReasons(mask) { + return REASON_TEXT.filter(([bit]) => (mask & bit) !== 0).map(([, text]) => text); +} +export const BPS = 10000n; +export const SECOND = 1_000; +export const MINUTE = 60 * SECOND; +export const HOUR = 60 * MINUTE; +export const DAY = 24 * HOUR; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/sdk/dist/types.js.map b/sdk/dist/types.js.map new file mode 100644 index 0000000..f815f5f --- /dev/null +++ b/sdk/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/vault.d.ts b/sdk/dist/vault.d.ts new file mode 100644 index 0000000..aa2e58e --- /dev/null +++ b/sdk/dist/vault.d.ts @@ -0,0 +1,59 @@ +import type { ClientWithCoreApi } from '@mysten/sui/client'; +import { type AssetLimits, type Proposal, type RecipientRecord, type TransferPreview, type VaultSummary, type Velocity } from './types.js'; +export declare function fetchVault(client: ClientWithCoreApi, vaultId: string): Promise; +export declare function fetchMembers(client: ClientWithCoreApi, vault: VaultSummary): Promise<{ + address: string; + roles: number; +}[]>; +export declare function fetchLimits(client: ClientWithCoreApi, vault: VaultSummary): Promise<{ + coinType: string; + limits: AssetLimits; +}[]>; +export declare function fetchBalances(client: ClientWithCoreApi, vault: VaultSummary): Promise<{ + coinType: string; + balance: bigint; +}[]>; +export declare function fetchVelocity(client: ClientWithCoreApi, vault: VaultSummary): Promise<{ + coinType: string; + velocity: Velocity; +}[]>; +export declare function fetchRecipients(client: ClientWithCoreApi, vault: VaultSummary): Promise; +/** One proposal by its number. */ +export declare function fetchProposal(client: ClientWithCoreApi, vault: VaultSummary, id: bigint): Promise; +/** + * The most recent proposals, newest first. Proposal numbers are sequential from 1, so this walks + * backwards from the counter instead of listing the whole table — a vault with ten thousand + * settled payments should not have to read all of them to show the queue. + */ +export declare function fetchRecentProposals(client: ClientWithCoreApi, vault: VaultSummary, count?: number): Promise; +/** + * What the vault itself says a transfer would need, read by simulating its own + * `preview_transfer`. The interface never computes this for a live vault: if the preview and the + * execution could disagree, the preview is worthless. + */ +export declare function previewTransfer(client: ClientWithCoreApi, input: { + packageId: string; + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; + sender: string; +}): Promise; +/** Everything an interface needs for one screen, in as few round trips as the transport allows. */ +export type VaultView = { + vault: VaultSummary; + members: { + address: string; + roles: number; + }[]; + assets: { + coinType: string; + limits: AssetLimits; + balance: bigint; + velocity: Velocity | null; + }[]; + recipients: RecipientRecord[]; + proposals: Proposal[]; +}; +export declare function fetchVaultView(client: ClientWithCoreApi, vaultId: string, proposalCount?: number): Promise; +//# sourceMappingURL=vault.d.ts.map \ No newline at end of file diff --git a/sdk/dist/vault.d.ts.map b/sdk/dist/vault.d.ts.map new file mode 100644 index 0000000..0cc8622 --- /dev/null +++ b/sdk/dist/vault.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAW5D,OAAO,EAML,KAAK,WAAW,EAEhB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAkEpB,wBAAsB,UAAU,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAkCvB;AA0BD,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAM/C;AAUD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,EAAE,CAAC,CAKtD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAGlD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,EAAE,CAAC,CAYrD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CAW5B;AAkCD,kCAAkC;AAClC,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAU1B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,KAAK,SAAK,GACT,OAAO,CAAC,QAAQ,EAAE,CAAC,CAMrB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,eAAe,CAAC,CAoB1B;AAED,mGAAmG;AACnG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAChG,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,CAAC;AAEF,wBAAsB,cAAc,CAClC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,EACf,aAAa,SAAK,GACjB,OAAO,CAAC,SAAS,CAAC,CAwBpB"} \ No newline at end of file diff --git a/sdk/dist/vault.js b/sdk/dist/vault.js new file mode 100644 index 0000000..0121293 --- /dev/null +++ b/sdk/dist/vault.js @@ -0,0 +1,273 @@ +import { bcs } from '@mysten/sui/bcs'; +import { AssetLimitsBcs, PolicyBcs, ProposalBcs, RecipientBcs, VaultBcs, VelocityBcs, } from './bcs.js'; +import { previewTransferTx } from './tx.js'; +import { Kind, Mode, Status, Tier, Trust, } from './types.js'; +/** + * Reading a vault. + * + * Written against `ClientWithCoreApi` rather than a concrete client, so the same code works over + * gRPC and GraphQL. The vault's collections are Move `Table`s and a `Bag`, which are dynamic + * fields on their own handles: list the names, then fetch the values. + */ +const CONCURRENCY = 16; +async function mapLimited(items, fn, limit = CONCURRENCY) { + const out = new Array(items.length); + let next = 0; + const workers = Array.from({ length: Math.min(limit, items.length) }, async () => { + while (true) { + const i = next++; + if (i >= items.length) + return; + out[i] = await fn(items[i]); + } + }); + await Promise.all(workers); + return out; +} +function num(v) { + return Number(v); +} +function big(v) { + return BigInt(v); +} +function toPolicy(raw) { + return { + approvalsLow: raw.approvals_low, + approvalsHigh: raw.approvals_high, + approvalsCritical: raw.approvals_critical, + governanceThreshold: raw.governance_threshold, + guardianThreshold: raw.guardian_threshold, + guardianRequiredCritical: raw.guardian_required_critical, + delayHigh: num(raw.delay_high), + delayCritical: num(raw.delay_critical), + recipientActivationDelay: num(raw.recipient_activation_delay), + policyChangeDelay: num(raw.policy_change_delay), + recoveryDelay: num(raw.recovery_delay), + proposalTtl: num(raw.proposal_ttl), + highExposureBps: num(raw.high_exposure_bps), + criticalExposureBps: num(raw.critical_exposure_bps), + hardBlockExposureBps: num(raw.hard_block_exposure_bps), + envelopeBps: num(raw.envelope_bps), + envelopeWindow: num(raw.envelope_window), + }; +} +function toLimits(raw) { + return { + approved: raw.approved, + lowMax: big(raw.low_max), + highMax: big(raw.high_max), + perTxMax: big(raw.per_tx_max), + dailyMax: big(raw.daily_max), + }; +} +export async function fetchVault(client, vaultId) { + const { object } = await client.core.getObject({ objectId: vaultId, include: { content: true } }); + const v = VaultBcs.parse(object.content); + return { + id: vaultId, + name: v.name, + policy: toPolicy(v.policy), + policyVersion: big(v.policy_version), + mode: num(v.mode), + postureReasons: num(v.posture_reasons), + ownerCount: num(v.owner_count), + approverCount: num(v.approver_count), + executorCount: num(v.executor_count), + guardianCount: num(v.guardian_count), + nextProposal: big(v.next_proposal), + pendingCount: num(v.pending_count), + createdAt: num(v.created_at), + tables: { + members: v.members.id, + limits: v.limits.id, + funds: v.funds.id, + velocity: v.velocity.id, + recipients: v.recipients.id, + proposals: v.proposals.id, + }, + sizes: { + members: num(v.members.size), + limits: num(v.limits.size), + funds: num(v.funds.size), + velocity: num(v.velocity.size), + recipients: num(v.recipients.size), + proposals: num(v.proposals.size), + }, + }; +} +/** Every dynamic field name under a handle, paged to the end. */ +async function listNames(client, parentId) { + const names = []; + let page = await client.core.listDynamicFields({ parentId, limit: 50 }); + for (;;) { + for (const f of page.dynamicFields) + names.push(f.name); + if (!page.hasNextPage) + break; + page = await client.core.listDynamicFields({ parentId, cursor: page.cursor, limit: 50 }); + } + return names; +} +async function readEntries(client, parentId, parse) { + const names = await listNames(client, parentId); + return mapLimited(names, async (name) => { + const { dynamicField } = await client.core.getDynamicField({ parentId, name }); + return { name, value: parse(dynamicField.value.bcs) }; + }); +} +export async function fetchMembers(client, vault) { + const entries = await readEntries(client, vault.tables.members, (b) => bcs.u8().parse(b)); + return entries.map((e) => ({ + address: bcs.Address.parse(e.name.bcs), + roles: e.value, + })); +} +/** The `TypeName` a `Table` or the funds `Bag` is keyed by. */ +function parseTypeNameKey(bytes) { + const name = bcs.struct('TypeName', { name: bcs.string() }).parse(bytes).name; + // Move reports a type name without the leading `0x`; restore it so the string matches the + // coin type an interface or an RPC filter would use. + return name.startsWith('0x') ? name : `0x${name}`; +} +export async function fetchLimits(client, vault) { + const entries = await readEntries(client, vault.tables.limits, (b) => toLimits(AssetLimitsBcs.parse(b))); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), limits: e.value })); +} +export async function fetchBalances(client, vault) { + const entries = await readEntries(client, vault.tables.funds, (b) => big(bcs.u64().parse(b))); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), balance: e.value })); +} +export async function fetchVelocity(client, vault) { + const entries = await readEntries(client, vault.tables.velocity, (b) => { + const raw = VelocityBcs.parse(b); + return { + dayAnchor: num(raw.day_anchor), + daySpent: big(raw.day_spent), + envelopeAnchor: num(raw.envelope_anchor), + envelopeSpent: big(raw.envelope_spent), + envelopeBasis: big(raw.envelope_basis), + }; + }); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), velocity: e.value })); +} +export async function fetchRecipients(client, vault) { + const entries = await readEntries(client, vault.tables.recipients, (b) => RecipientBcs.parse(b)); + return entries.map((e) => ({ + address: bcs.Address.parse(e.name.bcs), + trust: num(e.value.trust), + registeredAt: num(e.value.registered_at), + activatesAt: num(e.value.activates_at), + paidCount: num(e.value.paid_count), + lastPaid: num(e.value.last_paid), + label: e.value.label, + })); +} +function toProposal(raw) { + return { + id: big(raw.id), + kind: num(raw.kind), + status: num(raw.status), + proposer: raw.proposer, + createdAt: num(raw.created_at), + executableAt: num(raw.executable_at), + expiresAt: num(raw.expires_at), + reqApprovals: raw.req_approvals, + reqGuardians: raw.req_guardians, + tier: num(raw.tier), + reasons: num(raw.reasons), + exposureBps: num(raw.exposure_bps), + policyVersion: big(raw.policy_version), + reductionMask: num(raw.reduction_mask), + approvals: raw.approvals.contents, + confirmations: raw.confirmations.contents, + asset: raw.asset ? (raw.asset.name.startsWith('0x') ? raw.asset.name : `0x${raw.asset.name}`) : null, + amount: big(raw.amount), + recipient: raw.recipient, + memo: raw.memo, + newPolicy: raw.new_policy ? toPolicy(raw.new_policy) : null, + newLimits: raw.new_limits ? toLimits(raw.new_limits) : null, + member: raw.member, + memberPrev: raw.member_prev, + memberRoles: raw.member_roles, + trustLevel: num(raw.trust_level), + targetMode: num(raw.target_mode), + }; +} +/** One proposal by its number. */ +export async function fetchProposal(client, vault, id) { + try { + const { dynamicField } = await client.core.getDynamicField({ + parentId: vault.tables.proposals, + name: { type: 'u64', bcs: bcs.u64().serialize(id).toBytes() }, + }); + return toProposal(ProposalBcs.parse(dynamicField.value.bcs)); + } + catch { + return null; + } +} +/** + * The most recent proposals, newest first. Proposal numbers are sequential from 1, so this walks + * backwards from the counter instead of listing the whole table — a vault with ten thousand + * settled payments should not have to read all of them to show the queue. + */ +export async function fetchRecentProposals(client, vault, count = 25) { + const last = vault.nextProposal - 1n; + const ids = []; + for (let i = last; i > 0n && ids.length < count; i--) + ids.push(i); + const got = await mapLimited(ids, (id) => fetchProposal(client, vault, id)); + return got.filter((p) => p !== null); +} +/** + * What the vault itself says a transfer would need, read by simulating its own + * `preview_transfer`. The interface never computes this for a live vault: if the preview and the + * execution could disagree, the preview is worthless. + */ +export async function previewTransfer(client, input) { + const tx = previewTransferTx(input.packageId, input); + tx.setSender(input.sender); + const result = await client.core.simulateTransaction({ + transaction: await tx.build({ client }), + include: { commandResults: true }, + }); + const values = result.commandResults?.[0]?.returnValues; + if (!values || values.length < 6) { + throw new Error('preview_transfer returned no values; is the package id correct?'); + } + const at = (i) => values[i].bcs ?? values[i]; + return { + tier: num(bcs.u8().parse(at(0))), + reasons: num(bcs.u16().parse(at(1))), + exposureBps: num(bcs.u64().parse(at(2))), + reqApprovals: num(bcs.u8().parse(at(3))), + reqGuardians: num(bcs.u8().parse(at(4))), + delay: num(bcs.u64().parse(at(5))), + }; +} +export async function fetchVaultView(client, vaultId, proposalCount = 25) { + const vault = await fetchVault(client, vaultId); + const [members, limits, balances, velocity, recipients, proposals] = await Promise.all([ + fetchMembers(client, vault), + fetchLimits(client, vault), + fetchBalances(client, vault), + fetchVelocity(client, vault), + fetchRecipients(client, vault), + fetchRecentProposals(client, vault, proposalCount), + ]); + const balanceOf = new Map(balances.map((b) => [b.coinType, b.balance])); + const velocityOf = new Map(velocity.map((v) => [v.coinType, v.velocity])); + return { + vault, + members, + recipients, + proposals, + assets: limits.map((l) => ({ + coinType: l.coinType, + limits: l.limits, + balance: balanceOf.get(l.coinType) ?? 0n, + velocity: velocityOf.get(l.coinType) ?? null, + })), + }; +} +//# sourceMappingURL=vault.js.map \ No newline at end of file diff --git a/sdk/dist/vault.js.map b/sdk/dist/vault.js.map new file mode 100644 index 0000000..ad118ae --- /dev/null +++ b/sdk/dist/vault.js.map @@ -0,0 +1 @@ +{"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EACL,cAAc,EACd,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACL,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,IAAI,EACJ,KAAK,GAQN,MAAM,YAAY,CAAC;AAEpB;;;;;;GAMG;AAEH,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,KAAK,UAAU,UAAU,CAAO,KAAU,EAAE,EAAwB,EAAE,KAAK,GAAG,WAAW;IACvF,MAAM,GAAG,GAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;QAC/E,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;YACjB,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC9B,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,GAAG,CAAC,CAA2B;IACtC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,GAAG,CAAC,CAA2B;IACtC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAuC;IACvD,OAAO;QACL,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,aAAa,EAAE,GAAG,CAAC,cAAc;QACjC,iBAAiB,EAAE,GAAG,CAAC,kBAAkB;QACzC,mBAAmB,EAAE,GAAG,CAAC,oBAAoB;QAC7C,iBAAiB,EAAE,GAAG,CAAC,kBAAkB;QACzC,wBAAwB,EAAE,GAAG,CAAC,0BAA0B;QACxD,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;QAC9B,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QACtC,wBAAwB,EAAE,GAAG,CAAC,GAAG,CAAC,0BAA0B,CAAC;QAC7D,iBAAiB,EAAE,GAAG,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAC/C,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QACtC,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QAClC,eAAe,EAAE,GAAG,CAAC,GAAG,CAAC,iBAAiB,CAAC;QAC3C,mBAAmB,EAAE,GAAG,CAAC,GAAG,CAAC,qBAAqB,CAAC;QACnD,oBAAoB,EAAE,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC;QACtD,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QAClC,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,GAA4C;IAC5D,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QACxB,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;QAC7B,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAyB,EACzB,OAAe;IAEf,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAClG,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACzC,OAAO;QACL,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1B,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QACpC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAS;QACzB,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC;QACtC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;QAC9B,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QACpC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QACpC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;QACpC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC;QAClC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC;QAClC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;QAC5B,MAAM,EAAE;YACN,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE;YACrB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;YACnB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE;YACjB,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE;YACvB,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE;YAC3B,SAAS,EAAE,CAAC,CAAC,SAAS,CAAC,EAAE;SAC1B;QACD,KAAK,EAAE;YACL,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;YAC5B,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC;YAC1B,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YACxB,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC9B,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;YAClC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC;SACjC;KACF,CAAC;AACJ,CAAC;AAED,iEAAiE;AACjE,KAAK,UAAU,SAAS,CAAC,MAAyB,EAAE,QAAgB;IAClE,MAAM,KAAK,GAAwC,EAAE,CAAC;IACtD,IAAI,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACxE,SAAS,CAAC;QACR,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,MAAM;QAC7B,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,MAAyB,EACzB,QAAgB,EAChB,KAA+B;IAE/B,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChD,OAAO,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAyB,EACzB,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACtC,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CAAC;AACN,CAAC;AAED,4EAA4E;AAC5E,SAAS,gBAAgB,CAAC,KAAiB;IACzC,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;IAC9E,0FAA0F;IAC1F,qDAAqD;IACrD,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAyB,EACzB,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CACnE,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAClC,CAAC;IACF,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAyB,EACzB,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9F,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAyB,EACzB,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACrE,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;YAC9B,QAAQ,EAAE,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;YAC5B,cAAc,EAAE,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC;YACxC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;YACtC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;SACpB,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAyB,EACzB,KAAmB;IAEnB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjG,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACtC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAU;QAClC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;QACxC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;QACtC,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC;QAClC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;QAChC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK;KACrB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,UAAU,CAAC,GAAyC;IAC3D,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACf,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAS;QAC3B,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAW;QACjC,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;QAC9B,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,aAAa,CAAC;QACpC,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;QAC9B,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAS;QAC3B,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;QACzB,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QAClC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QACtC,aAAa,EAAE,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC;QACtC,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ;QACjC,aAAa,EAAE,GAAG,CAAC,aAAa,CAAC,QAAQ;QACzC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI;QACpG,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,SAAS,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI;QAC3D,SAAS,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI;QAC3D,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,UAAU,EAAE,GAAG,CAAC,WAAW;QAC3B,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAU;QACzC,UAAU,EAAE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAS;KACzC,CAAC;AACJ,CAAC;AAED,kCAAkC;AAClC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAyB,EACzB,KAAmB,EACnB,EAAU;IAEV,IAAI,CAAC;QACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;YACzD,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS;YAChC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE;SAC9D,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAyB,EACzB,KAAmB,EACnB,KAAK,GAAG,EAAE;IAEV,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,GAAG,EAAE,CAAC;IACrC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC5E,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAyB,EACzB,KAOC;IAED,MAAM,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACrD,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC;QACnD,WAAW,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACvC,OAAO,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE;KAClC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC;IACxD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAS;QACtD,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAC;QAClD,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAC;QACtD,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAC;QACtD,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAC;QACtD,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAe,CAAC,CAAC;KACjD,CAAC;AACJ,CAAC;AAWD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAyB,EACzB,OAAe,EACf,aAAa,GAAG,EAAE;IAElB,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACrF,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;QAC3B,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;QAC1B,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC;QAC5B,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC;QAC5B,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC;QAC9B,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC;KACnD,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO;QACL,KAAK;QACL,OAAO;QACP,UAAU;QACV,SAAS;QACT,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE;YACxC,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI;SAC7C,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/sdk/package-lock.json b/sdk/package-lock.json new file mode 100644 index 0000000..5715373 --- /dev/null +++ b/sdk/package-lock.json @@ -0,0 +1,1936 @@ +{ + "name": "@skur/sdk", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@skur/sdk", + "version": "0.1.0", + "dependencies": { + "@mysten/sui": "^2.34.0" + }, + "devDependencies": { + "@types/node": "^24.19.1", + "typescript": "~6.0.2", + "vitest": "^3.2.7" + } + }, + "node_modules/@0no-co/graphql.web": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.3.4.tgz", + "integrity": "sha512-imSwulOeDQodRy/olQmVEo2PiY6ntjkZ9eiGdw6lMYylh/tay9b7MusyJBmEnkL8GiKRKr6ltr+D42mY5bd8Bg==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@0no-co/graphqlsp": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.17.5.tgz", + "integrity": "sha512-wsygfTO3pdkz4idDw8BxdMdgB9AB8nuJDJTUwYy87BiZEZRXS4bEfn4oNl9VtxTo6j2lzX/gED+IvOgxsSy2Jg==", + "license": "MIT", + "dependencies": { + "@gql.tada/internal": "^1.2.1", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@gql.tada/cli-utils": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.9.4.tgz", + "integrity": "sha512-xQ9M+2Xxjxhz9IJi+7IMU/aOsEtuSiSNb4OgDMBUC/8AcSpo2vDtx71Aodsaif4qSwuTb0YFVfDwC+ESqiZSHg==", + "license": "MIT", + "dependencies": { + "@0no-co/graphqlsp": "^1.17.3", + "@gql.tada/internal": "1.2.2", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "@0no-co/graphqlsp": "^1.16.0", + "@gql.tada/svelte-support": "1.0.3", + "@gql.tada/vue-support": "1.0.3", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@gql.tada/svelte-support": { + "optional": true + }, + "@gql.tada/vue-support": { + "optional": true + } + } + }, + "node_modules/@gql.tada/internal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.2.2.tgz", + "integrity": "sha512-4lZcElPP6MC8Ct8KN70LR2WQsHjbAsyAmTGG09VsOPhx738UFIYaL0S1XiI2pqq2tj/sDs/y3b9jvKoWGL7iuQ==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.3.1" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@mysten/bcs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-2.1.2.tgz", + "integrity": "sha512-fv6lyuZMTHN0xRlu4GYiV/UXUrdJDOHbXm1KfZYEU0sy/t+22yTrTVtWnAQv1Km7eyB3qHhwIrAG2aem4JMocw==", + "license": "Apache-2.0", + "dependencies": { + "@mysten/utils": "^0.4.1", + "@scure/base": "^2.3.0" + } + }, + "node_modules/@mysten/sui": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-2.34.0.tgz", + "integrity": "sha512-Qf/xt10YIJv3Yo0hQTU70xPgimFfw2mudBzI/dylGXZNuhuQVmkmxUm0fz49BFPOFvBxWc/MRFl204zwpwRnXw==", + "license": "Apache-2.0", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "@mysten/bcs": "^2.1.2", + "@mysten/utils": "^0.4.1", + "@noble/curves": "^2.3.0", + "@noble/hashes": "^2.3.0", + "@protobuf-ts/grpcweb-transport": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "@scure/base": "^2.3.0", + "@scure/bip32": "^2.3.0", + "@scure/bip39": "^2.3.0", + "gql.tada": "^1.11.3", + "graphql": "^17.0.2", + "poseidon-lite": "0.3.0", + "valibot": "^1.4.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@mysten/utils": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@mysten/utils/-/utils-0.4.1.tgz", + "integrity": "sha512-gffLJ84CbqG/CcOPuVlwXIRu37tFn0BtUx7CQtbLwJzWjUE7FU2Gq8BXWjzxImnvufcyLTaNWtCPG6wq22Zhog==", + "license": "Apache-2.0", + "dependencies": { + "@scure/base": "^2.3.0" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@noble/curves": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", + "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.4.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@protobuf-ts/grpcweb-transport": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/grpcweb-transport/-/grpcweb-transport-2.11.1.tgz", + "integrity": "sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.64.0.tgz", + "integrity": "sha512-FLLpX941CD/7aBvX3GqLGBM9OvY5PGXTryPJkG5r5/OuBpZpV5k45Uo3RxAvqd35tsyc3hH1bhtz921IKzoIzg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.64.0.tgz", + "integrity": "sha512-iI32XM/jnDYJsvx5ai/za/7gWO9XoSeFFtU06/ZCaRgyilfJOjaopD3nOpk2WrTCGOyeDt4hleUiGOAnd5tHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.64.0.tgz", + "integrity": "sha512-dRBZlbt2sEtF8Mn4MODThze9fIPdDoOhVSlXMAKy5dQbOYK9pOOoPY4Fat3OTtr0+8zbJo5TTZwlsfxY/kDNJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.64.0.tgz", + "integrity": "sha512-Y3whrJOMucfkhgNkvcM93M6j8C53iEAMmPMYD99C6G1kUy4ELigLWk9ar2/4aCBSRgsql0zdlOemLgW2m5GZgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.64.0.tgz", + "integrity": "sha512-S6S1GEzPjFF6IONYJX3AKt/799+8RgBgCcwRnUo+Ep1IvBxUbw5M51iU0TDdK2NWWVnSvCQ8yi6Em0fGASMOng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.64.0.tgz", + "integrity": "sha512-Ed1DPoFENkXj4IGzSB12SesV40iP6LxCCrbTIkSGIQBpOOxpBM+0kj62lmaeIHfMWTDoddqTOtqc7s8LYfn+Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.64.0.tgz", + "integrity": "sha512-J/6xhutJPtFyIkmHdf4olOdHHKH5kOJNumojdWn+Elv5ICEYTVOa362Vw27TxsK0BLzb1le3EDlO3UbvFK1lnQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.64.0.tgz", + "integrity": "sha512-G4L/Nnx59d2LvDoV/P4S5lZ7oVLT6hodOHMacqjiq2LL2gts86KbkEBTYL53+fBt0odhf7XPIbIATGoYiJctxg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.64.0.tgz", + "integrity": "sha512-zF16pvJDEUksGYRbfnXne7pdklAyj2XDmJeYKgP93oq0cUyX9Y8O7lUo1R+IY1GagP/YBvCEDCe7eEcAKpw//g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.64.0.tgz", + "integrity": "sha512-nIggWn8n+w12+R5lsV+PYYoUY8vuObxPAQqJI7WES+9v0qspYuAHoZMfYM0yLxlipasT5BY9ht5W8t5c/rSCkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.64.0.tgz", + "integrity": "sha512-WLOTiHPzszP0dxIMsHpFeDSOSB5I49Mj8K4+yKE3H1X/D0JRG5XZ5jrctJLMjnUc/LUzaKiwq6EHWNJ8pup8PA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.64.0.tgz", + "integrity": "sha512-35RK9aRhh7g7Pmeu5gQ01aCvrhXzj9LoBE6xtUcEH1ns+nyTaSzxSpADmBQINu4QiTDGvmQYwo1j5hlg1rRXFw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.64.0.tgz", + "integrity": "sha512-RqTfnpoTjuWfPAmqK5p2edt2AMCDJWm6oTn7sKfmyx+6tRga0ip05SJ977o6udTcIiDeF/CJMUfkaN4gtWt6Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.64.0.tgz", + "integrity": "sha512-RQjZPigjxFvFZDijG6rjlSXxhRaTf9zLYVpGK+lVcga64oMqP1GbgVqCb46eHTTceSIgp89Ja0y5aPe3GFBYHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.64.0.tgz", + "integrity": "sha512-tjL58mgQcTRnDRpeky+Sth1MKQeYi2Ct6r3Luq9E5aTSjnM/i/JbozqZkKqp9thM5+oDSZxo+05f9kdQedfTGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.64.0.tgz", + "integrity": "sha512-ictoRyVaoZ8C67myHef+8hhCa6IplXJJ/xUCkVCxziV4zxMZh+jvhkhGsPBLqj1S72fnqD0QH5zL4lcaa4X7DQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.64.0.tgz", + "integrity": "sha512-8aVvZ2hfr9RLFzBQkQNmYeHLDja8fLeQAmLt757zdKN/B+8L809KlLJKctQjS22wZotptV8G6o7fVPuAs8S1tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.64.0.tgz", + "integrity": "sha512-2dEF8GAcDKwshUfydD+GhosppNyBzhVUHkdFF3CXd3FpOkzj/RZzF5aoEtzklujklT5qFVRU2GK/cFeLaTNKVg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.64.0.tgz", + "integrity": "sha512-3XHTvoo2hKkh0MiOfS7SkhHjMaaWF7P4F3drocZZaho/Z8w7h/jpnuBHm91BOQLfvrKHs1yR+zir4E8RI3XzTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.64.0.tgz", + "integrity": "sha512-HKtkzodL4a3KFWDXDoO61cRynAWTR3LnAE0oGtfG9lcNFpNuVYUFOByxDgNqEvic9rvaQbAj+SFwTEWDptRaIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.64.0.tgz", + "integrity": "sha512-JBsxqiY16uyyCujtoC3s7zL+SrYyNElptD7K4V+KUoJ2V8/XG3hPWpheK+SuPwNh1cikJvIZmIdsrYXvD6PLJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.64.0.tgz", + "integrity": "sha512-S5Qrijh37qhnUYQ0ay8WN3LuWeKjow7wTUyCOPMZtnXiBXYXdsZETI6ZLfYnQAKovltckPLBFdNeD61P2rJc7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.64.0.tgz", + "integrity": "sha512-zbZ6iMmLFEsCtTdc2/y1F/cDFVNNCPF7Ae8PCT/wdPE//hGwYp6r+MyCLMFX+kOeIe09Pz6ASfnnfpSTN1FJQQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.64.0.tgz", + "integrity": "sha512-L6Hw69oNpuYaOr1zCG30v0/DqKYCSRwodPGwIcVZ/6f8SOzq9rxtL/xNVI5MO4wjli+Ko0ErK9uHJL3mNPt8wQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.64.0.tgz", + "integrity": "sha512-nl+CTWIgOGszQmUz/kanfgrfFZ4qiwxKIfT/ryl3N3Ewk5tqizmYtNXiqb7Bu/fDtNgu1kyxdFiAUJNur3iysg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.4.0.tgz", + "integrity": "sha512-i3DS0CptAocyvqE4n3SUkpzeQK4vJMFwWLofTwRiiKo2aWojBOfyMCgfKw9HVpO6fSY5AK86sHS/Uzn8kK9Few==", + "license": "MIT", + "dependencies": { + "@noble/curves": "2.4.0", + "@noble/hashes": "2.4.0", + "@scure/base": "2.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.4.0.tgz", + "integrity": "sha512-82dxFbZUYboyOf0AXiydsQrFQ5Q4h9mX+O2UkE91ROYmsc0BKMGZLwDmy96Jpa2+vrtoxomjUhy1RPIgH/r2nA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.1.tgz", + "integrity": "sha512-aS3/DG0oM05K0RIXXP+hKjinGG5IgSSVGzswZxW3O0sS3pH4/fycXundUC9XsszgKCk4gHXylTEK6hyFxVxnoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", + "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", + "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.7", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", + "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", + "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.7", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", + "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", + "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", + "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gql.tada": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.11.4.tgz", + "integrity": "sha512-UQnhJUhSM0MV8cpcgjci/7ET8LnmHx9o9FtZqU4sH+ILiBVG5rnfXJzNdzTN+Y7MuCz6Pp3XE/VPEVqmO969jw==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.3.2", + "@0no-co/graphqlsp": "^1.17.3", + "@gql.tada/cli-utils": "1.9.4", + "@gql.tada/internal": "1.2.2" + }, + "bin": { + "gql-tada": "bin/cli.js", + "gql.tada": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/graphql": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-17.0.2.tgz", + "integrity": "sha512-FRWbddMxfkjiB7z+aQDWIR+E34xo9I8c9mtK2RPv8PmMzKRvrdsreHL/Ui/TmwHJfhHChEtsFPyMHKI+xuarQQ==", + "license": "MIT", + "engines": { + "node": "^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/poseidon-lite": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/poseidon-lite/-/poseidon-lite-0.3.0.tgz", + "integrity": "sha512-ilJj4MIve4uBEG7SrtPqUUNkvpJ/pLVbndxa0WvebcQqeIhe+h72JR4g0EvwchUzm9sOQDlOjiDNmRAgxNZl4A==", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.64.0.tgz", + "integrity": "sha512-gjA/kFeDfffII8COoPsvLPvE16hWDTEc1+0QKQNKUkuV8iJjqsC4xXs8/FzuL0v9EV39kuxTbAgcFoTRyy2TGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.64.0", + "@rollup/rollup-android-arm64": "4.64.0", + "@rollup/rollup-darwin-arm64": "4.64.0", + "@rollup/rollup-darwin-x64": "4.64.0", + "@rollup/rollup-freebsd-arm64": "4.64.0", + "@rollup/rollup-freebsd-x64": "4.64.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.64.0", + "@rollup/rollup-linux-arm-musleabihf": "4.64.0", + "@rollup/rollup-linux-arm64-gnu": "4.64.0", + "@rollup/rollup-linux-arm64-musl": "4.64.0", + "@rollup/rollup-linux-loong64-gnu": "4.64.0", + "@rollup/rollup-linux-loong64-musl": "4.64.0", + "@rollup/rollup-linux-ppc64-gnu": "4.64.0", + "@rollup/rollup-linux-ppc64-musl": "4.64.0", + "@rollup/rollup-linux-riscv64-gnu": "4.64.0", + "@rollup/rollup-linux-riscv64-musl": "4.64.0", + "@rollup/rollup-linux-s390x-gnu": "4.64.0", + "@rollup/rollup-linux-x64-gnu": "4.64.0", + "@rollup/rollup-linux-x64-musl": "4.64.0", + "@rollup/rollup-openbsd-x64": "4.64.0", + "@rollup/rollup-openharmony-arm64": "4.64.0", + "@rollup/rollup-win32-arm64-msvc": "4.64.0", + "@rollup/rollup-win32-ia32-msvc": "4.64.0", + "@rollup/rollup-win32-x64-gnu": "4.64.0", + "@rollup/rollup-win32-x64-msvc": "4.64.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz", + "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/valibot": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.5.0.tgz", + "integrity": "sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", + "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.7", + "@vitest/mocker": "3.2.7", + "@vitest/pretty-format": "^3.2.7", + "@vitest/runner": "3.2.7", + "@vitest/snapshot": "3.2.7", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.7", + "@vitest/ui": "3.2.7", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/sdk/package.json b/sdk/package.json new file mode 100644 index 0000000..77bf312 --- /dev/null +++ b/sdk/package.json @@ -0,0 +1,37 @@ +{ + "name": "@skur/sdk", + "private": true, + "version": "0.1.0", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./engine": { + "types": "./dist/engine/index.d.ts", + "import": "./dist/engine/index.js" + }, + "./src/*": "./src/*" + }, + "scripts": { + "build": "tsc -p tsconfig.build.json", + "typecheck": "tsc --noEmit", + "test": "vitest run", + "prepare": "tsc -p tsconfig.build.json" + }, + "dependencies": { + "@mysten/sui": "^2.34.0" + }, + "devDependencies": { + "@types/node": "^24.19.1", + "typescript": "~6.0.2", + "vitest": "^3.2.7" + }, + "files": [ + "dist", + "src" + ] +} diff --git a/sdk/scripts/seed.ts b/sdk/scripts/seed.ts new file mode 100644 index 0000000..42e44c8 --- /dev/null +++ b/sdk/scripts/seed.ts @@ -0,0 +1,129 @@ +/** + * Create a demonstration vault and fund it, so an evaluator can open a real one rather than read + * about it. + * + * SUI_PRIVATE_KEY=suiprivkey1... \ + * SKUR_NETWORK=testnet \ + * SKUR_PACKAGE_ID=0x... \ + * node --experimental-strip-types scripts/seed.ts + * + * The roster is deliberately realistic: two owners, a separate approver, a guardian that holds no + * treasury role, and an agent that can only propose. Addresses other than the deployer's are + * derived placeholders unless given — the point is to show the shape, and the deployer keeps the + * roles needed to drive a demo alone. + */ +import { readFile, writeFile } from 'node:fs/promises'; +import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; +import { SUI_TYPE_ARG } from '@mysten/sui/utils'; +import { decodeSuiPrivateKey } from '@mysten/sui/cryptography'; +import { grpcClient, Role, templateById, tx as build, type Network } from '../src/index.ts'; + +const network = (process.env.SKUR_NETWORK ?? 'testnet') as Network; +const packageId = process.env.SKUR_PACKAGE_ID; +const secret = process.env.SUI_PRIVATE_KEY; + +if (!packageId) throw new Error('SKUR_PACKAGE_ID is not set'); +if (!secret) throw new Error('SUI_PRIVATE_KEY is not set (use a throwaway key for a demo)'); + +const { secretKey } = decodeSuiPrivateKey(secret); +const keypair = Ed25519Keypair.fromSecretKey(secretKey); +const me = keypair.toSuiAddress(); +const client = grpcClient(network); + +const extra = (process.env.SKUR_SIGNERS ?? '').split(',').map((s) => s.trim()).filter(Boolean); +const [owner2 = me, approver = me, guardian, agent] = extra; + +const template = templateById('startup'); + +// A guardian must hold no treasury role, so a demo without a second key cannot have one. Saying +// so is better than quietly creating a vault with a guardian that is also an owner, which the +// contract would refuse anyway. +const members = [ + { address: me, roles: Role.OWNER | Role.APPROVER | Role.EXECUTOR }, + ...(owner2 !== me ? [{ address: owner2, roles: Role.OWNER | Role.APPROVER }] : []), + ...(approver !== me && approver !== owner2 ? [{ address: approver, roles: Role.APPROVER }] : []), + ...(guardian ? [{ address: guardian, roles: Role.GUARDIAN }] : []), + ...(agent ? [{ address: agent, roles: Role.PROPOSER }] : []), +]; + +// The template's policy assumes a roster this demo may not have, so the thresholds are brought +// down to what these members can actually satisfy. A vault whose threshold nobody can reach is a +// frozen vault, and the contract refuses to create one. +const owners = members.filter((m) => (m.roles & Role.OWNER) !== 0).length; +const approvers = members.filter((m) => (m.roles & Role.APPROVER) !== 0).length; +const guardians = members.filter((m) => (m.roles & Role.GUARDIAN) !== 0).length; +const policy = { + ...template.policy, + governanceThreshold: Math.min(template.policy.governanceThreshold, owners), + approvalsLow: Math.min(template.policy.approvalsLow, approvers), + approvalsHigh: Math.min(template.policy.approvalsHigh, approvers), + approvalsCritical: Math.min(template.policy.approvalsCritical, approvers), + guardianThreshold: Math.min(template.policy.guardianThreshold, guardians), + guardianRequiredCritical: guardians > 0 && template.policy.guardianRequiredCritical, +}; + +async function main() { + console.log(`seeding on ${network} as ${me}`); + + const transaction = build.createVault(packageId!, { + name: 'Skur Demo Treasury', + policy, + members, + assets: [{ coinType: SUI_TYPE_ARG, limits: template.native }], + recipients: [{ address: me, label: 'Operations' }], + }); + + const result = await client.signAndExecuteTransaction({ + transaction, + signer: keypair, + include: { effects: true, objectTypes: true }, + }); + await client.waitForTransaction({ result }); + + const settled = result.Transaction ?? result.FailedTransaction; + if (!settled?.status.success) { + throw new Error(`vault creation failed: ${JSON.stringify(settled?.status)}`); + } + + // `objectTypes` maps each changed object id to its type, which is how the new shared Vault is + // identified without guessing from ownership. + const types = result.Transaction?.objectTypes ?? {}; + const vaultId = settled.effects?.changedObjects.find( + (o) => o.idOperation === 'Created' && types[o.objectId]?.endsWith('::vault::Vault'), + )?.objectId; + if (!vaultId) throw new Error('the vault object id was not in the effects'); + console.log(`vault: ${vaultId}`); + + const fund = build.deposit(packageId!, { + vaultId, + coinType: SUI_TYPE_ARG, + amount: 1_000_000_000n, // 1 SUI + }); + const funded = await client.signAndExecuteTransaction({ + transaction: fund, + signer: keypair, + include: { effects: true }, + }); + await client.waitForTransaction({ result: funded }); + console.log('funded with 1 SUI'); + + const path = new URL(`../../sui/deployments/${network}.json`, import.meta.url).pathname; + try { + const file = JSON.parse(await readFile(path, 'utf8')); + file.vaults = [ + ...(file.vaults ?? []).filter((v: { id: string }) => v.id !== vaultId), + { id: vaultId, name: 'Skur Demo Treasury' }, + ]; + await writeFile(path, `${JSON.stringify(file, null, 2)}\n`); + console.log(`recorded in ${path}`); + } catch { + console.log(`could not update ${path}; record the vault id by hand`); + } + + console.log(`explorer: https://suiscan.xyz/${network}/object/${vaultId}`); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/sdk/src/bcs.ts b/sdk/src/bcs.ts new file mode 100644 index 0000000..da65b11 --- /dev/null +++ b/sdk/src/bcs.ts @@ -0,0 +1,133 @@ +import { bcs } from '@mysten/sui/bcs'; + +/** + * BCS layouts for the Move structs, in declaration order. BCS is positional, so these must match + * `sui/sources/*.move` field for field — reordering a field in Move without reordering it here + * silently misreads every vault. + * + * Parsed over the `content` bytes from `getObject({ include: { content: true } })`, which is the + * stable representation. The `json` include is explicitly documented as not guaranteed across + * clients, so nothing here uses it. + */ + +/** `sui::object::UID` is a single 32-byte id on the wire. */ +const UID = bcs.Address; + +/** `sui::table::Table` and `sui::bag::Bag` both serialise as a handle plus a count. */ +const Handle = bcs.struct('Handle', { id: UID, size: bcs.u64() }); + +const TypeNameBcs = bcs.struct('TypeName', { name: bcs.string() }); + +const VecSetAddress = bcs.struct('VecSet
      ', { + contents: bcs.vector(bcs.Address), +}); + +export const PolicyBcs = bcs.struct('Policy', { + approvals_low: bcs.u8(), + approvals_high: bcs.u8(), + approvals_critical: bcs.u8(), + governance_threshold: bcs.u8(), + guardian_threshold: bcs.u8(), + guardian_required_critical: bcs.bool(), + delay_high: bcs.u64(), + delay_critical: bcs.u64(), + recipient_activation_delay: bcs.u64(), + policy_change_delay: bcs.u64(), + recovery_delay: bcs.u64(), + proposal_ttl: bcs.u64(), + high_exposure_bps: bcs.u64(), + critical_exposure_bps: bcs.u64(), + hard_block_exposure_bps: bcs.u64(), + envelope_bps: bcs.u64(), + envelope_window: bcs.u64(), +}); + +export const AssetLimitsBcs = bcs.struct('AssetLimits', { + approved: bcs.bool(), + low_max: bcs.u64(), + high_max: bcs.u64(), + per_tx_max: bcs.u64(), + daily_max: bcs.u64(), +}); + +export const VelocityBcs = bcs.struct('Velocity', { + day_anchor: bcs.u64(), + day_spent: bcs.u64(), + envelope_anchor: bcs.u64(), + envelope_spent: bcs.u64(), + envelope_basis: bcs.u64(), +}); + +export const RecipientBcs = bcs.struct('Recipient', { + trust: bcs.u8(), + registered_at: bcs.u64(), + activates_at: bcs.u64(), + paid_count: bcs.u64(), + last_paid: bcs.u64(), + label: bcs.string(), +}); + +export const ProposalBcs = bcs.struct('Proposal', { + id: bcs.u64(), + kind: bcs.u8(), + status: bcs.u8(), + proposer: bcs.Address, + created_at: bcs.u64(), + executable_at: bcs.u64(), + expires_at: bcs.u64(), + req_approvals: bcs.u8(), + req_guardians: bcs.u8(), + tier: bcs.u8(), + reasons: bcs.u16(), + exposure_bps: bcs.u64(), + policy_version: bcs.u64(), + reduction_mask: bcs.u32(), + approvals: VecSetAddress, + confirmations: VecSetAddress, + asset: bcs.option(TypeNameBcs), + amount: bcs.u64(), + recipient: bcs.Address, + memo: bcs.string(), + new_policy: bcs.option(PolicyBcs), + new_limits: bcs.option(AssetLimitsBcs), + member: bcs.Address, + member_prev: bcs.Address, + member_roles: bcs.u8(), + trust_level: bcs.u8(), + target_mode: bcs.u8(), +}); + +export const VaultBcs = bcs.struct('Vault', { + id: UID, + name: bcs.string(), + policy: PolicyBcs, + policy_version: bcs.u64(), + mode: bcs.u8(), + posture_reasons: bcs.u16(), + members: Handle, + owner_count: bcs.u64(), + approver_count: bcs.u64(), + executor_count: bcs.u64(), + guardian_count: bcs.u64(), + limits: Handle, + funds: Handle, + velocity: Handle, + recipients: Handle, + proposals: Handle, + next_proposal: bcs.u64(), + pending_count: bcs.u64(), + created_at: bcs.u64(), +}); + +/** `sui::balance::Balance` is a single u64 on the wire. */ +export const BalanceBcs = bcs.struct('Balance', { value: bcs.u64() }); + +/** A `Table` entry is stored as `Field` under the table's own id. */ +export function fieldBcs( + key: ReturnType, + value: { parse: (bytes: Uint8Array) => V }, +) { + return { key, value }; +} + +export { bcs }; diff --git a/sdk/src/engine/format.ts b/sdk/src/engine/format.ts new file mode 100644 index 0000000..72a422a --- /dev/null +++ b/sdk/src/engine/format.ts @@ -0,0 +1,80 @@ +/** + * Formatting for amounts, durations and shares. No chain dependency: the EVM build imported these + * from viem, which is why they are implemented here instead. + * + * Durations are milliseconds throughout, matching `sui::clock`. + */ + +export function formatUnits(value: bigint, decimals: number): string { + const neg = value < 0n; + const abs = neg ? -value : value; + const base = 10n ** BigInt(decimals); + const int = abs / base; + const frac = abs % base; + const fracText = decimals === 0 ? '' : frac.toString().padStart(decimals, '0').replace(/0+$/, ''); + return `${neg ? '-' : ''}${int}${fracText ? `.${fracText}` : ''}`; +} + +export function parseUnits(text: string, decimals: number): bigint | null { + const cleaned = text.replace(/[, _]/g, '').trim(); + if (!cleaned || !/^-?\d*(\.\d*)?$/.test(cleaned)) return null; + const neg = cleaned.startsWith('-'); + const body = neg ? cleaned.slice(1) : cleaned; + const [int = '0', frac = ''] = body.split('.'); + if (frac.length > decimals) return null; + const scaled = BigInt(int || '0') * 10n ** BigInt(decimals) + BigInt((frac || '0').padEnd(decimals, '0') || '0'); + return neg ? -scaled : scaled; +} + +export function short(addr: string, n = 4): string { + if (!addr) return ''; + if (addr.length <= 2 * n + 3) return addr; + return `${addr.slice(0, 2 + n)}…${addr.slice(-n)}`; +} + +export function fmtAmount(value: bigint, decimals: number, symbol?: string, maxFrac = 2): string { + const s = formatUnits(value, decimals); + const [int, frac = ''] = s.split('.'); + const intFmt = Number(int).toLocaleString('en-US'); + const fracTrim = frac.slice(0, maxFrac).replace(/0+$/, ''); + const out = fracTrim ? `${intFmt}.${fracTrim}` : intFmt; + return symbol ? `${out} ${symbol}` : out; +} + +export function parseAmount(text: string, decimals: number): bigint | null { + const v = parseUnits(text, decimals); + return v === null || v < 0n ? null : v; +} + +export function fmtBps(bps: number): string { + return `${(bps / 100).toFixed(bps % 100 === 0 ? 0 : 2)}%`; +} + +/** Milliseconds to something a person reads. */ +export function fmtDuration(ms: number): string { + if (ms <= 0) return 'none'; + const totalMinutes = Math.floor(ms / 60_000); + const d = Math.floor(totalMinutes / 1440); + const h = Math.floor((totalMinutes % 1440) / 60); + const m = totalMinutes % 60; + const parts: string[] = []; + if (d) parts.push(`${d}d`); + if (h) parts.push(`${h}h`); + if (m && !d) parts.push(`${m}m`); + return parts.join(' ') || `${Math.round(ms / 1000)}s`; +} + +export function fmtTimestamp(ms: number | bigint): string { + const n = Number(ms); + if (!n) return '—'; + return new Date(n).toLocaleString('en-US', { dateStyle: 'medium', timeStyle: 'short' }); +} + +export function fmtRelative(ms: number | bigint, now = Date.now()): string { + const n = Number(ms); + if (!n) return '—'; + const diff = n - now; + if (Math.abs(diff) < 60_000) return diff >= 0 ? 'now' : 'just now'; + const abs = fmtDuration(Math.abs(diff)); + return diff > 0 ? `in ${abs}` : `${abs} ago`; +} diff --git a/sdk/src/engine/index.ts b/sdk/src/engine/index.ts new file mode 100644 index 0000000..f237c10 --- /dev/null +++ b/sdk/src/engine/index.ts @@ -0,0 +1,17 @@ +/** + * The chain-agnostic core. These are the engines that make a Skur vault more than a threshold: + * the risk classifier, the policy rules and what counts as weakening them, the organization + * templates, the maximum-loss calculation, the posture report and the attack simulator. + * + * Every one of them mirrors a Move module and is pinned against the Move tests. They exist in + * TypeScript so an interface can preview a policy that is not deployed yet; for a live vault the + * chain is always authoritative. + */ +export * from './format.js'; +export * from './maxLoss.js'; +export * from './policy.js'; +export * from './policyFields.js'; +export * from './posture.js'; +export * from './risk.js'; +export * from './simulator.js'; +export * from './templates.js'; diff --git a/sdk/src/engine/maxLoss.ts b/sdk/src/engine/maxLoss.ts new file mode 100644 index 0000000..007596c --- /dev/null +++ b/sdk/src/engine/maxLoss.ts @@ -0,0 +1,112 @@ +import { DAY, Mode, type AssetLimits, type Policy } from '../types.js'; +import { effectiveCaps } from './risk.js'; +import { fmtDuration } from './format.js'; + +/** + * Maximum possible loss per asset, turned from a policy into numbers a finance team can act on. + * + * Conservative by construction: it assumes every signer a tier needs is compromised and + * cooperating, and that the attacker picks amounts optimally. It is an upper bound under the + * stated assumptions and never a guarantee — the assumptions are returned alongside the numbers + * so they cannot be quoted without them. + */ +export type MaxLoss = { + /** The most that can leave with no delay at all. */ + immediate: bigint; + /** The most that can leave within a day if no guardian acts. */ + day: bigint; + criticalDelay: number; + highDelay: number; + /** Which control produced each number. */ + immediateBinding: string; + dayBinding: string; + assumptions: string[]; +}; + +function min(...xs: bigint[]): bigint { + return xs.reduce((a, b) => (b < a ? b : a)); +} + +export function computeMaxLoss( + policy: Policy, + limits: AssetLimits, + balance: bigint, + mode: Mode, +): MaxLoss { + const caps = effectiveCaps(limits.perTxMax, limits.dailyMax, mode); + const assumptions = [ + 'Enough approvers to satisfy each tier are compromised and cooperate.', + 'Executors are compromised or colluding.', + 'No guardian vetoes or freezes the vault during any delay window.', + 'The attacker pays addresses that are already activated, not in probation.', + 'Limits are per asset: each asset has its own caps and its own envelope.', + ]; + + // Immediate: the routine tier needs no delay, so an attacker repeats it until a cumulative + // control binds. In Elevated there is no undelayed tier at all. + let immediate = 0n; + let immediateBinding = 'no undelayed tier'; + if (mode === Mode.NORMAL) { + const exposureLow = + policy.highExposureBps === 0 + ? balance + : (balance * BigInt(Math.max(policy.highExposureBps - 1, 0))) / 10_000n; + const perTransfer = min(limits.lowMax, caps.perTxMax || limits.lowMax, exposureLow); + if (perTransfer > 0n) { + immediate = balance; + immediateBinding = 'the entire balance (no daily cap and no envelope)'; + const envelope = + policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10_000n; + if (caps.dailyMax !== 0n && caps.dailyMax < immediate) { + immediate = caps.dailyMax; + immediateBinding = 'the daily cap'; + } + if (envelope !== 0n && envelope < immediate) { + immediate = envelope; + immediateBinding = `the loss envelope per ${fmtDuration(policy.envelopeWindow)}`; + } + } else { + immediateBinding = 'the routine tier is disabled by the limits'; + } + } + + // Within a day: the high tier is also reachable if its delay is under a day. Either way the + // attacker can straddle a bucket boundary and get two windows' worth. + const envelope = policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10_000n; + const perTx = caps.perTxMax === 0n ? balance : caps.perTxMax; + const highCeiling = + policy.criticalExposureBps === 0 + ? balance + : (balance * BigInt(Math.max(policy.criticalExposureBps - 1, 0))) / 10_000n; + const candidates: [bigint, string][] = [[balance, 'the entire balance']]; + if (caps.dailyMax !== 0n) + candidates.push([caps.dailyMax * 2n, 'two daily buckets across a boundary']); + if (envelope !== 0n) + candidates.push([envelope * 2n, 'two envelope windows across a boundary']); + if (policy.delayHigh >= DAY) { + candidates.push([immediate * 2n, 'the routine tier only, across two buckets']); + } else { + candidates.push([ + min(perTx, highCeiling) === 0n ? 0n : balance, + 'the high tier, reachable within a day', + ]); + } + let [day, dayBinding] = candidates.reduce((a, b) => (b[0] < a[0] ? b : a)); + + if (mode === Mode.LOCKDOWN) { + immediate = 0n; + day = 0n; + immediateBinding = 'the vault is in Lockdown'; + dayBinding = 'the vault is in Lockdown'; + } + + return { + immediate, + day, + criticalDelay: policy.delayCritical, + highDelay: policy.delayHigh, + immediateBinding, + dayBinding, + assumptions, + }; +} diff --git a/sdk/src/engine/policy.ts b/sdk/src/engine/policy.ts new file mode 100644 index 0000000..e4bd9a8 --- /dev/null +++ b/sdk/src/engine/policy.ts @@ -0,0 +1,131 @@ +import { BPS, HOUR, Trust, type AssetLimits, type Policy } from '../types.js'; +import { POLICY_ERRORS } from '../errors.js'; + +/** + * Mirror of `sui/sources/policy.move`. The codes are the Move abort codes, so a draft validated + * here fails for the same reason and with the same number as it would on chain. + */ +const MIN_EXECUTION_WINDOW = HOUR; + +export const OK = 0; + +export function validatePolicyCode(p: Policy): number { + if (p.approvalsLow === 0) return 1; + if (p.approvalsHigh < p.approvalsLow) return 2; + if (p.approvalsCritical < p.approvalsHigh) return 3; + if (p.governanceThreshold === 0) return 4; + if (p.guardianRequiredCritical && p.guardianThreshold === 0) return 5; + if (p.delayCritical < p.delayHigh) return 6; + if (p.criticalExposureBps !== 0 && p.highExposureBps > p.criticalExposureBps) return 7; + if (p.criticalExposureBps > Number(BPS) || p.highExposureBps > Number(BPS)) return 8; + if (p.hardBlockExposureBps !== 0 && p.hardBlockExposureBps < p.criticalExposureBps) return 9; + if (p.hardBlockExposureBps > Number(BPS)) return 10; + if (p.envelopeBps > Number(BPS)) return 11; + if (p.envelopeBps !== 0 && p.envelopeWindow < MIN_EXECUTION_WINDOW) return 12; + if (p.proposalTtl < longestDelay(p) + MIN_EXECUTION_WINDOW) return 13; + return OK; +} + +export function longestDelay(p: Policy): number { + return Math.max(p.delayCritical, p.policyChangeDelay, p.recoveryDelay, p.recipientActivationDelay); +} + +/** Every failing rule, not just the first, so an editor can mark all of them at once. */ +export function validatePolicy(p: Policy): string[] { + const errs: string[] = []; + const push = (code: number) => errs.push(POLICY_ERRORS[code]); + if (p.approvalsLow === 0) push(1); + if (p.approvalsHigh < p.approvalsLow) push(2); + if (p.approvalsCritical < p.approvalsHigh) push(3); + if (p.governanceThreshold === 0) push(4); + if (p.guardianRequiredCritical && p.guardianThreshold === 0) push(5); + if (p.delayCritical < p.delayHigh) push(6); + if (p.criticalExposureBps !== 0 && p.highExposureBps > p.criticalExposureBps) push(7); + if (p.criticalExposureBps > Number(BPS) || p.highExposureBps > Number(BPS)) push(8); + if (p.hardBlockExposureBps !== 0 && p.hardBlockExposureBps < p.criticalExposureBps) push(9); + if (p.hardBlockExposureBps > Number(BPS)) push(10); + if (p.envelopeBps > Number(BPS)) push(11); + if (p.envelopeBps !== 0 && p.envelopeWindow < MIN_EXECUTION_WINDOW) push(12); + if (p.proposalTtl < longestDelay(p) + MIN_EXECUTION_WINDOW) push(13); + return errs; +} + +export function validateLimits(l: AssetLimits): string[] { + const errs: string[] = []; + if (l.lowMax > l.highMax) errs.push(POLICY_ERRORS[20]); + if (l.perTxMax !== 0n && l.dailyMax !== 0n && l.perTxMax > l.dailyMax) errs.push(POLICY_ERRORS[21]); + return errs; +} + +export function validateCounts( + p: Policy, + owners: number, + approvers: number, + executors: number, + guardians: number, +): string[] { + const errs: string[] = []; + if (owners < 1) errs.push(POLICY_ERRORS[30]); + if (executors < 1) errs.push(POLICY_ERRORS[31]); + if (owners < p.governanceThreshold) + errs.push(`The governance threshold (${p.governanceThreshold}) exceeds the number of owners (${owners}).`); + if (approvers < p.approvalsCritical) + errs.push(`Critical approvals (${p.approvalsCritical}) exceed the number of approvers (${approvers}).`); + if (guardians < p.guardianThreshold) + errs.push(`The guardian threshold (${p.guardianThreshold}) exceeds the number of guardians (${guardians}).`); + return errs; +} + +/** Where zero means "disabled", going to zero is the loosest move available. */ +function thresholdLoosens(a: number | bigint, b: number | bigint): boolean { + if (a === 0 || a === 0n) return false; + if (b === 0 || b === 0n) return true; + return b > a; +} + +/** The fields `b` gives up relative to `a`. Empty means the change only tightens. */ +export function policyReductions(a: Policy, b: Policy): string[] { + const out: string[] = []; + if (b.approvalsLow < a.approvalsLow) out.push('fewer approvals for routine payments'); + if (b.approvalsHigh < a.approvalsHigh) out.push('fewer approvals for high-risk payments'); + if (b.approvalsCritical < a.approvalsCritical) out.push('fewer approvals for critical payments'); + if (b.governanceThreshold < a.governanceThreshold) out.push('a lower governance threshold'); + if (b.guardianThreshold < a.guardianThreshold) out.push('fewer guardian confirmations'); + if (a.guardianRequiredCritical && !b.guardianRequiredCritical) + out.push('no guardian required for critical payments'); + if (b.delayHigh < a.delayHigh) out.push('a shorter high-risk delay'); + if (b.delayCritical < a.delayCritical) out.push('a shorter critical delay'); + if (b.recipientActivationDelay < a.recipientActivationDelay) + out.push('a shorter new-recipient delay'); + if (b.policyChangeDelay < a.policyChangeDelay) out.push('a shorter policy-change delay'); + if (b.recoveryDelay < a.recoveryDelay) out.push('a shorter recovery delay'); + if (b.proposalTtl > a.proposalTtl) out.push('a longer proposal lifetime'); + if (thresholdLoosens(a.highExposureBps, b.highExposureBps)) + out.push('a higher exposure threshold before escalation'); + if (thresholdLoosens(a.criticalExposureBps, b.criticalExposureBps)) + out.push('a higher exposure threshold before critical'); + if (thresholdLoosens(a.hardBlockExposureBps, b.hardBlockExposureBps)) + out.push('a weaker exposure hard block'); + if (thresholdLoosens(a.envelopeBps, b.envelopeBps)) out.push('a larger loss envelope'); + if (a.envelopeBps !== 0 && b.envelopeWindow < a.envelopeWindow) + out.push('a shorter envelope window'); + return out; +} + +export function limitReductions(a: AssetLimits, b: AssetLimits): string[] { + const out: string[] = []; + if (!a.approved && b.approved) out.push('approving a new asset'); + if (b.lowMax > a.lowMax) out.push('a higher routine maximum'); + if (b.highMax > a.highMax) out.push('a higher high-tier maximum'); + if (thresholdLoosens(a.perTxMax, b.perTxMax)) out.push('a weaker per-transaction cap'); + if (thresholdLoosens(a.dailyMax, b.dailyMax)) out.push('a weaker daily cap'); + return out; +} + +/** Raising trust, or lifting a restriction, is security-reducing; tightening is not. */ +export function trustReduces(from: Trust, to: Trust): boolean { + const heldBack = from === Trust.RESTRICTED || from === Trust.BLOCKED || from === Trust.UNKNOWN; + if (heldBack && to !== Trust.RESTRICTED && to !== Trust.BLOCKED) return true; + if (to === Trust.BLOCKED || to === Trust.RESTRICTED) return false; + return to > from; +} diff --git a/sdk/src/engine/policyFields.ts b/sdk/src/engine/policyFields.ts new file mode 100644 index 0000000..3a2adfb --- /dev/null +++ b/sdk/src/engine/policyFields.ts @@ -0,0 +1,60 @@ +import { HOUR, type Policy } from '../types.js'; + +/** Field metadata for the policy editor, shared by every interface. */ +export type Unit = 'count' | 'hours' | 'bps' | 'bool'; +export type PolicyField = { + key: keyof Policy; + label: string; + hint: string; + unit: Unit; + max?: number; +}; + +/** Editors show hours; the policy stores milliseconds. */ +export const HOUR_MS = HOUR; +export const toHours = (ms: number) => ms / HOUR; +export const fromHours = (h: number) => Math.round(h * HOUR); + +export const POLICY_GROUPS: { title: string; sub: string; fields: PolicyField[] }[] = [ + { + title: 'Approvals', + sub: 'How many confirmations each tier needs. Guardians confirm critical payments in addition to approvers.', + fields: [ + { key: 'approvalsLow', label: 'Routine', hint: 'Payments under the routine maximum.', unit: 'count' }, + { key: 'approvalsHigh', label: 'High risk', hint: 'Larger payments, new recipients, elevated posture.', unit: 'count' }, + { key: 'approvalsCritical', label: 'Critical', hint: 'Very large or high-exposure payments.', unit: 'count' }, + { key: 'guardianRequiredCritical', label: 'Guardian required for critical', hint: 'An independent sign-off on the largest payments.', unit: 'bool' }, + { key: 'guardianThreshold', label: 'Guardian confirmations', hint: 'For critical payments, leaving Lockdown, and recovery.', unit: 'count' }, + { key: 'governanceThreshold', label: 'Owner approvals for governance', hint: 'Policy, limits, signers, trust and mode changes.', unit: 'count' }, + ], + }, + { + title: 'Delays', + sub: 'A delay gives guardians a veto window and gives the organization time to notice.', + fields: [ + { key: 'delayHigh', label: 'High-risk delay', hint: 'Between full approval and execution.', unit: 'hours' }, + { key: 'delayCritical', label: 'Critical delay', hint: 'Also the guardian veto window.', unit: 'hours' }, + { key: 'recipientActivationDelay', label: 'New-recipient activation', hint: 'A never-paid address cannot be paid sooner.', unit: 'hours' }, + { key: 'policyChangeDelay', label: 'Security-reducing change delay', hint: 'Any loosening waits this long and can be vetoed.', unit: 'hours' }, + { key: 'recoveryDelay', label: 'Recovery delay', hint: 'Owners can cancel a recovery during it.', unit: 'hours' }, + { key: 'proposalTtl', label: 'Proposal lifetime', hint: 'Must exceed the longest delay by at least an hour.', unit: 'hours' }, + ], + }, + { + title: 'Exposure', + sub: "Share of the asset's holdings a single payment may move before it is escalated or refused.", + fields: [ + { key: 'highExposureBps', label: 'Escalate to high risk at', hint: 'Percent of holdings.', unit: 'bps', max: 100 }, + { key: 'criticalExposureBps', label: 'Escalate to critical at', hint: '', unit: 'bps', max: 100 }, + { key: 'hardBlockExposureBps', label: 'Refuse above', hint: '0 disables the hard block.', unit: 'bps', max: 100 }, + ], + }, + { + title: 'Circuit breaker', + sub: 'Cumulative outflow per window, as a share of the balance when the window opened. The payment that would cross it is not made; the vault enters Lockdown.', + fields: [ + { key: 'envelopeBps', label: 'Loss envelope', hint: '0 disables the breaker.', unit: 'bps', max: 100 }, + { key: 'envelopeWindow', label: 'Envelope window', hint: 'At least one hour.', unit: 'hours' }, + ], + }, +]; diff --git a/sdk/src/engine/posture.ts b/sdk/src/engine/posture.ts new file mode 100644 index 0000000..99f848a --- /dev/null +++ b/sdk/src/engine/posture.ts @@ -0,0 +1,78 @@ +import { DAY, type AssetLimits, type Policy } from '../types.js'; +import { fmtDuration } from './format.js'; + +/** + * Plain-language posture checks. This reports confirmed controls and obvious weaknesses; it does + * not claim to measure absolute security, and it deliberately produces no score. + */ +export type PostureItem = { ok: 'ok' | 'warn' | 'bad'; text: string }; + +export type PostureInput = { + policy: Policy; + guardians: number; + assets: { symbol: string; limits: AssetLimits }[]; +}; + +export function postureItems({ policy: p, guardians: g, assets }: PostureInput): PostureItem[] { + const everyAssetCapped = assets.length > 0 && assets.every((a) => a.limits.dailyMax > 0n); + return [ + { + ok: g > 0 ? 'ok' : 'bad', + text: g > 0 + ? `${g} independent guardian${g === 1 ? '' : 's'} configured` + : 'No guardian: nobody independent can veto or freeze the vault', + }, + { + ok: p.guardianRequiredCritical ? 'ok' : 'warn', + text: p.guardianRequiredCritical + ? 'Critical payments need guardian confirmation' + : 'Critical payments do not need a guardian', + }, + { + ok: p.delayCritical >= DAY ? 'ok' : 'warn', + text: `Critical payments wait ${fmtDuration(p.delayCritical)}`, + }, + { + ok: p.recipientActivationDelay > 0 ? 'ok' : 'bad', + text: p.recipientActivationDelay > 0 + ? `New recipients wait ${fmtDuration(p.recipientActivationDelay)}` + : 'New recipients can be paid immediately', + }, + { + ok: everyAssetCapped ? 'ok' : 'warn', + text: everyAssetCapped + ? 'A 24-hour outflow cap on every approved asset' + : 'Some approved assets have no 24-hour cap', + }, + { + ok: p.envelopeBps > 0 ? 'ok' : 'warn', + text: p.envelopeBps > 0 + ? `Circuit breaker at ${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}` + : 'No loss envelope configured', + }, + { + ok: p.policyChangeDelay > 0 ? 'ok' : 'bad', + text: p.policyChangeDelay > 0 + ? `Weakening the policy waits ${fmtDuration(p.policyChangeDelay)} and can be vetoed` + : 'The policy can be weakened immediately', + }, + { + ok: p.recoveryDelay > 0 && g > 0 ? 'ok' : 'warn', + text: p.recoveryDelay > 0 && g > 0 + ? `Signer recovery available after ${fmtDuration(p.recoveryDelay)}` + : 'No usable recovery path', + }, + { + ok: p.approvalsLow >= 2 ? 'ok' : 'warn', + text: p.approvalsLow >= 2 + ? 'Routine payments need two approvals' + : 'Routine payments need a single approval', + }, + { + ok: p.hardBlockExposureBps > 0 ? 'ok' : 'warn', + text: p.hardBlockExposureBps > 0 + ? `No single payment may exceed ${p.hardBlockExposureBps / 100}% of an asset` + : 'No hard block: a single payment could take the whole balance if approved', + }, + ]; +} diff --git a/sdk/src/engine/risk.ts b/sdk/src/engine/risk.ts new file mode 100644 index 0000000..61b59f6 --- /dev/null +++ b/sdk/src/engine/risk.ts @@ -0,0 +1,108 @@ +import { BPS, Mode, Reason, Tier, Trust, type Policy } from '../types.js'; + +/** + * Mirror of `sui/sources/risk.move`. Used to preview a transfer against a policy that is not + * deployed yet, and to drive the simulator. + * + * For a live vault, prefer `previewTransfer` from `../vault`, which simulates the chain's own + * `preview_transfer` so the answer is the contract's and not this file's. These vectors are pinned + * against the Move tests in `sui/tests/engine_tests.move`. + */ +export type RiskInput = { + amount: bigint; + assetBalance: bigint; + lowMax: bigint; + highMax: bigint; + dailyMax: bigint; + daySpent: bigint; + trust: Trust; + inProbation: boolean; + mode: Mode; + highExposureBps: number; + criticalExposureBps: number; +}; + +export type RiskOutput = { tier: Tier; reasons: number; exposureBps: number }; + +export function exposureBps(amount: bigint, balance: bigint): number { + if (amount === 0n) return 0; + if (balance === 0n || amount >= balance) return Number(BPS); + return Number((amount * BPS) / balance); +} + +function bump(t: Tier): Tier { + return t === Tier.LOW ? Tier.HIGH : Tier.CRITICAL; +} + +function atLeast(t: Tier, floor: Tier): Tier { + return t >= floor ? t : floor; +} + +export function classify(i: RiskInput): RiskOutput { + let tier: Tier = Tier.LOW; + let reasons = 0; + + if (i.amount > i.highMax) { + tier = Tier.CRITICAL; + reasons |= Reason.AMOUNT_CRITICAL; + } else if (i.amount > i.lowMax) { + tier = Tier.HIGH; + reasons |= Reason.AMOUNT_HIGH; + } + + const exposure = exposureBps(i.amount, i.assetBalance); + if (i.criticalExposureBps !== 0 && exposure >= i.criticalExposureBps) { + tier = Tier.CRITICAL; + reasons |= Reason.EXPOSURE_CRITICAL; + } else if (i.highExposureBps !== 0 && exposure >= i.highExposureBps) { + tier = atLeast(tier, Tier.HIGH); + reasons |= Reason.EXPOSURE_HIGH; + } + + if (i.trust === Trust.RESTRICTED) { + tier = Tier.CRITICAL; + reasons |= Reason.RECIPIENT_RESTRICTED; + } else if (i.trust === Trust.UNKNOWN) { + tier = bump(tier); + reasons |= Reason.RECIPIENT_UNKNOWN | Reason.RECIPIENT_PROBATION; + } else if (i.trust === Trust.NEW && i.inProbation) { + tier = bump(tier); + reasons |= Reason.RECIPIENT_PROBATION; + } + + if (i.dailyMax !== 0n && (i.daySpent + i.amount) * 2n > i.dailyMax) { + tier = atLeast(tier, Tier.HIGH); + reasons |= Reason.VELOCITY_PRESSURE; + } + + if (i.mode === Mode.ELEVATED) { + tier = bump(tier); + reasons |= Reason.MODE_ELEVATED; + } + + return { tier, reasons, exposureBps: exposure }; +} + +export function requirements( + p: Policy, + tier: Tier, +): { approvals: number; guardians: number; delay: number } { + if (tier === Tier.LOW) return { approvals: p.approvalsLow, guardians: 0, delay: 0 }; + if (tier === Tier.HIGH) return { approvals: p.approvalsHigh, guardians: 0, delay: p.delayHigh }; + return { + approvals: p.approvalsCritical, + guardians: p.guardianRequiredCritical ? p.guardianThreshold : 0, + delay: p.delayCritical, + }; +} + +/** Elevated halves the caps, floored at one unit. No cap stays no cap. */ +export function effectiveCaps( + perTxMax: bigint, + dailyMax: bigint, + mode: Mode, +): { perTxMax: bigint; dailyMax: bigint } { + if (mode !== Mode.ELEVATED) return { perTxMax, dailyMax }; + const half = (x: bigint) => (x === 0n ? 0n : x / 2n === 0n ? 1n : x / 2n); + return { perTxMax: half(perTxMax), dailyMax: half(dailyMax) }; +} diff --git a/sdk/src/engine/simulator.ts b/sdk/src/engine/simulator.ts new file mode 100644 index 0000000..32dd96e --- /dev/null +++ b/sdk/src/engine/simulator.ts @@ -0,0 +1,266 @@ +import { Mode, TIER_LABELS, Tier, Trust, type AssetLimits, type Policy } from '../types.js'; +import { classify, effectiveCaps, requirements } from './risk.js'; +import { fmtDuration } from './format.js'; + +/** + * Runs a policy against the attacks that actually happen, before the policy is live. Every verdict + * is the deterministic risk engine plus the vault's own limit checks — nothing here is heuristic, + * and nothing here is a score. + */ +export type Verdict = 'blocked' | 'delayed' | 'escalated' | 'allowed' | 'impossible'; + +export type ScenarioResult = { + id: string; + title: string; + narrative: string; + verdict: Verdict; + detail: string[]; +}; + +export type SimContext = { + policy: Policy; + limits: AssetLimits; + balance: bigint; + decimals: number; + symbol: string; + approverCount: number; + guardianCount: number; +}; + +function fmt(v: bigint, ctx: SimContext): string { + const s = Number(v) / 10 ** ctx.decimals; + return `${s.toLocaleString('en-US', { maximumFractionDigits: 2 })} ${ctx.symbol}`; +} + +function single( + ctx: SimContext, + amount: bigint, + trust: Trust, + inProbation: boolean, + mode: Mode, + compromised: number, +): { verdict: Verdict; detail: string[] } { + const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, mode); + const detail: string[] = []; + if (mode === Mode.LOCKDOWN) + return { verdict: 'blocked', detail: ['The vault is in Lockdown: nothing outgoing executes.'] }; + if (trust === Trust.BLOCKED) return { verdict: 'blocked', detail: ['The recipient is blocked.'] }; + if (caps.perTxMax !== 0n && amount > caps.perTxMax) + return { + verdict: 'blocked', + detail: [ + `The per-transaction cap is ${fmt(caps.perTxMax, ctx)}, so the proposal is refused when it is opened.`, + ], + }; + + const r = classify({ + amount, + assetBalance: ctx.balance, + lowMax: ctx.limits.lowMax, + highMax: ctx.limits.highMax, + dailyMax: caps.dailyMax, + daySpent: 0n, + trust, + inProbation, + mode, + highExposureBps: ctx.policy.highExposureBps, + criticalExposureBps: ctx.policy.criticalExposureBps, + }); + + if (ctx.policy.hardBlockExposureBps !== 0 && r.exposureBps >= ctx.policy.hardBlockExposureBps) + return { + verdict: 'blocked', + detail: [ + `Exposure of ${(r.exposureBps / 100).toFixed(1)}% is at or above the hard block of ${ctx.policy.hardBlockExposureBps / 100}%, which no amount of approval can clear.`, + ], + }; + if (caps.dailyMax !== 0n && amount > caps.dailyMax) + return { + verdict: 'blocked', + detail: [`The daily cap is ${fmt(caps.dailyMax, ctx)}, so this cannot be opened today.`], + }; + + const envelope = + ctx.policy.envelopeBps === 0 ? 0n : (ctx.balance * BigInt(ctx.policy.envelopeBps)) / 10_000n; + if (envelope !== 0n && amount > envelope) + return { + verdict: 'blocked', + detail: [ + `The loss envelope is ${fmt(envelope, ctx)} per ${fmtDuration(ctx.policy.envelopeWindow)}. The breaker trips and the vault enters Lockdown instead of paying.`, + ], + }; + + const req = requirements(ctx.policy, r.tier); + detail.push( + `Risk tier: ${TIER_LABELS[r.tier]}, at ${(r.exposureBps / 100).toFixed(2)}% of holdings.`, + ); + detail.push( + `Needs ${req.approvals} approval${req.approvals === 1 ? '' : 's'}${ + req.guardians + ? ` and ${req.guardians} guardian confirmation${req.guardians === 1 ? '' : 's'}` + : '' + }${req.delay ? `, then waits ${fmtDuration(req.delay)}` : ', with no delay'}.`, + ); + + let delay = req.delay; + if (inProbation) { + delay = Math.max(delay, ctx.policy.recipientActivationDelay); + detail.push( + `The recipient's activation delay forces a wait of at least ${fmtDuration(ctx.policy.recipientActivationDelay)}.`, + ); + } + if (r.tier === Tier.CRITICAL || inProbation || mode !== Mode.NORMAL) + detail.push('Any guardian can veto it before it executes.'); + + if (req.guardians > ctx.guardianCount) + return { + verdict: 'impossible', + detail: [...detail, 'More guardian confirmations are required than there are guardians.'], + }; + if (compromised < req.approvals) { + detail.push( + `The attacker holds ${compromised} approver key${compromised === 1 ? '' : 's'}, fewer than required.`, + ); + return { verdict: 'blocked', detail }; + } + if (req.guardians > 0) { + detail.push('Guardian confirmation is an independent control the attacker does not hold.'); + return { verdict: 'blocked', detail }; + } + if (delay > 0) return { verdict: 'delayed', detail }; + if (r.tier > Tier.LOW) return { verdict: 'escalated', detail }; + return { verdict: 'allowed', detail }; +} + +export function runScenarios(ctx: SimContext): ScenarioResult[] { + const out: ScenarioResult[] = []; + const pct = (bps: number) => (ctx.balance * BigInt(bps)) / 10_000n; + const unit = 10n ** BigInt(ctx.decimals); + + { + const amount = 100_000n * unit; + const r = single(ctx, amount, Trust.UNKNOWN, true, Mode.NORMAL, 1); + out.push({ + id: 'single-signer-new-address', + title: 'One finance signer compromised', + narrative: `An attacker with a single approver key opens ${fmt(amount, ctx)} to an address the vault has never paid.`, + ...r, + }); + } + { + const amount = pct(4_000); + const r = single(ctx, amount, Trust.VERIFIED, false, Mode.NORMAL, 3); + out.push({ + id: 'three-signers-40pct', + title: 'Three signers compromised, 40% of the treasury', + narrative: `An attacker with three approver keys opens ${fmt(amount, ctx)} — 40% of holdings — to a recipient the vault has already verified.`, + ...r, + }); + } + { + const each = 9_900n * unit; + const total = each * 20n; + const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, Mode.NORMAL); + const envelope = ctx.policy.envelopeBps === 0 ? 0n : pct(ctx.policy.envelopeBps); + const detail: string[] = []; + let verdict: Verdict = 'allowed'; + const tierEach = classify({ + amount: each, + assetBalance: ctx.balance, + lowMax: ctx.limits.lowMax, + highMax: ctx.limits.highMax, + dailyMax: caps.dailyMax, + daySpent: 0n, + trust: Trust.VERIFIED, + inProbation: false, + mode: Mode.NORMAL, + highExposureBps: ctx.policy.highExposureBps, + criticalExposureBps: ctx.policy.criticalExposureBps, + }); + detail.push(`On its own each payment is ${TIER_LABELS[tierEach.tier]} tier.`); + if (caps.dailyMax !== 0n && total > caps.dailyMax) { + const n = Number(caps.dailyMax / each); + detail.push( + `The daily cap of ${fmt(caps.dailyMax, ctx)} stops execution after ${n} payment${n === 1 ? '' : 's'}, at ${fmt(each * BigInt(n), ctx)}.`, + ); + verdict = 'blocked'; + } + if (envelope !== 0n && total > envelope) { + const n = Number(envelope / each); + detail.push( + `The loss envelope of ${fmt(envelope, ctx)} trips the breaker after ${n} payment${n === 1 ? '' : 's'}, and the vault latches into Lockdown.`, + ); + verdict = 'blocked'; + } + if (caps.dailyMax !== 0n && each * 2n > caps.dailyMax / 2n) { + detail.push("Once half the day's allowance is gone, every further payment is scored high risk."); + if (verdict === 'allowed') verdict = 'escalated'; + } + if (verdict === 'allowed') + detail.push( + 'No cumulative control is configured, so the split drain would succeed. Set a daily cap or a loss envelope.', + ); + out.push({ + id: 'split-drain', + title: 'A drain split into twenty payments', + narrative: `Twenty payments of ${fmt(each, ctx)}, ${fmt(total, ctx)} in total, inside one day.`, + verdict, + detail, + }); + } + { + const detail = [ + `Lowering any threshold, delay or cap is a security-reducing change: it waits ${fmtDuration(ctx.policy.policyChangeDelay)} and any guardian can veto it.`, + `It needs ${ctx.policy.governanceThreshold} owner approval${ctx.policy.governanceThreshold === 1 ? '' : 's'}, and cannot be opened at all while the vault is in Lockdown.`, + 'Until it takes effect, payments already in flight keep the requirements pinned when they were opened.', + ]; + const verdict: Verdict = ctx.policy.policyChangeDelay > 0 ? 'delayed' : 'allowed'; + if (verdict === 'allowed') + detail.push( + 'The policy-change delay is zero, so a compromised owner quorum could weaken the vault at once. Set a delay.', + ); + out.push({ + id: 'policy-weaken', + title: 'An attacker weakens the policy first', + narrative: 'A compromised owner quorum lowers approvals and caps before trying to drain the vault.', + verdict, + detail, + }); + } + { + out.push({ + id: 'guardian-compromised', + title: 'A guardian key is compromised', + narrative: 'An attacker holding a guardian key tries to take funds.', + verdict: 'impossible', + detail: [ + 'A guardian holds no treasury role: it cannot open, approve or execute a payment, and the contract refuses to give a guardian any treasury role.', + `The worst it can do is freeze the vault, or open a recovery that waits ${fmtDuration(ctx.policy.recoveryDelay)} and that any owner can cancel.`, + ], + }); + } + { + const r = single(ctx, ctx.limits.lowMax, Trust.VERIFIED, false, Mode.ELEVATED, 2); + out.push({ + id: 'elevated-routine', + title: 'A routine payment during an incident', + narrative: `The vault is in Elevated mode and a ${fmt(ctx.limits.lowMax, ctx)} routine payment is opened.`, + ...r, + }); + } + { + const detail = [ + 'An agent holds the proposer role only. It can open a payment and nothing else.', + `Whatever it opens still needs ${ctx.policy.approvalsLow} approval${ctx.policy.approvalsLow === 1 ? '' : 's'} from a human approver for a routine amount, and more above it.`, + 'A compromised agent is a queue full of proposals nobody approves, not a withdrawal.', + ]; + out.push({ + id: 'agent-compromised', + title: 'An automated agent is compromised', + narrative: 'An attacker takes over the key an automation uses to request payments.', + verdict: 'blocked', + detail, + }); + } + return out; +} diff --git a/sdk/src/engine/templates.ts b/sdk/src/engine/templates.ts new file mode 100644 index 0000000..8fb6fa3 --- /dev/null +++ b/sdk/src/engine/templates.ts @@ -0,0 +1,255 @@ +import { DAY, HOUR, type AssetLimits, type Policy } from '../types.js'; + +/** + * Starting policies, one per kind of organization. Nobody designs seventeen fields from first + * principles; they pick the closest fit and tighten from there, which is why every template is a + * complete and valid policy rather than a partial preset. + * + * Amounts assume a 6-decimal stablecoin (USDC on Sui) and 9-decimal SUI. + */ +export const USDC = 1_000_000n; +export const SUI = 1_000_000_000n; + +export type TemplateId = + | 'startup' + | 'team' + | 'protocol' + | 'fund' + | 'payments' + | 'nonprofit' + | 'familyOffice'; + +export type Template = { + id: TemplateId; + name: string; + tagline: string; + /** Who this is for, in the words that organization would use. */ + audience: string; + minSigners: number; + minGuardians: number; + policy: Policy; + stable: AssetLimits; + native: AssetLimits; +}; + +const startupPolicy: Policy = { + approvalsLow: 1, + approvalsHigh: 2, + approvalsCritical: 2, + governanceThreshold: 2, + guardianThreshold: 1, + guardianRequiredCritical: true, + delayHigh: 6 * HOUR, + delayCritical: 24 * HOUR, + recipientActivationDelay: 24 * HOUR, + policyChangeDelay: 24 * HOUR, + recoveryDelay: 48 * HOUR, + proposalTtl: 7 * DAY, + highExposureBps: 500, + criticalExposureBps: 2_000, + hardBlockExposureBps: 5_000, + envelopeBps: 1_000, + envelopeWindow: 24 * HOUR, +}; + +const startupStable: AssetLimits = { + approved: true, + lowMax: 5_000n * USDC, + highMax: 25_000n * USDC, + perTxMax: 100_000n * USDC, + dailyMax: 100_000n * USDC, +}; + +const startupNative: AssetLimits = { + approved: true, + lowMax: 100n * SUI, + highMax: 1_000n * SUI, + perTxMax: 0n, + dailyMax: 5_000n * SUI, +}; + +export const TEMPLATES: Template[] = [ + { + id: 'startup', + name: 'Startup', + tagline: 'Simple thresholds, a new-recipient delay, one guardian.', + audience: 'A small team paying contractors and vendors out of a seed round.', + minSigners: 2, + minGuardians: 1, + policy: startupPolicy, + stable: startupStable, + native: startupNative, + }, + { + id: 'team', + name: 'Operating team', + tagline: 'Tiered approvals, velocity limits, supplier trust.', + audience: 'A company with a finance function and recurring suppliers.', + minSigners: 3, + minGuardians: 1, + policy: { ...startupPolicy, approvalsCritical: 3, delayHigh: 4 * HOUR, envelopeBps: 500 }, + stable: { + ...startupStable, + lowMax: 10_000n * USDC, + highMax: 50_000n * USDC, + perTxMax: 150_000n * USDC, + dailyMax: 150_000n * USDC, + }, + native: startupNative, + }, + { + id: 'protocol', + name: 'Protocol / DAO', + tagline: 'Higher quorum, long timelocks, two guardians.', + audience: 'A protocol treasury answerable to tokenholders, where every move is public.', + minSigners: 4, + minGuardians: 2, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 3, + approvalsCritical: 4, + governanceThreshold: 3, + guardianThreshold: 2, + delayHigh: 24 * HOUR, + delayCritical: 72 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 7 * DAY, + proposalTtl: 14 * DAY, + highExposureBps: 200, + criticalExposureBps: 1_000, + hardBlockExposureBps: 2_500, + envelopeBps: 500, + }, + stable: { + ...startupStable, + lowMax: 25_000n * USDC, + highMax: 100_000n * USDC, + perTxMax: 500_000n * USDC, + dailyMax: 500_000n * USDC, + }, + native: { ...startupNative, lowMax: 1_000n * SUI, highMax: 10_000n * SUI, dailyMax: 50_000n * SUI }, + }, + { + id: 'fund', + name: 'Fund', + tagline: 'Tight exposure limits, strong guardians, long critical delays.', + audience: 'A fund managing outside capital, where a single bad transfer is existential.', + minSigners: 3, + minGuardians: 2, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 3, + approvalsCritical: 3, + guardianThreshold: 2, + delayHigh: 12 * HOUR, + delayCritical: 72 * HOUR, + recipientActivationDelay: 48 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 7 * DAY, + proposalTtl: 14 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 2_000, + envelopeBps: 300, + }, + stable: { + ...startupStable, + lowMax: 50_000n * USDC, + highMax: 250_000n * USDC, + perTxMax: 1_000_000n * USDC, + dailyMax: 1_000_000n * USDC, + }, + native: { ...startupNative, lowMax: 1_000n * SUI, highMax: 10_000n * SUI, dailyMax: 50_000n * SUI }, + }, + { + id: 'payments', + name: 'Payments company', + tagline: 'High routine throughput, a tight envelope, an agent proposer.', + audience: + 'A business paying many small amounts automatically, where volume is normal and a spike is not.', + minSigners: 3, + minGuardians: 1, + policy: { + ...startupPolicy, + approvalsLow: 1, + approvalsHigh: 2, + approvalsCritical: 3, + delayHigh: 1 * HOUR, + delayCritical: 12 * HOUR, + recipientActivationDelay: 6 * HOUR, + policyChangeDelay: 48 * HOUR, + proposalTtl: 3 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 1_500, + // The envelope, not the per-payment caps, is what defends a high-volume treasury. + envelopeBps: 200, + envelopeWindow: 6 * HOUR, + }, + stable: { + ...startupStable, + lowMax: 2_500n * USDC, + highMax: 25_000n * USDC, + perTxMax: 25_000n * USDC, + dailyMax: 500_000n * USDC, + }, + native: startupNative, + }, + { + id: 'nonprofit', + name: 'Nonprofit', + tagline: 'Restricted recipients, separation of duties, a full audit trail.', + audience: 'An organization spending donated money that has to account for all of it.', + minSigners: 3, + minGuardians: 1, + policy: { + ...startupPolicy, + approvalsLow: 2, + approvalsHigh: 2, + approvalsCritical: 3, + recipientActivationDelay: 72 * HOUR, + delayHigh: 12 * HOUR, + delayCritical: 48 * HOUR, + envelopeBps: 500, + }, + stable: startupStable, + native: startupNative, + }, + { + id: 'familyOffice', + name: 'Family office', + tagline: 'Conservative limits, a cold guardian, a long recovery path.', + audience: 'Long-term holdings that move rarely, where availability matters less than safety.', + minSigners: 2, + minGuardians: 1, + policy: { + ...startupPolicy, + delayHigh: 24 * HOUR, + delayCritical: 72 * HOUR, + recipientActivationDelay: 72 * HOUR, + policyChangeDelay: 72 * HOUR, + recoveryDelay: 14 * DAY, + proposalTtl: 21 * DAY, + highExposureBps: 100, + criticalExposureBps: 500, + hardBlockExposureBps: 1_500, + envelopeBps: 200, + }, + stable: { + ...startupStable, + lowMax: 10_000n * USDC, + highMax: 50_000n * USDC, + perTxMax: 250_000n * USDC, + dailyMax: 250_000n * USDC, + }, + native: startupNative, + }, +]; + +export function templateById(id: TemplateId): Template { + const t = TEMPLATES.find((x) => x.id === id); + if (!t) throw new Error(`unknown template ${id}`); + return t; +} diff --git a/sdk/src/errors.ts b/sdk/src/errors.ts new file mode 100644 index 0000000..752b65a --- /dev/null +++ b/sdk/src/errors.ts @@ -0,0 +1,91 @@ +/** + * Move abort codes, mapped to the sentence a person should read. The numbers are the constants in + * `sui/sources/policy.move` and `sui/sources/vault.move`; a change there is a change here. + * + * A Sui abort arrives as a `MoveAbort` in the execution status, carrying the module and the code, + * so an interface can be specific about why a transaction was refused rather than saying "failed". + */ +export const POLICY_ERRORS: Record = { + 1: 'Routine transfers must need at least one approval.', + 2: 'High-risk transfers cannot need fewer approvals than routine ones.', + 3: 'Critical transfers cannot need fewer approvals than high-risk ones.', + 4: 'Governance must need at least one owner.', + 5: 'Guardian confirmation is required but no guardian confirmations were set.', + 6: 'The critical delay cannot be shorter than the high-risk delay.', + 7: 'The high exposure threshold cannot exceed the critical one.', + 8: 'Exposure thresholds cannot exceed 100%.', + 9: 'The hard block cannot sit below the critical exposure threshold.', + 10: 'The hard block cannot exceed 100%.', + 11: 'The loss envelope cannot exceed 100%.', + 12: 'The envelope window must be at least one hour.', + 13: 'Proposal lifetime must exceed the longest delay by at least an hour.', + 20: 'The routine maximum cannot exceed the high-tier maximum.', + 21: 'The per-transaction cap cannot exceed the daily cap.', + 30: 'A vault needs at least one owner.', + 31: 'A vault needs at least one executor.', + 32: 'The governance threshold exceeds the number of owners.', + 33: 'Critical approvals exceed the number of approvers.', + 34: 'The guardian threshold exceeds the number of guardians.', +}; + +export const VAULT_ERRORS: Record = { + 100: 'That address is not a member of this vault.', + 101: 'Only an owner can do that.', + 102: 'Only an approver can approve a payment.', + 103: 'Only an executor can execute.', + 104: 'Only a guardian can do that.', + 105: 'That role cannot open proposals.', + 106: 'Those roles are not a valid combination.', + 107: 'The vault is in Lockdown.', + 108: 'That asset is not approved for this vault.', + 109: 'No such proposal.', + 110: 'That proposal is no longer pending.', + 111: 'That proposal is of a different kind.', + 112: 'That proposal is for a different asset.', + 113: 'The waiting period has not elapsed yet.', + 114: 'That proposal has expired.', + 115: 'That proposal has not expired yet.', + 116: 'Not enough approvals from current signers.', + 117: 'Not enough guardian confirmations.', + 118: 'The recipient is blocked.', + 119: 'The recipient is still in its activation delay.', + 120: 'Above the per-transaction cap for this asset.', + 121: "Above today's remaining allowance for this asset.", + 122: 'Above the hard block: no amount of approval can clear this.', + 123: 'The vault does not hold enough of that asset.', + 124: 'The amount must be greater than zero.', + 125: 'That proposal is not one a guardian can veto.', + 126: 'That address is already registered.', + 127: 'That recipient is not registered.', + 128: 'That is not a valid trust level.', + 129: 'That is not a valid security mode.', + 130: 'That is not a relaxation of the current mode.', + 131: 'Only the proposer or an owner can cancel.', + 132: 'A vault cannot be left without an owner.', + 133: 'A guardian cannot hold a treasury role.', + 134: 'That asset was already configured.', + 135: 'The member list and the role list are different lengths.', + 136: 'A guardian cannot nominate themselves as a replacement signer.', + 137: 'No such member.', + 138: 'That signer has already voted on this proposal.', + 139: 'Those roles are already set.', +}; + +export function describeAbort(module: string | undefined, code: number | bigint): string { + const n = Number(code); + if (module === 'policy' && POLICY_ERRORS[n]) return POLICY_ERRORS[n]; + if (module === 'vault' && VAULT_ERRORS[n]) return VAULT_ERRORS[n]; + return POLICY_ERRORS[n] ?? VAULT_ERRORS[n] ?? `The vault refused the transaction (code ${n}).`; +} + +/** Pull a readable reason out of a failed execution result. */ +export function describeFailure(error: unknown): string { + const text = error instanceof Error ? error.message : String(error); + const abort = /MoveAbort.*?(\w+)::(\w+).*?(\d+)/.exec(text); + if (abort) return describeAbort(abort[2], Number(abort[3])); + const bare = /MoveAbort[^0-9]*(\d+)/.exec(text); + if (bare) return describeAbort(undefined, Number(bare[1])); + if (/InsufficientGas|GasBalanceTooLow/.test(text)) return 'Not enough SUI to pay for gas.'; + if (/ObjectNotFound/.test(text)) return 'That object no longer exists on this network.'; + return text; +} diff --git a/sdk/src/events.ts b/sdk/src/events.ts new file mode 100644 index 0000000..00e65a5 --- /dev/null +++ b/sdk/src/events.ts @@ -0,0 +1,432 @@ +import type { ClientWithCoreApi } from '@mysten/sui/client'; +import { bcs } from '@mysten/sui/bcs'; +import { AssetLimitsBcs, PolicyBcs } from './bcs.js'; +import { moveType } from './network.js'; +import type { Kind, Mode, Status, Tier, Trust } from './types.js'; + +/** + * The vault's events, which are the whole history. Every state change emits one, so an indexer or + * a notification service never has to diff object versions to know what happened. + * + * Parsed from `event.bcs`, not `event.json`: the SDK documents the JSON shape as varying between + * transports, and an audit trail cannot depend on which endpoint read it. + */ + +const UID = bcs.Address; +const OptionTypeName = bcs.option(bcs.struct('TypeName', { name: bcs.string() })); + +function typeName(v: { name: string } | null): string | null { + if (!v) return null; + return v.name.startsWith('0x') ? v.name : `0x${v.name}`; +} + +export const EVENT_NAMES = [ + 'VaultCreated', + 'Deposited', + 'ProposalOpened', + 'Approved', + 'Confirmed', + 'Settled', + 'Executed', + 'BreakerTripped', + 'ModeChanged', + 'PolicyChanged', + 'LimitsChanged', + 'MemberChanged', + 'RecipientRegistered', + 'RecipientTrustChanged', + 'Recovered', +] as const; +export type EventName = (typeof EVENT_NAMES)[number]; + +const VaultCreatedBcs = bcs.struct('VaultCreated', { + vault: UID, + name: bcs.string(), + creator: bcs.Address, + owner_count: bcs.u64(), + guardian_count: bcs.u64(), + at: bcs.u64(), +}); + +const DepositedBcs = bcs.struct('Deposited', { + vault: UID, + asset: bcs.struct('TypeName', { name: bcs.string() }), + amount: bcs.u64(), + balance: bcs.u64(), + from: bcs.Address, + at: bcs.u64(), +}); + +const ProposalOpenedBcs = bcs.struct('ProposalOpened', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + proposer: bcs.Address, + asset: OptionTypeName, + amount: bcs.u64(), + recipient: bcs.Address, + tier: bcs.u8(), + reasons: bcs.u16(), + exposure_bps: bcs.u64(), + req_approvals: bcs.u8(), + req_guardians: bcs.u8(), + executable_at: bcs.u64(), + expires_at: bcs.u64(), + reduction_mask: bcs.u32(), + memo: bcs.string(), + at: bcs.u64(), +}); + +const ApprovedBcs = bcs.struct('Approved', { + vault: UID, + proposal: bcs.u64(), + approver: bcs.Address, + approvals: bcs.u64(), + req_approvals: bcs.u8(), + at: bcs.u64(), +}); + +const ConfirmedBcs = bcs.struct('Confirmed', { + vault: UID, + proposal: bcs.u64(), + guardian: bcs.Address, + confirmations: bcs.u64(), + req_guardians: bcs.u8(), + at: bcs.u64(), +}); + +const SettledBcs = bcs.struct('Settled', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + status: bcs.u8(), + actor: bcs.Address, + at: bcs.u64(), +}); + +const ExecutedBcs = bcs.struct('Executed', { + vault: UID, + proposal: bcs.u64(), + kind: bcs.u8(), + asset: OptionTypeName, + amount: bcs.u64(), + recipient: bcs.Address, + executor: bcs.Address, + tier: bcs.u8(), + balance_after: bcs.u64(), + day_spent: bcs.u64(), + at: bcs.u64(), +}); + +const BreakerTrippedBcs = bcs.struct('BreakerTripped', { + vault: UID, + proposal: bcs.u64(), + asset: bcs.struct('TypeName', { name: bcs.string() }), + amount: bcs.u64(), + envelope_spent: bcs.u64(), + envelope_limit: bcs.u64(), + envelope_basis: bcs.u64(), + at: bcs.u64(), +}); + +const ModeChangedBcs = bcs.struct('ModeChanged', { + vault: UID, + from: bcs.u8(), + to: bcs.u8(), + actor: bcs.Address, + reasons: bcs.u16(), + at: bcs.u64(), +}); + +const PolicyChangedBcs = bcs.struct('PolicyChanged', { + vault: UID, + proposal: bcs.u64(), + version: bcs.u64(), + reduction_mask: bcs.u32(), + at: bcs.u64(), +}); + +const LimitsChangedBcs = bcs.struct('LimitsChanged', { + vault: UID, + proposal: bcs.u64(), + asset: bcs.struct('TypeName', { name: bcs.string() }), + approved: bcs.bool(), + low_max: bcs.u64(), + high_max: bcs.u64(), + per_tx_max: bcs.u64(), + daily_max: bcs.u64(), + reduction_mask: bcs.u32(), + at: bcs.u64(), +}); + +const MemberChangedBcs = bcs.struct('MemberChanged', { + vault: UID, + proposal: bcs.u64(), + member: bcs.Address, + roles_before: bcs.u8(), + roles_after: bcs.u8(), + at: bcs.u64(), +}); + +const RecipientRegisteredBcs = bcs.struct('RecipientRegistered', { + vault: UID, + recipient: bcs.Address, + trust: bcs.u8(), + activates_at: bcs.u64(), + label: bcs.string(), + actor: bcs.Address, + at: bcs.u64(), +}); + +const RecipientTrustChangedBcs = bcs.struct('RecipientTrustChanged', { + vault: UID, + proposal: bcs.u64(), + recipient: bcs.Address, + from: bcs.u8(), + to: bcs.u8(), + actor: bcs.Address, + at: bcs.u64(), +}); + +const RecoveredBcs = bcs.struct('Recovered', { + vault: UID, + proposal: bcs.u64(), + lost: bcs.Address, + replacement: bcs.Address, + roles: bcs.u8(), + at: bcs.u64(), +}); + +export type SkurEvent = + | { name: 'VaultCreated'; vault: string; vaultName: string; creator: string; ownerCount: number; guardianCount: number; at: number } + | { name: 'Deposited'; vault: string; asset: string; amount: bigint; balance: bigint; from: string; at: number } + | { + name: 'ProposalOpened'; + vault: string; + proposal: bigint; + kind: Kind; + proposer: string; + asset: string | null; + amount: bigint; + recipient: string; + tier: Tier; + reasons: number; + exposureBps: number; + reqApprovals: number; + reqGuardians: number; + executableAt: number; + expiresAt: number; + reductionMask: number; + memo: string; + at: number; + } + | { name: 'Approved'; vault: string; proposal: bigint; approver: string; approvals: number; reqApprovals: number; at: number } + | { name: 'Confirmed'; vault: string; proposal: bigint; guardian: string; confirmations: number; reqGuardians: number; at: number } + | { name: 'Settled'; vault: string; proposal: bigint; kind: Kind; status: Status; actor: string; at: number } + | { + name: 'Executed'; + vault: string; + proposal: bigint; + kind: Kind; + asset: string | null; + amount: bigint; + recipient: string; + executor: string; + tier: Tier; + balanceAfter: bigint; + daySpent: bigint; + at: number; + } + | { + name: 'BreakerTripped'; + vault: string; + proposal: bigint; + asset: string; + amount: bigint; + envelopeSpent: bigint; + envelopeLimit: bigint; + envelopeBasis: bigint; + at: number; + } + | { name: 'ModeChanged'; vault: string; from: Mode; to: Mode; actor: string; reasons: number; at: number } + | { name: 'PolicyChanged'; vault: string; proposal: bigint; version: bigint; reductionMask: number; at: number } + | { + name: 'LimitsChanged'; + vault: string; + proposal: bigint; + asset: string; + approved: boolean; + lowMax: bigint; + highMax: bigint; + perTxMax: bigint; + dailyMax: bigint; + reductionMask: number; + at: number; + } + | { name: 'MemberChanged'; vault: string; proposal: bigint; member: string; rolesBefore: number; rolesAfter: number; at: number } + | { name: 'RecipientRegistered'; vault: string; recipient: string; trust: Trust; activatesAt: number; label: string; actor: string; at: number } + | { name: 'RecipientTrustChanged'; vault: string; proposal: bigint; recipient: string; from: Trust; to: Trust; actor: string; at: number } + | { name: 'Recovered'; vault: string; proposal: bigint; lost: string; replacement: string; roles: number; at: number }; + +/** Ledger position, so an indexer can resume exactly where it stopped. */ +export type EventPosition = { + transactionDigest: string; + eventIndex: number; + checkpoint?: string; + timestampMs?: number; +}; + +export type DecodedEvent = { event: SkurEvent; position: EventPosition }; + +const n = (v: string | number | bigint) => Number(v); +const b = (v: string | number | bigint) => BigInt(v); + +/** Decode one Move event into a tagged union, or null if it is not one of ours. */ +export function decodeEvent(eventType: string, bytes: Uint8Array): SkurEvent | null { + const name = eventType.split('::').pop() as EventName | undefined; + switch (name) { + case 'VaultCreated': { + const e = VaultCreatedBcs.parse(bytes); + return { name, vault: e.vault, vaultName: e.name, creator: e.creator, ownerCount: n(e.owner_count), guardianCount: n(e.guardian_count), at: n(e.at) }; + } + case 'Deposited': { + const e = DepositedBcs.parse(bytes); + return { name, vault: e.vault, asset: typeName(e.asset)!, amount: b(e.amount), balance: b(e.balance), from: e.from, at: n(e.at) }; + } + case 'ProposalOpened': { + const e = ProposalOpenedBcs.parse(bytes); + return { + name, + vault: e.vault, + proposal: b(e.proposal), + kind: n(e.kind) as Kind, + proposer: e.proposer, + asset: typeName(e.asset), + amount: b(e.amount), + recipient: e.recipient, + tier: n(e.tier) as Tier, + reasons: n(e.reasons), + exposureBps: n(e.exposure_bps), + reqApprovals: n(e.req_approvals), + reqGuardians: n(e.req_guardians), + executableAt: n(e.executable_at), + expiresAt: n(e.expires_at), + reductionMask: n(e.reduction_mask), + memo: e.memo, + at: n(e.at), + }; + } + case 'Approved': { + const e = ApprovedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), approver: e.approver, approvals: n(e.approvals), reqApprovals: n(e.req_approvals), at: n(e.at) }; + } + case 'Confirmed': { + const e = ConfirmedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), guardian: e.guardian, confirmations: n(e.confirmations), reqGuardians: n(e.req_guardians), at: n(e.at) }; + } + case 'Settled': { + const e = SettledBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), kind: n(e.kind) as Kind, status: n(e.status) as Status, actor: e.actor, at: n(e.at) }; + } + case 'Executed': { + const e = ExecutedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), kind: n(e.kind) as Kind, asset: typeName(e.asset), amount: b(e.amount), recipient: e.recipient, executor: e.executor, tier: n(e.tier) as Tier, balanceAfter: b(e.balance_after), daySpent: b(e.day_spent), at: n(e.at) }; + } + case 'BreakerTripped': { + const e = BreakerTrippedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), asset: typeName(e.asset)!, amount: b(e.amount), envelopeSpent: b(e.envelope_spent), envelopeLimit: b(e.envelope_limit), envelopeBasis: b(e.envelope_basis), at: n(e.at) }; + } + case 'ModeChanged': { + const e = ModeChangedBcs.parse(bytes); + return { name, vault: e.vault, from: n(e.from) as Mode, to: n(e.to) as Mode, actor: e.actor, reasons: n(e.reasons), at: n(e.at) }; + } + case 'PolicyChanged': { + const e = PolicyChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), version: b(e.version), reductionMask: n(e.reduction_mask), at: n(e.at) }; + } + case 'LimitsChanged': { + const e = LimitsChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), asset: typeName(e.asset)!, approved: e.approved, lowMax: b(e.low_max), highMax: b(e.high_max), perTxMax: b(e.per_tx_max), dailyMax: b(e.daily_max), reductionMask: n(e.reduction_mask), at: n(e.at) }; + } + case 'MemberChanged': { + const e = MemberChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), member: e.member, rolesBefore: n(e.roles_before), rolesAfter: n(e.roles_after), at: n(e.at) }; + } + case 'RecipientRegistered': { + const e = RecipientRegisteredBcs.parse(bytes); + return { name, vault: e.vault, recipient: e.recipient, trust: n(e.trust) as Trust, activatesAt: n(e.activates_at), label: e.label, actor: e.actor, at: n(e.at) }; + } + case 'RecipientTrustChanged': { + const e = RecipientTrustChangedBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), recipient: e.recipient, from: n(e.from) as Trust, to: n(e.to) as Trust, actor: e.actor, at: n(e.at) }; + } + case 'Recovered': { + const e = RecoveredBcs.parse(bytes); + return { name, vault: e.vault, proposal: b(e.proposal), lost: e.lost, replacement: e.replacement, roles: n(e.roles), at: n(e.at) }; + } + default: + return null; + } +} + +/** + * Page through the package's events. The filter is `emitModule`, which is one predicate and so + * works on every transport; events for other vaults are dropped client-side when `vaultId` is + * given, because a module-wide filter is the finest the portable API offers. + */ +export async function listVaultEvents( + client: ClientWithCoreApi, + input: { + packageId: string; + vaultId?: string; + limit?: number; + /** Walk forwards from here. Use for indexing and for polling what is new. */ + after?: string | null; + /** Walk backwards from here. Use for an interface showing newest first. */ + before?: string | null; + order?: 'ascending' | 'descending'; + }, +): Promise<{ + events: DecodedEvent[]; + startCursor: string | null; + endCursor: string | null; + hasNextPage: boolean; +}> { + const page = await client.core.listEvents({ + filter: { emitModule: `${input.packageId}::vault` }, + limit: input.limit ?? 50, + ...(input.after != null ? { after: input.after } : {}), + ...(input.before != null ? { before: input.before } : {}), + ...(input.after == null && input.before == null + ? { order: input.order ?? 'descending' } + : {}), + }); + const events: DecodedEvent[] = []; + for (const e of page.events) { + const decoded = decodeEvent(e.eventType, e.bcs); + if (!decoded) continue; + if (input.vaultId && decoded.vault !== input.vaultId) continue; + events.push({ + event: decoded, + position: { + transactionDigest: e.transactionDigest, + eventIndex: e.eventIndex, + checkpoint: e.checkpoint ?? undefined, + timestampMs: decoded.at, + }, + }); + } + return { + events, + startCursor: page.startCursor, + endCursor: page.endCursor, + hasNextPage: page.hasNextPage, + }; +} + +/** The Move type of one of our events, for a precise `eventType` filter. */ +export function eventType(packageId: string, name: EventName): string { + return moveType(packageId, 'vault', name); +} + +export { PolicyBcs, AssetLimitsBcs }; diff --git a/sdk/src/index.ts b/sdk/src/index.ts new file mode 100644 index 0000000..0afe8be --- /dev/null +++ b/sdk/src/index.ts @@ -0,0 +1,14 @@ +/** + * The Skur SDK: everything an interface, a backend or a script needs to read and drive a vault on + * Sui. + * + * Transport is gRPC or GraphQL. JSON-RPC is not used anywhere, directly or transitively. + */ +export * from './network.js'; +export * from './types.js'; +export * from './errors.js'; +export * from './events.js'; +export * from './vault.js'; +export * as tx from './tx.js'; +export * from './engine/index.js'; +export { bcs } from '@mysten/sui/bcs'; diff --git a/sdk/src/network.ts b/sdk/src/network.ts new file mode 100644 index 0000000..78095ee --- /dev/null +++ b/sdk/src/network.ts @@ -0,0 +1,71 @@ +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { SuiGraphQLClient } from '@mysten/sui/graphql'; +import type { ClientWithCoreApi } from '@mysten/sui/client'; + +/** + * Transport policy for this project: gRPC first, GraphQL where a query needs shapes gRPC's + * unified methods do not carry. + * + * JSON-RPC is deliberately absent. It was switched off on Sui Foundation mainnet full nodes in + * the week of 27 July 2026 and is scheduled for full removal, code included, in mid-October 2026. + * Nothing here may depend on it, including transitively: `@mysten/dapp-kit` 1.x is JSON-RPC only + * and is why the frontend uses `@mysten/dapp-kit-react` 2.x instead. + */ +export type Network = 'mainnet' | 'testnet' | 'devnet' | 'localnet'; + +export const GRPC_ENDPOINTS: Record = { + mainnet: 'https://fullnode.mainnet.sui.io:443', + testnet: 'https://fullnode.testnet.sui.io:443', + devnet: 'https://fullnode.devnet.sui.io:443', + localnet: 'http://127.0.0.1:9000', +}; + +export const GRAPHQL_ENDPOINTS: Record = { + mainnet: 'https://sui-mainnet.mystenlabs.com/graphql', + testnet: 'https://sui-testnet.mystenlabs.com/graphql', + devnet: 'https://sui-devnet.mystenlabs.com/graphql', + localnet: 'http://127.0.0.1:9125/graphql', +}; + +/** The shared `Clock` every time-dependent entry function reads. */ +export const CLOCK_ID = '0x6'; + +export function grpcClient(network: Network, baseUrl = GRPC_ENDPOINTS[network]) { + return new SuiGrpcClient({ network, baseUrl }); +} + +export function graphqlClient(network: Network, url = GRAPHQL_ENDPOINTS[network]) { + return new SuiGraphQLClient({ network, url }); +} + +/** + * Where the package and its vaults live. One object per environment, written by the deploy + * script, so nothing in the app hardcodes an address. + */ +export type Deployment = { + network: Network; + /** The published `skur` package. */ + packageId: string; + /** Vaults the deploy script created, for demos and for the explorer links in the docs. */ + vaults: { id: string; name: string }[]; + publishedAtDigest?: string; + publishedAtCheckpoint?: string; +}; + +export type SkurConfig = { + deployment: Deployment; + client: ClientWithCoreApi; +}; + +/** Fully qualified Move type for a struct in the deployed package. */ +export function moveType(packageId: string, module: string, name: string) { + return `${packageId}::${module}::${name}`; +} + +export function moveTarget( + packageId: string, + module: string, + fn: string, +): `${string}::${string}::${string}` { + return `${packageId}::${module}::${fn}`; +} diff --git a/sdk/src/tx.ts b/sdk/src/tx.ts new file mode 100644 index 0000000..32372db --- /dev/null +++ b/sdk/src/tx.ts @@ -0,0 +1,382 @@ +import { Transaction, type TransactionObjectArgument } from '@mysten/sui/transactions'; +import { SUI_TYPE_ARG } from '@mysten/sui/utils'; +import { CLOCK_ID, moveTarget } from './network.js'; +import type { AssetLimits, Mode, Policy, Trust } from './types.js'; + +/** + * Programmable transaction blocks for every vault action. + * + * Two things here are worth knowing. First, a policy is built on chain by calling + * `policy::new(...)` inside the same block, so the seventeen fields are validated by the module + * that owns them rather than packed into bytes by this file. Second, creating a vault is one + * block: `begin` hands back a value with no abilities, so the same transaction has to configure + * the assets and call `finish`, and there is no moment when a half-configured vault exists. + */ + +export type Builder = { tx: Transaction; packageId: string }; + +function target(pkg: string, module: string, fn: string) { + return moveTarget(pkg, module, fn); +} + +/** Build the `Policy` struct inside the block. */ +export function policyArg(b: Builder, p: Policy): TransactionObjectArgument { + const { tx, packageId } = b; + return tx.moveCall({ + target: target(packageId, 'policy', 'new'), + arguments: [ + tx.pure.u8(p.approvalsLow), + tx.pure.u8(p.approvalsHigh), + tx.pure.u8(p.approvalsCritical), + tx.pure.u8(p.governanceThreshold), + tx.pure.u8(p.guardianThreshold), + tx.pure.bool(p.guardianRequiredCritical), + tx.pure.u64(p.delayHigh), + tx.pure.u64(p.delayCritical), + tx.pure.u64(p.recipientActivationDelay), + tx.pure.u64(p.policyChangeDelay), + tx.pure.u64(p.recoveryDelay), + tx.pure.u64(p.proposalTtl), + tx.pure.u64(p.highExposureBps), + tx.pure.u64(p.criticalExposureBps), + tx.pure.u64(p.hardBlockExposureBps), + tx.pure.u64(p.envelopeBps), + tx.pure.u64(p.envelopeWindow), + ], + }); +} + +export type MemberSeed = { address: string; roles: number }; +export type AssetSeed = { coinType: string; limits: AssetLimits }; +export type RecipientSeed = { address: string; label: string }; + +/** `begin` → `setup_asset`* → `setup_recipient`* → `finish`, in one block. */ +export function createVault( + packageId: string, + input: { + name: string; + policy: Policy; + members: MemberSeed[]; + assets: AssetSeed[]; + recipients?: RecipientSeed[]; + }, +): Transaction { + const tx = new Transaction(); + const b = { tx, packageId }; + const setup = tx.moveCall({ + target: target(packageId, 'vault', 'begin'), + arguments: [ + tx.pure.string(input.name), + policyArg(b, input.policy), + tx.pure.vector('address', input.members.map((m) => m.address)), + tx.pure.vector('u8', input.members.map((m) => m.roles)), + tx.object(CLOCK_ID), + ], + }); + + for (const a of input.assets) { + tx.moveCall({ + target: target(packageId, 'vault', 'setup_asset'), + typeArguments: [a.coinType], + arguments: [ + setup, + tx.pure.bool(a.limits.approved), + tx.pure.u64(a.limits.lowMax), + tx.pure.u64(a.limits.highMax), + tx.pure.u64(a.limits.perTxMax), + tx.pure.u64(a.limits.dailyMax), + ], + }); + } + for (const r of input.recipients ?? []) { + tx.moveCall({ + target: target(packageId, 'vault', 'setup_recipient'), + arguments: [setup, tx.pure.address(r.address), tx.pure.string(r.label)], + }); + } + tx.moveCall({ target: target(packageId, 'vault', 'finish'), arguments: [setup] }); + return tx; +} + +/** + * Fund a vault. SUI comes out of the gas coin, which is the only coin a PTB always has; any other + * asset is merged from the coin objects the caller holds and then split to the exact amount, so a + * deposit never has to match a coin's balance. + */ +export function deposit( + packageId: string, + input: { vaultId: string; coinType: string; amount: bigint; coinObjectIds?: string[] }, +): Transaction { + const tx = new Transaction(); + let coin: TransactionObjectArgument; + if (input.coinType === SUI_TYPE_ARG || input.coinType === '0x2::sui::SUI') { + [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(input.amount)]); + } else { + const ids = input.coinObjectIds ?? []; + if (ids.length === 0) throw new Error('coinObjectIds is required for a non-SUI deposit'); + const primary = tx.object(ids[0]); + if (ids.length > 1) tx.mergeCoins(primary, ids.slice(1).map((id) => tx.object(id))); + [coin] = tx.splitCoins(primary, [tx.pure.u64(input.amount)]); + } + tx.moveCall({ + target: target(packageId, 'vault', 'deposit'), + typeArguments: [input.coinType], + arguments: [tx.object(input.vaultId), coin, tx.object(CLOCK_ID)], + }); + return tx; +} + +export function proposeTransfer( + packageId: string, + input: { + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; + memo?: string; + }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.amount), + tx.pure.address(input.recipient), + tx.pure.string(input.memo ?? ''), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +/** `approve`, `confirm`, `veto`, `cancel` and `expire` all take the same arguments. */ +function proposalAction(packageId: string, fn: string, vaultId: string, proposalId: bigint) { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', fn), + arguments: [tx.object(vaultId), tx.pure.u64(proposalId), tx.object(CLOCK_ID)], + }); + return tx; +} + +export const approve = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'approve', vaultId, id); +export const confirm = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'confirm', vaultId, id); +export const veto = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'veto', vaultId, id); +export const cancel = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'cancel', vaultId, id); +export const expire = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'expire', vaultId, id); +export const executePolicy = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'execute_policy', vaultId, id); +export const executeMember = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'execute_member', vaultId, id); +export const executeRecipientTrust = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'execute_recipient_trust', vaultId, id); +export const executeModeRelax = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'execute_mode_relax', vaultId, id); +export const executeRecovery = (pkg: string, vaultId: string, id: bigint) => + proposalAction(pkg, 'execute_recovery', vaultId, id); + +export function executeTransfer( + packageId: string, + input: { vaultId: string; coinType: string; proposalId: bigint }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'execute_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.proposalId), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function registerRecipient( + packageId: string, + input: { vaultId: string; recipient: string; label: string }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'register_recipient'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.string(input.label), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +/** A guardian restricting or blocking a destination, immediately and alone. */ +export function guardianRestrict( + packageId: string, + input: { vaultId: string; recipient: string; trust: Trust }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'guardian_restrict'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.u8(input.trust), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function raiseMode( + packageId: string, + input: { vaultId: string; mode: Mode; reasons?: number }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'raise_mode'), + arguments: [ + tx.object(input.vaultId), + tx.pure.u8(input.mode), + tx.pure.u16(input.reasons ?? 0), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function proposePolicy( + packageId: string, + input: { vaultId: string; policy: Policy }, +): Transaction { + const tx = new Transaction(); + const b = { tx, packageId }; + tx.moveCall({ + target: target(packageId, 'vault', 'propose_policy'), + arguments: [tx.object(input.vaultId), policyArg(b, input.policy), tx.object(CLOCK_ID)], + }); + return tx; +} + +export function proposeAssetLimits( + packageId: string, + input: { vaultId: string; coinType: string; limits: AssetLimits }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_asset_limits'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.bool(input.limits.approved), + tx.pure.u64(input.limits.lowMax), + tx.pure.u64(input.limits.highMax), + tx.pure.u64(input.limits.perTxMax), + tx.pure.u64(input.limits.dailyMax), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function executeAssetLimits( + packageId: string, + input: { vaultId: string; coinType: string; proposalId: bigint }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'execute_asset_limits'), + typeArguments: [input.coinType], + arguments: [tx.object(input.vaultId), tx.pure.u64(input.proposalId), tx.object(CLOCK_ID)], + }); + return tx; +} + +/** `roles` of 0 removes the member. */ +export function proposeMember( + packageId: string, + input: { vaultId: string; member: string; roles: number }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_member'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.member), + tx.pure.u8(input.roles), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function proposeRecipientTrust( + packageId: string, + input: { vaultId: string; recipient: string; trust: Trust }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_recipient_trust'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.recipient), + tx.pure.u8(input.trust), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +export function proposeModeRelax( + packageId: string, + input: { vaultId: string; mode: Mode }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_mode_relax'), + arguments: [tx.object(input.vaultId), tx.pure.u8(input.mode), tx.object(CLOCK_ID)], + }); + return tx; +} + +export function proposeRecovery( + packageId: string, + input: { vaultId: string; lost: string; replacement: string }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'propose_recovery'), + arguments: [ + tx.object(input.vaultId), + tx.pure.address(input.lost), + tx.pure.address(input.replacement), + tx.object(CLOCK_ID), + ], + }); + return tx; +} + +/** The block used to read `preview_transfer` back through a simulation. */ +export function previewTransferTx( + packageId: string, + input: { vaultId: string; coinType: string; amount: bigint; recipient: string }, +): Transaction { + const tx = new Transaction(); + tx.moveCall({ + target: target(packageId, 'vault', 'preview_transfer'), + typeArguments: [input.coinType], + arguments: [ + tx.object(input.vaultId), + tx.pure.u64(input.amount), + tx.pure.address(input.recipient), + tx.object(CLOCK_ID), + ], + }); + return tx; +} diff --git a/sdk/src/types.ts b/sdk/src/types.ts new file mode 100644 index 0000000..4cf80cb --- /dev/null +++ b/sdk/src/types.ts @@ -0,0 +1,288 @@ +/** + * The vocabulary, kept identical to `sui/sources/types.move`. Anything that disagrees with the + * chain is a bug in this file, not in the contract. + * + * Durations are milliseconds everywhere, because that is what `sui::clock` reports. Amounts are + * `bigint` in the smallest unit of their coin type. + */ + +export const Role = { + OWNER: 1, + APPROVER: 2, + EXECUTOR: 4, + GUARDIAN: 8, + /** An automated agent: may open proposals and nothing else. */ + PROPOSER: 16, +} as const; +export type Role = (typeof Role)[keyof typeof Role]; + +export const ROLE_TREASURY_MASK = Role.OWNER | Role.APPROVER | Role.EXECUTOR | Role.PROPOSER; +export const ROLE_ALL = 31; + +export const ROLE_LABELS: Record = { + [Role.OWNER]: 'Owner', + [Role.APPROVER]: 'Approver', + [Role.EXECUTOR]: 'Executor', + [Role.GUARDIAN]: 'Guardian', + [Role.PROPOSER]: 'Proposer', +}; + +export function hasRole(bits: number, role: Role | number): boolean { + return (bits & role) === role; +} + +export function hasAnyRole(bits: number, mask: number): boolean { + return (bits & mask) !== 0; +} + +export function canPropose(bits: number): boolean { + return hasAnyRole(bits, ROLE_TREASURY_MASK); +} + +/** A guardian is the second control plane and may hold no treasury role. */ +export function rolesValid(bits: number): boolean { + if (bits === 0 || bits > ROLE_ALL) return false; + if (hasRole(bits, Role.GUARDIAN) && (bits & ROLE_TREASURY_MASK) !== 0) return false; + return true; +} + +export function describeRoles(bits: number): string[] { + return Object.values(Role) + .filter((r) => hasRole(bits, r)) + .map((r) => ROLE_LABELS[r]); +} + +export const Tier = { LOW: 0, HIGH: 1, CRITICAL: 2 } as const; +export type Tier = (typeof Tier)[keyof typeof Tier]; +export const TIER_LABELS: Record = { + [Tier.LOW]: 'Routine', + [Tier.HIGH]: 'High risk', + [Tier.CRITICAL]: 'Critical', +}; + +export const Trust = { + UNKNOWN: 0, + NEW: 1, + VERIFIED: 2, + TRUSTED: 3, + RESTRICTED: 4, + BLOCKED: 5, +} as const; +export type Trust = (typeof Trust)[keyof typeof Trust]; +export const TRUST_LABELS: Record = { + [Trust.UNKNOWN]: 'Never paid', + [Trust.NEW]: 'New', + [Trust.VERIFIED]: 'Verified', + [Trust.TRUSTED]: 'Trusted', + [Trust.RESTRICTED]: 'Restricted', + [Trust.BLOCKED]: 'Blocked', +}; + +export const Mode = { NORMAL: 0, ELEVATED: 1, LOCKDOWN: 2 } as const; +export type Mode = (typeof Mode)[keyof typeof Mode]; +export const MODE_LABELS: Record = { + [Mode.NORMAL]: 'Normal', + [Mode.ELEVATED]: 'Elevated', + [Mode.LOCKDOWN]: 'Lockdown', +}; + +export const Kind = { + TRANSFER: 0, + POLICY_UPDATE: 1, + ASSET_LIMITS: 2, + MEMBER_SET: 3, + RECIPIENT_TRUST: 4, + MODE_RELAX: 5, + RECOVERY: 6, +} as const; +export type Kind = (typeof Kind)[keyof typeof Kind]; +export const KIND_LABELS: Record = { + [Kind.TRANSFER]: 'Payment', + [Kind.POLICY_UPDATE]: 'Policy change', + [Kind.ASSET_LIMITS]: 'Asset limits', + [Kind.MEMBER_SET]: 'Signer change', + [Kind.RECIPIENT_TRUST]: 'Recipient trust', + [Kind.MODE_RELAX]: 'Lower security mode', + [Kind.RECOVERY]: 'Signer recovery', +}; + +export const Status = { + NONE: 0, + PENDING: 1, + EXECUTED: 2, + CANCELLED: 3, + VETOED: 4, + EXPIRED: 5, + /** Refused by the circuit breaker. The vault latched into Lockdown instead of paying. */ + BLOCKED: 6, +} as const; +export type Status = (typeof Status)[keyof typeof Status]; +export const STATUS_LABELS: Record = { + [Status.NONE]: 'Unknown', + [Status.PENDING]: 'Awaiting approval', + [Status.EXECUTED]: 'Executed', + [Status.CANCELLED]: 'Cancelled', + [Status.VETOED]: 'Vetoed', + [Status.EXPIRED]: 'Expired', + [Status.BLOCKED]: 'Refused by the circuit breaker', +}; + +export const Reason = { + AMOUNT_HIGH: 1, + AMOUNT_CRITICAL: 2, + EXPOSURE_HIGH: 4, + EXPOSURE_CRITICAL: 8, + RECIPIENT_PROBATION: 16, + RECIPIENT_RESTRICTED: 32, + MODE_ELEVATED: 64, + VELOCITY_PRESSURE: 128, + RECIPIENT_UNKNOWN: 256, + ENVELOPE_PRESSURE: 512, +} as const; +export type Reason = (typeof Reason)[keyof typeof Reason]; + +/** Plain-language explanations, in the order a reviewer should read them. */ +export const REASON_TEXT: [Reason, string][] = [ + [Reason.AMOUNT_CRITICAL, 'Above the high-tier maximum for this asset'], + [Reason.AMOUNT_HIGH, 'Above the routine maximum for this asset'], + [Reason.EXPOSURE_CRITICAL, 'A critical share of what the vault holds'], + [Reason.EXPOSURE_HIGH, 'A large share of what the vault holds'], + [Reason.RECIPIENT_RESTRICTED, 'The recipient is restricted'], + [Reason.RECIPIENT_UNKNOWN, 'The vault has never paid this address'], + [Reason.RECIPIENT_PROBATION, 'The recipient is still in its activation delay'], + [Reason.VELOCITY_PRESSURE, "Past half of today's allowance for this asset"], + [Reason.ENVELOPE_PRESSURE, 'Against the loss envelope for the window'], + [Reason.MODE_ELEVATED, 'The vault is in Elevated mode'], +]; + +export function describeReasons(mask: number): string[] { + return REASON_TEXT.filter(([bit]) => (mask & bit) !== 0).map(([, text]) => text); +} + +export const BPS = 10_000n; +export const SECOND = 1_000; +export const MINUTE = 60 * SECOND; +export const HOUR = 60 * MINUTE; +export const DAY = 24 * HOUR; + +/** The seventeen fields. Durations in milliseconds, exposures in basis points. */ +export type Policy = { + approvalsLow: number; + approvalsHigh: number; + approvalsCritical: number; + governanceThreshold: number; + guardianThreshold: number; + guardianRequiredCritical: boolean; + delayHigh: number; + delayCritical: number; + recipientActivationDelay: number; + policyChangeDelay: number; + recoveryDelay: number; + proposalTtl: number; + highExposureBps: number; + criticalExposureBps: number; + hardBlockExposureBps: number; + envelopeBps: number; + envelopeWindow: number; +}; + +export type AssetLimits = { + approved: boolean; + lowMax: bigint; + highMax: bigint; + perTxMax: bigint; + dailyMax: bigint; +}; + +export type Velocity = { + dayAnchor: number; + daySpent: bigint; + envelopeAnchor: number; + envelopeSpent: bigint; + /** The balance when the window opened; the envelope is measured against this, not the live + * balance, so a drain cannot shrink its own denominator. */ + envelopeBasis: bigint; +}; + +export type RecipientRecord = { + address: string; + trust: Trust; + registeredAt: number; + activatesAt: number; + paidCount: number; + lastPaid: number; + label: string; +}; + +export type Proposal = { + id: bigint; + kind: Kind; + status: Status; + proposer: string; + createdAt: number; + executableAt: number; + expiresAt: number; + reqApprovals: number; + reqGuardians: number; + tier: Tier; + reasons: number; + exposureBps: number; + policyVersion: bigint; + reductionMask: number; + approvals: string[]; + confirmations: string[]; + asset: string | null; + amount: bigint; + recipient: string; + memo: string; + newPolicy: Policy | null; + newLimits: AssetLimits | null; + member: string; + memberPrev: string; + memberRoles: number; + trustLevel: Trust; + targetMode: Mode; +}; + +export type VaultSummary = { + id: string; + name: string; + policy: Policy; + policyVersion: bigint; + mode: Mode; + postureReasons: number; + ownerCount: number; + approverCount: number; + executorCount: number; + guardianCount: number; + nextProposal: bigint; + pendingCount: number; + createdAt: number; + /** Table and Bag object ids, needed to read the collections by dynamic field. */ + tables: { + members: string; + limits: string; + funds: string; + velocity: string; + recipients: string; + proposals: string; + }; + sizes: { + members: number; + limits: number; + funds: number; + velocity: number; + recipients: number; + proposals: number; + }; +}; + +/** What `preview_transfer` returns, in order. */ +export type TransferPreview = { + tier: Tier; + reasons: number; + exposureBps: number; + reqApprovals: number; + reqGuardians: number; + delay: number; +}; diff --git a/sdk/src/vault.ts b/sdk/src/vault.ts new file mode 100644 index 0000000..ca4417e --- /dev/null +++ b/sdk/src/vault.ts @@ -0,0 +1,364 @@ +import type { ClientWithCoreApi } from '@mysten/sui/client'; +import { bcs } from '@mysten/sui/bcs'; +import { + AssetLimitsBcs, + PolicyBcs, + ProposalBcs, + RecipientBcs, + VaultBcs, + VelocityBcs, +} from './bcs.js'; +import { previewTransferTx } from './tx.js'; +import { + Kind, + Mode, + Status, + Tier, + Trust, + type AssetLimits, + type Policy, + type Proposal, + type RecipientRecord, + type TransferPreview, + type VaultSummary, + type Velocity, +} from './types.js'; + +/** + * Reading a vault. + * + * Written against `ClientWithCoreApi` rather than a concrete client, so the same code works over + * gRPC and GraphQL. The vault's collections are Move `Table`s and a `Bag`, which are dynamic + * fields on their own handles: list the names, then fetch the values. + */ + +const CONCURRENCY = 16; + +async function mapLimited(items: A[], fn: (a: A) => Promise, limit = CONCURRENCY) { + const out: B[] = new Array(items.length); + let next = 0; + const workers = Array.from({ length: Math.min(limit, items.length) }, async () => { + while (true) { + const i = next++; + if (i >= items.length) return; + out[i] = await fn(items[i]); + } + }); + await Promise.all(workers); + return out; +} + +function num(v: string | number | bigint): number { + return Number(v); +} + +function big(v: string | number | bigint): bigint { + return BigInt(v); +} + +function toPolicy(raw: ReturnType): Policy { + return { + approvalsLow: raw.approvals_low, + approvalsHigh: raw.approvals_high, + approvalsCritical: raw.approvals_critical, + governanceThreshold: raw.governance_threshold, + guardianThreshold: raw.guardian_threshold, + guardianRequiredCritical: raw.guardian_required_critical, + delayHigh: num(raw.delay_high), + delayCritical: num(raw.delay_critical), + recipientActivationDelay: num(raw.recipient_activation_delay), + policyChangeDelay: num(raw.policy_change_delay), + recoveryDelay: num(raw.recovery_delay), + proposalTtl: num(raw.proposal_ttl), + highExposureBps: num(raw.high_exposure_bps), + criticalExposureBps: num(raw.critical_exposure_bps), + hardBlockExposureBps: num(raw.hard_block_exposure_bps), + envelopeBps: num(raw.envelope_bps), + envelopeWindow: num(raw.envelope_window), + }; +} + +function toLimits(raw: ReturnType): AssetLimits { + return { + approved: raw.approved, + lowMax: big(raw.low_max), + highMax: big(raw.high_max), + perTxMax: big(raw.per_tx_max), + dailyMax: big(raw.daily_max), + }; +} + +export async function fetchVault( + client: ClientWithCoreApi, + vaultId: string, +): Promise { + const { object } = await client.core.getObject({ objectId: vaultId, include: { content: true } }); + const v = VaultBcs.parse(object.content); + return { + id: vaultId, + name: v.name, + policy: toPolicy(v.policy), + policyVersion: big(v.policy_version), + mode: num(v.mode) as Mode, + postureReasons: num(v.posture_reasons), + ownerCount: num(v.owner_count), + approverCount: num(v.approver_count), + executorCount: num(v.executor_count), + guardianCount: num(v.guardian_count), + nextProposal: big(v.next_proposal), + pendingCount: num(v.pending_count), + createdAt: num(v.created_at), + tables: { + members: v.members.id, + limits: v.limits.id, + funds: v.funds.id, + velocity: v.velocity.id, + recipients: v.recipients.id, + proposals: v.proposals.id, + }, + sizes: { + members: num(v.members.size), + limits: num(v.limits.size), + funds: num(v.funds.size), + velocity: num(v.velocity.size), + recipients: num(v.recipients.size), + proposals: num(v.proposals.size), + }, + }; +} + +/** Every dynamic field name under a handle, paged to the end. */ +async function listNames(client: ClientWithCoreApi, parentId: string) { + const names: { type: string; bcs: Uint8Array }[] = []; + let page = await client.core.listDynamicFields({ parentId, limit: 50 }); + for (;;) { + for (const f of page.dynamicFields) names.push(f.name); + if (!page.hasNextPage) break; + page = await client.core.listDynamicFields({ parentId, cursor: page.cursor, limit: 50 }); + } + return names; +} + +async function readEntries( + client: ClientWithCoreApi, + parentId: string, + parse: (bytes: Uint8Array) => V, +) { + const names = await listNames(client, parentId); + return mapLimited(names, async (name) => { + const { dynamicField } = await client.core.getDynamicField({ parentId, name }); + return { name, value: parse(dynamicField.value.bcs) }; + }); +} + +export async function fetchMembers( + client: ClientWithCoreApi, + vault: VaultSummary, +): Promise<{ address: string; roles: number }[]> { + const entries = await readEntries(client, vault.tables.members, (b) => bcs.u8().parse(b)); + return entries.map((e) => ({ + address: bcs.Address.parse(e.name.bcs), + roles: e.value, + })); +} + +/** The `TypeName` a `Table` or the funds `Bag` is keyed by. */ +function parseTypeNameKey(bytes: Uint8Array): string { + const name = bcs.struct('TypeName', { name: bcs.string() }).parse(bytes).name; + // Move reports a type name without the leading `0x`; restore it so the string matches the + // coin type an interface or an RPC filter would use. + return name.startsWith('0x') ? name : `0x${name}`; +} + +export async function fetchLimits( + client: ClientWithCoreApi, + vault: VaultSummary, +): Promise<{ coinType: string; limits: AssetLimits }[]> { + const entries = await readEntries(client, vault.tables.limits, (b) => + toLimits(AssetLimitsBcs.parse(b)), + ); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), limits: e.value })); +} + +export async function fetchBalances( + client: ClientWithCoreApi, + vault: VaultSummary, +): Promise<{ coinType: string; balance: bigint }[]> { + const entries = await readEntries(client, vault.tables.funds, (b) => big(bcs.u64().parse(b))); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), balance: e.value })); +} + +export async function fetchVelocity( + client: ClientWithCoreApi, + vault: VaultSummary, +): Promise<{ coinType: string; velocity: Velocity }[]> { + const entries = await readEntries(client, vault.tables.velocity, (b) => { + const raw = VelocityBcs.parse(b); + return { + dayAnchor: num(raw.day_anchor), + daySpent: big(raw.day_spent), + envelopeAnchor: num(raw.envelope_anchor), + envelopeSpent: big(raw.envelope_spent), + envelopeBasis: big(raw.envelope_basis), + } satisfies Velocity; + }); + return entries.map((e) => ({ coinType: parseTypeNameKey(e.name.bcs), velocity: e.value })); +} + +export async function fetchRecipients( + client: ClientWithCoreApi, + vault: VaultSummary, +): Promise { + const entries = await readEntries(client, vault.tables.recipients, (b) => RecipientBcs.parse(b)); + return entries.map((e) => ({ + address: bcs.Address.parse(e.name.bcs), + trust: num(e.value.trust) as Trust, + registeredAt: num(e.value.registered_at), + activatesAt: num(e.value.activates_at), + paidCount: num(e.value.paid_count), + lastPaid: num(e.value.last_paid), + label: e.value.label, + })); +} + +function toProposal(raw: ReturnType): Proposal { + return { + id: big(raw.id), + kind: num(raw.kind) as Kind, + status: num(raw.status) as Status, + proposer: raw.proposer, + createdAt: num(raw.created_at), + executableAt: num(raw.executable_at), + expiresAt: num(raw.expires_at), + reqApprovals: raw.req_approvals, + reqGuardians: raw.req_guardians, + tier: num(raw.tier) as Tier, + reasons: num(raw.reasons), + exposureBps: num(raw.exposure_bps), + policyVersion: big(raw.policy_version), + reductionMask: num(raw.reduction_mask), + approvals: raw.approvals.contents, + confirmations: raw.confirmations.contents, + asset: raw.asset ? (raw.asset.name.startsWith('0x') ? raw.asset.name : `0x${raw.asset.name}`) : null, + amount: big(raw.amount), + recipient: raw.recipient, + memo: raw.memo, + newPolicy: raw.new_policy ? toPolicy(raw.new_policy) : null, + newLimits: raw.new_limits ? toLimits(raw.new_limits) : null, + member: raw.member, + memberPrev: raw.member_prev, + memberRoles: raw.member_roles, + trustLevel: num(raw.trust_level) as Trust, + targetMode: num(raw.target_mode) as Mode, + }; +} + +/** One proposal by its number. */ +export async function fetchProposal( + client: ClientWithCoreApi, + vault: VaultSummary, + id: bigint, +): Promise { + try { + const { dynamicField } = await client.core.getDynamicField({ + parentId: vault.tables.proposals, + name: { type: 'u64', bcs: bcs.u64().serialize(id).toBytes() }, + }); + return toProposal(ProposalBcs.parse(dynamicField.value.bcs)); + } catch { + return null; + } +} + +/** + * The most recent proposals, newest first. Proposal numbers are sequential from 1, so this walks + * backwards from the counter instead of listing the whole table — a vault with ten thousand + * settled payments should not have to read all of them to show the queue. + */ +export async function fetchRecentProposals( + client: ClientWithCoreApi, + vault: VaultSummary, + count = 25, +): Promise { + const last = vault.nextProposal - 1n; + const ids: bigint[] = []; + for (let i = last; i > 0n && ids.length < count; i--) ids.push(i); + const got = await mapLimited(ids, (id) => fetchProposal(client, vault, id)); + return got.filter((p): p is Proposal => p !== null); +} + +/** + * What the vault itself says a transfer would need, read by simulating its own + * `preview_transfer`. The interface never computes this for a live vault: if the preview and the + * execution could disagree, the preview is worthless. + */ +export async function previewTransfer( + client: ClientWithCoreApi, + input: { + packageId: string; + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; + sender: string; + }, +): Promise { + const tx = previewTransferTx(input.packageId, input); + tx.setSender(input.sender); + const result = await client.core.simulateTransaction({ + transaction: await tx.build({ client }), + include: { commandResults: true }, + }); + const values = result.commandResults?.[0]?.returnValues; + if (!values || values.length < 6) { + throw new Error('preview_transfer returned no values; is the package id correct?'); + } + const at = (i: number) => values[i].bcs ?? values[i]; + return { + tier: num(bcs.u8().parse(at(0) as Uint8Array)) as Tier, + reasons: num(bcs.u16().parse(at(1) as Uint8Array)), + exposureBps: num(bcs.u64().parse(at(2) as Uint8Array)), + reqApprovals: num(bcs.u8().parse(at(3) as Uint8Array)), + reqGuardians: num(bcs.u8().parse(at(4) as Uint8Array)), + delay: num(bcs.u64().parse(at(5) as Uint8Array)), + }; +} + +/** Everything an interface needs for one screen, in as few round trips as the transport allows. */ +export type VaultView = { + vault: VaultSummary; + members: { address: string; roles: number }[]; + assets: { coinType: string; limits: AssetLimits; balance: bigint; velocity: Velocity | null }[]; + recipients: RecipientRecord[]; + proposals: Proposal[]; +}; + +export async function fetchVaultView( + client: ClientWithCoreApi, + vaultId: string, + proposalCount = 25, +): Promise { + const vault = await fetchVault(client, vaultId); + const [members, limits, balances, velocity, recipients, proposals] = await Promise.all([ + fetchMembers(client, vault), + fetchLimits(client, vault), + fetchBalances(client, vault), + fetchVelocity(client, vault), + fetchRecipients(client, vault), + fetchRecentProposals(client, vault, proposalCount), + ]); + const balanceOf = new Map(balances.map((b) => [b.coinType, b.balance])); + const velocityOf = new Map(velocity.map((v) => [v.coinType, v.velocity])); + return { + vault, + members, + recipients, + proposals, + assets: limits.map((l) => ({ + coinType: l.coinType, + limits: l.limits, + balance: balanceOf.get(l.coinType) ?? 0n, + velocity: velocityOf.get(l.coinType) ?? null, + })), + }; +} diff --git a/sdk/test/engine.test.ts b/sdk/test/engine.test.ts new file mode 100644 index 0000000..1ead3c6 --- /dev/null +++ b/sdk/test/engine.test.ts @@ -0,0 +1,370 @@ +import { describe, expect, it } from 'vitest'; +import { + classify, + computeMaxLoss, + effectiveCaps, + exposureBps, + fmtDuration, + limitReductions, + parseAmount, + policyReductions, + postureItems, + requirements, + runScenarios, + TEMPLATES, + trustReduces, + validateCounts, + validateLimits, + validatePolicy, + validatePolicyCode, +} from '../src/engine'; +import { DAY, HOUR, Mode, Reason, Tier, Trust, type Policy } from '../src/types'; + +/** + * These are the same vectors as `sui/tests/engine_tests.move`. Both suites have to agree, because + * the only thing worse than a wrong tier is two components disagreeing about it. + */ +const base: Policy = { + approvalsLow: 1, + approvalsHigh: 2, + approvalsCritical: 3, + governanceThreshold: 2, + guardianThreshold: 1, + guardianRequiredCritical: true, + delayHigh: HOUR, + delayCritical: DAY, + recipientActivationDelay: 12 * HOUR, + policyChangeDelay: 2 * DAY, + recoveryDelay: 3 * DAY, + proposalTtl: 30 * DAY, + highExposureBps: 1_000, + criticalExposureBps: 2_500, + hardBlockExposureBps: 9_000, + envelopeBps: 3_000, + envelopeWindow: DAY, +}; + +const input = ( + amount: bigint, + balance: bigint, + trust: Trust, + probation = false, + mode: Mode = Mode.NORMAL, +) => ({ + amount, + assetBalance: balance, + lowMax: 1_000n, + highMax: 10_000n, + dailyMax: 0n, + daySpent: 0n, + trust, + inProbation: probation, + mode, + highExposureBps: 1_000, + criticalExposureBps: 2_500, +}); + +describe('policy validation', () => { + it('accepts the base policy', () => { + expect(validatePolicyCode(base)).toBe(0); + expect(validatePolicy(base)).toEqual([]); + }); + + it('returns the same code the contract aborts with', () => { + expect(validatePolicyCode({ ...base, approvalsLow: 0 })).toBe(1); + expect(validatePolicyCode({ ...base, approvalsHigh: 0, approvalsLow: 1 })).toBe(2); + expect(validatePolicyCode({ ...base, approvalsCritical: 1 })).toBe(3); + expect(validatePolicyCode({ ...base, governanceThreshold: 0 })).toBe(4); + expect(validatePolicyCode({ ...base, guardianThreshold: 0 })).toBe(5); + expect(validatePolicyCode({ ...base, delayCritical: 0 })).toBe(6); + expect(validatePolicyCode({ ...base, highExposureBps: 3_000 })).toBe(7); + expect(validatePolicyCode({ ...base, hardBlockExposureBps: 2_000 })).toBe(9); + expect(validatePolicyCode({ ...base, envelopeWindow: 60_000 })).toBe(12); + expect(validatePolicyCode({ ...base, proposalTtl: DAY })).toBe(13); + }); + + it('requires the lifetime to clear the longest delay by an hour', () => { + const p = { ...base, delayCritical: DAY, policyChangeDelay: 0, recoveryDelay: 0, recipientActivationDelay: 0 }; + expect(validatePolicyCode({ ...p, proposalTtl: DAY + HOUR })).toBe(0); + expect(validatePolicyCode({ ...p, proposalTtl: DAY + HOUR - 1 })).toBe(13); + }); + + it('checks the roster against the policy', () => { + expect(validateCounts(base, 2, 3, 1, 1)).toEqual([]); + expect(validateCounts(base, 0, 3, 1, 1)).toHaveLength(2); // no owner, and below threshold + expect(validateCounts(base, 2, 3, 0, 1)).toHaveLength(1); + expect(validateCounts(base, 2, 2, 1, 1)).toHaveLength(1); + expect(validateCounts(base, 2, 3, 1, 0)).toHaveLength(1); + }); + + it('checks limits for coherence, treating zero as no cap', () => { + expect(validateLimits({ approved: true, lowMax: 10n, highMax: 5n, perTxMax: 0n, dailyMax: 0n })).toHaveLength(1); + expect(validateLimits({ approved: true, lowMax: 1n, highMax: 5n, perTxMax: 100n, dailyMax: 50n })).toHaveLength(1); + expect(validateLimits({ approved: true, lowMax: 1n, highMax: 5n, perTxMax: 100n, dailyMax: 0n })).toEqual([]); + }); +}); + +describe('what counts as weakening', () => { + it('reports nothing for a change that only tightens', () => { + expect( + policyReductions(base, { + ...base, + approvalsLow: 2, + delayHigh: 2 * HOUR, + highExposureBps: 500, + envelopeBps: 2_000, + }), + ).toEqual([]); + }); + + it('catches fewer approvals', () => { + expect(policyReductions(base, { ...base, approvalsHigh: 1 })).toHaveLength(1); + }); + + it('catches dropping the guardian requirement', () => { + expect(policyReductions(base, { ...base, guardianRequiredCritical: false })).toEqual([ + 'no guardian required for critical payments', + ]); + }); + + it('treats disabling a threshold as the loosest move, not the tightest', () => { + expect(policyReductions(base, { ...base, envelopeBps: 0 })).toEqual(['a larger loss envelope']); + expect(policyReductions(base, { ...base, hardBlockExposureBps: 0 })).toEqual([ + 'a weaker exposure hard block', + ]); + }); + + it('treats a longer proposal lifetime as weakening', () => { + expect(policyReductions(base, { ...base, proposalTtl: 60 * DAY })).toEqual([ + 'a longer proposal lifetime', + ]); + }); + + it('catches weakened caps and newly approved assets', () => { + const a = { approved: true, lowMax: 100n, highMax: 1_000n, perTxMax: 500n, dailyMax: 5_000n }; + expect(limitReductions(a, { ...a, perTxMax: 0n })).toEqual(['a weaker per-transaction cap']); + expect(limitReductions(a, { ...a, perTxMax: 400n })).toEqual([]); + expect(limitReductions({ ...a, approved: false }, a)).toContain('approving a new asset'); + }); + + it('treats lifting a restriction as weakening and imposing one as not', () => { + expect(trustReduces(Trust.RESTRICTED, Trust.VERIFIED)).toBe(true); + expect(trustReduces(Trust.NEW, Trust.TRUSTED)).toBe(true); + expect(trustReduces(Trust.TRUSTED, Trust.BLOCKED)).toBe(false); + expect(trustReduces(Trust.VERIFIED, Trust.NEW)).toBe(false); + }); +}); + +describe('risk classification', () => { + it('computes exposure as a share of holdings', () => { + expect(exposureBps(0n, 1_000n)).toBe(0); + expect(exposureBps(100n, 1_000n)).toBe(1_000); + expect(exposureBps(1_000n, 1_000n)).toBe(10_000); + expect(exposureBps(1_500n, 1_000n)).toBe(10_000); + expect(exposureBps(5n, 0n)).toBe(10_000); + }); + + it('survives a treasury large enough to overflow 64-bit intermediate maths', () => { + const big = 1_000_000_000_000_000_000n; + expect(exposureBps(big / 4n, big)).toBe(2_500); + }); + + it('escalates on amount', () => { + expect(classify(input(500n, 1_000_000n, Trust.VERIFIED)).tier).toBe(Tier.LOW); + expect(classify(input(5_000n, 1_000_000n, Trust.VERIFIED)).tier).toBe(Tier.HIGH); + expect(classify(input(50_000n, 10_000_000n, Trust.VERIFIED)).tier).toBe(Tier.CRITICAL); + }); + + it('escalates on share of the treasury alone', () => { + const o = classify(input(500n, 4_000n, Trust.VERIFIED)); + expect(o.tier).toBe(Tier.HIGH); + expect(o.reasons & Reason.EXPOSURE_HIGH).toBeTruthy(); + expect(classify(input(900n, 3_000n, Trust.VERIFIED)).tier).toBe(Tier.CRITICAL); + }); + + it('escalates an address the vault has never paid', () => { + const o = classify(input(500n, 1_000_000n, Trust.UNKNOWN)); + expect(o.tier).toBe(Tier.HIGH); + expect(o.reasons & Reason.RECIPIENT_UNKNOWN).toBeTruthy(); + expect(classify(input(5_000n, 1_000_000n, Trust.UNKNOWN)).tier).toBe(Tier.CRITICAL); + }); + + it('escalates during probation and stops afterwards', () => { + expect(classify(input(500n, 1_000_000n, Trust.NEW, true)).tier).toBe(Tier.HIGH); + expect(classify(input(500n, 1_000_000n, Trust.NEW, false)).tier).toBe(Tier.LOW); + }); + + it('makes a restricted recipient critical at any amount', () => { + expect(classify(input(1n, 1_000_000_000n, Trust.RESTRICTED)).tier).toBe(Tier.CRITICAL); + }); + + it('escalates halfway through the day rather than at the end', () => { + const quiet = { ...input(100n, 1_000_000n, Trust.VERIFIED), dailyMax: 10_000n, daySpent: 0n }; + expect(classify(quiet).tier).toBe(Tier.LOW); + const pressured = { ...quiet, daySpent: 5_000n }; + const o = classify(pressured); + expect(o.tier).toBe(Tier.HIGH); + expect(o.reasons & Reason.VELOCITY_PRESSURE).toBeTruthy(); + }); + + it('escalates everything in Elevated mode', () => { + expect(classify(input(500n, 1_000_000n, Trust.VERIFIED, false, Mode.ELEVATED)).tier).toBe(Tier.HIGH); + expect(classify(input(5_000n, 1_000_000n, Trust.VERIFIED, false, Mode.ELEVATED)).tier).toBe(Tier.CRITICAL); + }); + + it('records every reason, not only the loudest', () => { + const o = classify({ + ...input(5_000n, 20_000n, Trust.UNKNOWN, true, Mode.ELEVATED), + dailyMax: 10_000n, + daySpent: 6_000n, + }); + expect(o.tier).toBe(Tier.CRITICAL); + for (const bit of [ + Reason.AMOUNT_HIGH, + Reason.EXPOSURE_CRITICAL, + Reason.RECIPIENT_UNKNOWN, + Reason.VELOCITY_PRESSURE, + Reason.MODE_ELEVATED, + ]) { + expect(o.reasons & bit).toBeTruthy(); + } + }); + + it('maps a tier to its requirements', () => { + expect(requirements(base, Tier.LOW)).toEqual({ approvals: 1, guardians: 0, delay: 0 }); + expect(requirements(base, Tier.HIGH)).toEqual({ approvals: 2, guardians: 0, delay: HOUR }); + expect(requirements(base, Tier.CRITICAL)).toEqual({ approvals: 3, guardians: 1, delay: DAY }); + }); + + it('halves the caps in Elevated but never to zero, and leaves "no cap" alone', () => { + expect(effectiveCaps(1_000n, 10_000n, Mode.ELEVATED)).toEqual({ perTxMax: 500n, dailyMax: 5_000n }); + expect(effectiveCaps(1n, 1n, Mode.ELEVATED)).toEqual({ perTxMax: 1n, dailyMax: 1n }); + expect(effectiveCaps(0n, 0n, Mode.ELEVATED)).toEqual({ perTxMax: 0n, dailyMax: 0n }); + expect(effectiveCaps(1_000n, 10_000n, Mode.NORMAL)).toEqual({ perTxMax: 1_000n, dailyMax: 10_000n }); + }); +}); + +describe('templates', () => { + it('ships only valid policies', () => { + for (const t of TEMPLATES) { + expect(validatePolicy(t.policy), t.name).toEqual([]); + expect(validateLimits(t.stable), t.name).toEqual([]); + expect(validateLimits(t.native), t.name).toEqual([]); + } + }); + + it('ships rosters each template can actually satisfy', () => { + for (const t of TEMPLATES) { + expect( + validateCounts(t.policy, t.minSigners, t.minSigners, t.minSigners, t.minGuardians), + t.name, + ).toEqual([]); + } + }); + + it('covers every kind of organization the product is for', () => { + expect(TEMPLATES.map((t) => t.id)).toEqual([ + 'startup', + 'team', + 'protocol', + 'fund', + 'payments', + 'nonprofit', + 'familyOffice', + ]); + }); +}); + +describe('maximum loss', () => { + const limits = { approved: true, lowMax: 5_000n, highMax: 25_000n, perTxMax: 0n, dailyMax: 100_000n }; + + it('is bounded by the tightest cumulative control', () => { + const r = computeMaxLoss(base, limits, 1_000_000n, Mode.NORMAL); + // The envelope is 30% of 1,000,000 = 300,000, so the 100,000 daily cap binds first. + expect(r.immediate).toBe(100_000n); + expect(r.immediateBinding).toBe('the daily cap'); + }); + + it('is zero in Lockdown', () => { + const r = computeMaxLoss(base, limits, 1_000_000n, Mode.LOCKDOWN); + expect(r.immediate).toBe(0n); + expect(r.day).toBe(0n); + }); + + it('always states its assumptions', () => { + expect(computeMaxLoss(base, limits, 1_000_000n, Mode.NORMAL).assumptions.length).toBeGreaterThan(3); + }); +}); + +describe('the simulator', () => { + const ctx = { + policy: base, + limits: { approved: true, lowMax: 5_000_000_000n, highMax: 25_000_000_000n, perTxMax: 0n, dailyMax: 100_000_000_000n }, + balance: 1_000_000_000_000n, + decimals: 6, + symbol: 'USDC', + approverCount: 4, + guardianCount: 2, + }; + + it('stops one compromised signer paying a new address', () => { + const r = runScenarios(ctx).find((s) => s.id === 'single-signer-new-address')!; + expect(r.verdict).toBe('blocked'); + }); + + it('calls a compromised guardian impossible, because it holds no spend path', () => { + const r = runScenarios(ctx).find((s) => s.id === 'guardian-compromised')!; + expect(r.verdict).toBe('impossible'); + }); + + it('stops a split drain on the cumulative controls', () => { + const r = runScenarios(ctx).find((s) => s.id === 'split-drain')!; + expect(r.verdict).toBe('blocked'); + expect(r.detail.join(' ')).toMatch(/envelope|daily cap/); + }); + + it('warns when nothing cumulative is configured', () => { + const open = { + ...ctx, + policy: { ...base, envelopeBps: 0 }, + limits: { ...ctx.limits, dailyMax: 0n }, + }; + const r = runScenarios(open).find((s) => s.id === 'split-drain')!; + expect(r.verdict).toBe('allowed'); + expect(r.detail.join(' ')).toMatch(/Set a daily cap or a loss envelope/); + }); + + it('shows a compromised agent cannot pay itself', () => { + const r = runScenarios(ctx).find((s) => s.id === 'agent-compromised')!; + expect(r.verdict).toBe('blocked'); + }); +}); + +describe('posture', () => { + it('flags a vault with no guardian as bad, not merely a warning', () => { + const items = postureItems({ policy: base, guardians: 0, assets: [] }); + expect(items[0].ok).toBe('bad'); + }); + + it('flags an instantly weakenable policy', () => { + const items = postureItems({ policy: { ...base, policyChangeDelay: 0 }, guardians: 1, assets: [] }); + expect(items.some((i) => i.ok === 'bad' && /weakened immediately/.test(i.text))).toBe(true); + }); +}); + +describe('formatting', () => { + it('renders durations from milliseconds', () => { + expect(fmtDuration(0)).toBe('none'); + expect(fmtDuration(HOUR)).toBe('1h'); + expect(fmtDuration(DAY + 6 * HOUR)).toBe('1d 6h'); + expect(fmtDuration(90 * 60_000)).toBe('1h 30m'); + }); + + it('parses amounts without losing precision', () => { + expect(parseAmount('1.5', 9)).toBe(1_500_000_000n); + expect(parseAmount('0.000001', 6)).toBe(1n); + expect(parseAmount('1,000', 6)).toBe(1_000_000_000n); + expect(parseAmount('1.0000001', 6)).toBeNull(); + expect(parseAmount('abc', 6)).toBeNull(); + }); +}); diff --git a/sdk/tsconfig.build.json b/sdk/tsconfig.build.json new file mode 100644 index 0000000..cf12b4a --- /dev/null +++ b/sdk/tsconfig.build.json @@ -0,0 +1,21 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "nodenext", + "allowImportingTsExtensions": false + }, + "include": [ + "src" + ], + "exclude": [ + "scripts", + "test" + ] +} \ No newline at end of file diff --git a/sdk/tsconfig.json b/sdk/tsconfig.json new file mode 100644 index 0000000..2eaf5ec --- /dev/null +++ b/sdk/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": [ + "ES2023", + "DOM" + ], + "strict": true, + "noUncheckedIndexedAccess": false, + "noEmit": true, + "skipLibCheck": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowImportingTsExtensions": true, + "types": [ + "node" + ] + }, + "include": [ + "src", + "scripts", + "test" + ] +} \ No newline at end of file diff --git a/server/.env.example b/server/.env.example new file mode 100644 index 0000000..84ea356 --- /dev/null +++ b/server/.env.example @@ -0,0 +1,14 @@ +# Postgres +DATABASE_URL=postgres://localhost:5432/skur + +# Which network to index, and the published package on it. +SKUR_NETWORK=testnet +SKUR_PACKAGE_ID=0x0 + +# Optional: a gRPC endpoint other than the public full node. +# SKUR_GRPC_URL=https://fullnode.testnet.sui.io:443 + +# How often the indexer asks for new events, in milliseconds. +INDEX_INTERVAL_MS=4000 + +PORT=8787 diff --git a/server/migrations/001_init.sql b/server/migrations/001_init.sql new file mode 100644 index 0000000..e45f280 --- /dev/null +++ b/server/migrations/001_init.sql @@ -0,0 +1,182 @@ +-- Skur indexer and notification store. +-- +-- Nothing here is authoritative. The chain is. Every row is a projection of an event the vault +-- emitted, kept so that an interface can answer "show me the last 500 payments" without walking +-- the ledger, and so that a notification can be sent once rather than every time someone polls. +-- +-- Two consequences are designed for: the indexer may see the same event twice (so every insert is +-- idempotent on its ledger position), and it may be rebuilt from zero (so no table holds state +-- that cannot be derived from events). + +CREATE TABLE IF NOT EXISTS networks ( + name TEXT PRIMARY KEY, + package_id TEXT NOT NULL, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Where the indexer has read to. One row per network, advanced only after a batch commits. +CREATE TABLE IF NOT EXISTS indexer_cursor ( + network TEXT PRIMARY KEY REFERENCES networks(name) ON DELETE CASCADE, + cursor TEXT, + last_event_at TIMESTAMPTZ, + events_seen BIGINT NOT NULL DEFAULT 0, + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +CREATE TABLE IF NOT EXISTS vaults ( + network TEXT NOT NULL REFERENCES networks(name) ON DELETE CASCADE, + vault_id TEXT NOT NULL, + name TEXT NOT NULL, + creator TEXT NOT NULL, + mode SMALLINT NOT NULL DEFAULT 0, + posture_reasons INTEGER NOT NULL DEFAULT 0, + policy_version BIGINT NOT NULL DEFAULT 1, + created_at TIMESTAMPTZ NOT NULL, + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (network, vault_id) +); + +-- The raw event log, which is the only table the projections are derived from. +CREATE TABLE IF NOT EXISTS events ( + network TEXT NOT NULL REFERENCES networks(name) ON DELETE CASCADE, + tx_digest TEXT NOT NULL, + event_index INTEGER NOT NULL, + vault_id TEXT NOT NULL, + name TEXT NOT NULL, + checkpoint BIGINT, + occurred_at TIMESTAMPTZ NOT NULL, + payload JSONB NOT NULL, + PRIMARY KEY (network, tx_digest, event_index) +); + +CREATE INDEX IF NOT EXISTS events_vault_time ON events (network, vault_id, occurred_at DESC); +CREATE INDEX IF NOT EXISTS events_name ON events (network, name, occurred_at DESC); + +CREATE TABLE IF NOT EXISTS members ( + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + address TEXT NOT NULL, + roles SMALLINT NOT NULL, + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (network, vault_id, address) +); + +CREATE INDEX IF NOT EXISTS members_by_address ON members (network, address); + +CREATE TABLE IF NOT EXISTS assets ( + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + coin_type TEXT NOT NULL, + approved BOOLEAN NOT NULL DEFAULT false, + low_max NUMERIC(39,0) NOT NULL DEFAULT 0, + high_max NUMERIC(39,0) NOT NULL DEFAULT 0, + per_tx_max NUMERIC(39,0) NOT NULL DEFAULT 0, + daily_max NUMERIC(39,0) NOT NULL DEFAULT 0, + balance NUMERIC(39,0) NOT NULL DEFAULT 0, + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + PRIMARY KEY (network, vault_id, coin_type) +); + +CREATE TABLE IF NOT EXISTS proposals ( + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + proposal_id BIGINT NOT NULL, + kind SMALLINT NOT NULL, + status SMALLINT NOT NULL, + proposer TEXT NOT NULL, + coin_type TEXT, + amount NUMERIC(39,0) NOT NULL DEFAULT 0, + recipient TEXT, + memo TEXT NOT NULL DEFAULT '', + tier SMALLINT NOT NULL DEFAULT 0, + reasons INTEGER NOT NULL DEFAULT 0, + exposure_bps INTEGER NOT NULL DEFAULT 0, + req_approvals SMALLINT NOT NULL DEFAULT 0, + req_guardians SMALLINT NOT NULL DEFAULT 0, + approvals INTEGER NOT NULL DEFAULT 0, + confirmations INTEGER NOT NULL DEFAULT 0, + reduction_mask INTEGER NOT NULL DEFAULT 0, + opened_at TIMESTAMPTZ NOT NULL, + executable_at TIMESTAMPTZ NOT NULL, + expires_at TIMESTAMPTZ NOT NULL, + settled_at TIMESTAMPTZ, + PRIMARY KEY (network, vault_id, proposal_id) +); + +CREATE INDEX IF NOT EXISTS proposals_pending ON proposals (network, vault_id, status, executable_at); +CREATE INDEX IF NOT EXISTS proposals_recipient ON proposals (network, recipient) WHERE recipient IS NOT NULL; + +CREATE TABLE IF NOT EXISTS proposal_votes ( + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + proposal_id BIGINT NOT NULL, + voter TEXT NOT NULL, + kind TEXT NOT NULL CHECK (kind IN ('approval', 'confirmation')), + voted_at TIMESTAMPTZ NOT NULL, + PRIMARY KEY (network, vault_id, proposal_id, voter, kind) +); + +CREATE TABLE IF NOT EXISTS recipients ( + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + address TEXT NOT NULL, + label TEXT NOT NULL DEFAULT '', + trust SMALLINT NOT NULL DEFAULT 0, + activates_at TIMESTAMPTZ, + paid_count INTEGER NOT NULL DEFAULT 0, + total_paid NUMERIC(39,0) NOT NULL DEFAULT 0, + first_seen TIMESTAMPTZ NOT NULL DEFAULT now(), + last_paid TIMESTAMPTZ, + PRIMARY KEY (network, vault_id, address) +); + +-- Cross-vault reputation: how many distinct vaults have paid this address, and for how long. +-- This is the one genuinely off-chain signal, and it is advisory only. No contract reads it. +CREATE TABLE IF NOT EXISTS recipient_reputation ( + network TEXT NOT NULL, + address TEXT NOT NULL, + vault_count INTEGER NOT NULL DEFAULT 0, + payment_count INTEGER NOT NULL DEFAULT 0, + first_seen TIMESTAMPTZ NOT NULL, + last_seen TIMESTAMPTZ NOT NULL, + blocked_by INTEGER NOT NULL DEFAULT 0, + PRIMARY KEY (network, address) +); + +-- Who gets told what. A subscription is per address and per vault, because a guardian wants the +-- vetoable things and an approver wants the queue. +CREATE TABLE IF NOT EXISTS subscriptions ( + id BIGSERIAL PRIMARY KEY, + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + address TEXT NOT NULL, + channel TEXT NOT NULL CHECK (channel IN ('webhook', 'email', 'log')), + endpoint TEXT NOT NULL, + events TEXT[] NOT NULL DEFAULT '{}', + secret TEXT, + active BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + UNIQUE (network, vault_id, address, channel, endpoint) +); + +CREATE TABLE IF NOT EXISTS notifications ( + id BIGSERIAL PRIMARY KEY, + subscription_id BIGINT NOT NULL REFERENCES subscriptions(id) ON DELETE CASCADE, + network TEXT NOT NULL, + vault_id TEXT NOT NULL, + -- The event that caused it, so a replayed event cannot send a second notification. + tx_digest TEXT NOT NULL, + event_index INTEGER NOT NULL, + rule TEXT NOT NULL, + title TEXT NOT NULL, + body TEXT NOT NULL, + severity TEXT NOT NULL CHECK (severity IN ('info', 'action', 'alert')), + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + delivered_at TIMESTAMPTZ, + attempts INTEGER NOT NULL DEFAULT 0, + last_error TEXT, + UNIQUE (subscription_id, tx_digest, event_index, rule) +); + +CREATE INDEX IF NOT EXISTS notifications_undelivered + ON notifications (created_at) WHERE delivered_at IS NULL; diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..1c8872a --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,2795 @@ +{ + "name": "@skur/server", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@skur/server", + "version": "0.1.0", + "dependencies": { + "@skur/sdk": "file:../sdk", + "express": "^5.1.0", + "pg": "^8.16.3" + }, + "devDependencies": { + "@types/express": "^5.0.3", + "@types/node": "^24.13.3", + "@types/pg": "^8.15.5", + "typescript": "~6.0.2", + "vitest": "^3.2.7" + } + }, + "../sdk": { + "name": "@skur/sdk", + "version": "0.1.0", + "dependencies": { + "@mysten/sui": "^2.34.0" + }, + "devDependencies": { + "typescript": "~6.0.2", + "vitest": "^3.2.7" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.64.0.tgz", + "integrity": "sha512-FLLpX941CD/7aBvX3GqLGBM9OvY5PGXTryPJkG5r5/OuBpZpV5k45Uo3RxAvqd35tsyc3hH1bhtz921IKzoIzg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.64.0.tgz", + "integrity": "sha512-iI32XM/jnDYJsvx5ai/za/7gWO9XoSeFFtU06/ZCaRgyilfJOjaopD3nOpk2WrTCGOyeDt4hleUiGOAnd5tHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.64.0.tgz", + "integrity": "sha512-dRBZlbt2sEtF8Mn4MODThze9fIPdDoOhVSlXMAKy5dQbOYK9pOOoPY4Fat3OTtr0+8zbJo5TTZwlsfxY/kDNJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.64.0.tgz", + "integrity": "sha512-Y3whrJOMucfkhgNkvcM93M6j8C53iEAMmPMYD99C6G1kUy4ELigLWk9ar2/4aCBSRgsql0zdlOemLgW2m5GZgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.64.0.tgz", + "integrity": "sha512-S6S1GEzPjFF6IONYJX3AKt/799+8RgBgCcwRnUo+Ep1IvBxUbw5M51iU0TDdK2NWWVnSvCQ8yi6Em0fGASMOng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.64.0.tgz", + "integrity": "sha512-Ed1DPoFENkXj4IGzSB12SesV40iP6LxCCrbTIkSGIQBpOOxpBM+0kj62lmaeIHfMWTDoddqTOtqc7s8LYfn+Pw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.64.0.tgz", + "integrity": "sha512-J/6xhutJPtFyIkmHdf4olOdHHKH5kOJNumojdWn+Elv5ICEYTVOa362Vw27TxsK0BLzb1le3EDlO3UbvFK1lnQ==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.64.0.tgz", + "integrity": "sha512-G4L/Nnx59d2LvDoV/P4S5lZ7oVLT6hodOHMacqjiq2LL2gts86KbkEBTYL53+fBt0odhf7XPIbIATGoYiJctxg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.64.0.tgz", + "integrity": "sha512-zF16pvJDEUksGYRbfnXne7pdklAyj2XDmJeYKgP93oq0cUyX9Y8O7lUo1R+IY1GagP/YBvCEDCe7eEcAKpw//g==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.64.0.tgz", + "integrity": "sha512-nIggWn8n+w12+R5lsV+PYYoUY8vuObxPAQqJI7WES+9v0qspYuAHoZMfYM0yLxlipasT5BY9ht5W8t5c/rSCkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.64.0.tgz", + "integrity": "sha512-WLOTiHPzszP0dxIMsHpFeDSOSB5I49Mj8K4+yKE3H1X/D0JRG5XZ5jrctJLMjnUc/LUzaKiwq6EHWNJ8pup8PA==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.64.0.tgz", + "integrity": "sha512-35RK9aRhh7g7Pmeu5gQ01aCvrhXzj9LoBE6xtUcEH1ns+nyTaSzxSpADmBQINu4QiTDGvmQYwo1j5hlg1rRXFw==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.64.0.tgz", + "integrity": "sha512-RqTfnpoTjuWfPAmqK5p2edt2AMCDJWm6oTn7sKfmyx+6tRga0ip05SJ977o6udTcIiDeF/CJMUfkaN4gtWt6Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.64.0.tgz", + "integrity": "sha512-RQjZPigjxFvFZDijG6rjlSXxhRaTf9zLYVpGK+lVcga64oMqP1GbgVqCb46eHTTceSIgp89Ja0y5aPe3GFBYHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.64.0.tgz", + "integrity": "sha512-tjL58mgQcTRnDRpeky+Sth1MKQeYi2Ct6r3Luq9E5aTSjnM/i/JbozqZkKqp9thM5+oDSZxo+05f9kdQedfTGA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.64.0.tgz", + "integrity": "sha512-ictoRyVaoZ8C67myHef+8hhCa6IplXJJ/xUCkVCxziV4zxMZh+jvhkhGsPBLqj1S72fnqD0QH5zL4lcaa4X7DQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.64.0.tgz", + "integrity": "sha512-8aVvZ2hfr9RLFzBQkQNmYeHLDja8fLeQAmLt757zdKN/B+8L809KlLJKctQjS22wZotptV8G6o7fVPuAs8S1tQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.64.0.tgz", + "integrity": "sha512-2dEF8GAcDKwshUfydD+GhosppNyBzhVUHkdFF3CXd3FpOkzj/RZzF5aoEtzklujklT5qFVRU2GK/cFeLaTNKVg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.64.0.tgz", + "integrity": "sha512-3XHTvoo2hKkh0MiOfS7SkhHjMaaWF7P4F3drocZZaho/Z8w7h/jpnuBHm91BOQLfvrKHs1yR+zir4E8RI3XzTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.64.0.tgz", + "integrity": "sha512-HKtkzodL4a3KFWDXDoO61cRynAWTR3LnAE0oGtfG9lcNFpNuVYUFOByxDgNqEvic9rvaQbAj+SFwTEWDptRaIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.64.0.tgz", + "integrity": "sha512-JBsxqiY16uyyCujtoC3s7zL+SrYyNElptD7K4V+KUoJ2V8/XG3hPWpheK+SuPwNh1cikJvIZmIdsrYXvD6PLJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.64.0.tgz", + "integrity": "sha512-S5Qrijh37qhnUYQ0ay8WN3LuWeKjow7wTUyCOPMZtnXiBXYXdsZETI6ZLfYnQAKovltckPLBFdNeD61P2rJc7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.64.0.tgz", + "integrity": "sha512-zbZ6iMmLFEsCtTdc2/y1F/cDFVNNCPF7Ae8PCT/wdPE//hGwYp6r+MyCLMFX+kOeIe09Pz6ASfnnfpSTN1FJQQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.64.0.tgz", + "integrity": "sha512-L6Hw69oNpuYaOr1zCG30v0/DqKYCSRwodPGwIcVZ/6f8SOzq9rxtL/xNVI5MO4wjli+Ko0ErK9uHJL3mNPt8wQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.64.0.tgz", + "integrity": "sha512-nl+CTWIgOGszQmUz/kanfgrfFZ4qiwxKIfT/ryl3N3Ewk5tqizmYtNXiqb7Bu/fDtNgu1kyxdFiAUJNur3iysg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@skur/sdk": { + "resolved": "../sdk", + "link": true + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz", + "integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.19.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.1.tgz", + "integrity": "sha512-aS3/DG0oM05K0RIXXP+hKjinGG5IgSSVGzswZxW3O0sS3pH4/fycXundUC9XsszgKCk4gHXylTEK6hyFxVxnoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/pg": { + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.23.1.tgz", + "integrity": "sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", + "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", + "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.7", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", + "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", + "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.7", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", + "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", + "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", + "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.7", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/negotiator/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pg": { + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.23.1.tgz", + "integrity": "sha512-aL96AHANtWjPLDOLqnhx+ngp9+UK7ETEU8VJrDCGvsSSi/mGLcWYsS6Herg7lmaBJe4uwrfqsa7gTEFaSizDoQ==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.14.1", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.16.1", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.1.tgz", + "integrity": "sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.1.tgz", + "integrity": "sha512-qR3kGNPBLpCNtz0evbKA0Y/MRFXwSSdT+pTJvYp/bXTcReZbvX1kzF0IyTc1QnxqF7AZbOeBhNL8R5mYQZV/MA==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.16.1.tgz", + "integrity": "sha512-p9VOFMiHB/ZbJATetbg+99PxssTVSQRnyuPSQ67mN1+1KBOjZaZ83ZQzltnxPhJwSsC3nwVjJ10DVJlerbFzLg==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/rollup": { + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.64.0.tgz", + "integrity": "sha512-gjA/kFeDfffII8COoPsvLPvE16hWDTEc1+0QKQNKUkuV8iJjqsC4xXs8/FzuL0v9EV39kuxTbAgcFoTRyy2TGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.64.0", + "@rollup/rollup-android-arm64": "4.64.0", + "@rollup/rollup-darwin-arm64": "4.64.0", + "@rollup/rollup-darwin-x64": "4.64.0", + "@rollup/rollup-freebsd-arm64": "4.64.0", + "@rollup/rollup-freebsd-x64": "4.64.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.64.0", + "@rollup/rollup-linux-arm-musleabihf": "4.64.0", + "@rollup/rollup-linux-arm64-gnu": "4.64.0", + "@rollup/rollup-linux-arm64-musl": "4.64.0", + "@rollup/rollup-linux-loong64-gnu": "4.64.0", + "@rollup/rollup-linux-loong64-musl": "4.64.0", + "@rollup/rollup-linux-ppc64-gnu": "4.64.0", + "@rollup/rollup-linux-ppc64-musl": "4.64.0", + "@rollup/rollup-linux-riscv64-gnu": "4.64.0", + "@rollup/rollup-linux-riscv64-musl": "4.64.0", + "@rollup/rollup-linux-s390x-gnu": "4.64.0", + "@rollup/rollup-linux-x64-gnu": "4.64.0", + "@rollup/rollup-linux-x64-musl": "4.64.0", + "@rollup/rollup-openbsd-x64": "4.64.0", + "@rollup/rollup-openharmony-arm64": "4.64.0", + "@rollup/rollup-win32-arm64-msvc": "4.64.0", + "@rollup/rollup-win32-ia32-msvc": "4.64.0", + "@rollup/rollup-win32-x64-gnu": "4.64.0", + "@rollup/rollup-win32-x64-msvc": "4.64.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz", + "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", + "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.7", + "@vitest/mocker": "3.2.7", + "@vitest/pretty-format": "^3.2.7", + "@vitest/runner": "3.2.7", + "@vitest/snapshot": "3.2.7", + "@vitest/spy": "3.2.7", + "@vitest/utils": "3.2.7", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.7", + "@vitest/ui": "3.2.7", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..ecdef43 --- /dev/null +++ b/server/package.json @@ -0,0 +1,26 @@ +{ + "name": "@skur/server", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "node --experimental-strip-types --watch src/main.ts", + "start": "node --experimental-strip-types src/main.ts", + "migrate": "node --experimental-strip-types src/migrate.ts", + "index": "node --experimental-strip-types src/indexer.ts", + "typecheck": "tsc --noEmit", + "test": "vitest run" + }, + "dependencies": { + "@skur/sdk": "file:../sdk", + "express": "^5.1.0", + "pg": "^8.16.3" + }, + "devDependencies": { + "@types/express": "^5.0.3", + "@types/node": "^24.13.3", + "@types/pg": "^8.15.5", + "typescript": "~6.0.2", + "vitest": "^3.2.7" + } +} diff --git a/server/src/advisory.ts b/server/src/advisory.ts new file mode 100644 index 0000000..781f609 --- /dev/null +++ b/server/src/advisory.ts @@ -0,0 +1,216 @@ +import { + DAY, + Mode, + Trust, + computeMaxLoss, + fmtDuration, + postureItems, + type AssetLimits, + type Policy, +} from '@skur/sdk'; +import { fromNumeric, pool } from './db.ts'; + +/** + * The off-chain policy services. + * + * These are advisory by design. Nothing here can approve, delay or refuse a payment — the vault + * does that, from its own state, and a backend that could override it would be the single point of + * failure the whole product exists to remove. What a backend can do is see across vaults and + * across time, which no single vault object can, and tell a human something useful before they + * sign. + */ + +export type RecipientAdvisory = { + address: string; + /** Trust as the vault records it. */ + trust: Trust; + knownForMs: number; + paymentsFromThisVault: number; + /** How many other vaults on this network have paid it. */ + otherVaults: number; + /** How many vaults have restricted or blocked it. */ + restrictedBy: number; + flags: string[]; + /** Short sentence for a confirmation screen. */ + summary: string; +}; + +export async function recipientAdvisory( + network: string, + vaultId: string, + address: string, +): Promise { + const { rows: local } = await pool.query<{ + trust: number; + paid_count: number; + first_seen: Date; + activates_at: Date | null; + }>( + `SELECT trust, paid_count, first_seen, activates_at + FROM recipients WHERE network = $1 AND vault_id = $2 AND address = $3`, + [network, vaultId, address], + ); + const { rows: rep } = await pool.query<{ + vault_count: number; + payment_count: number; + first_seen: Date; + blocked_by: number; + }>( + `SELECT vault_count, payment_count, first_seen, blocked_by + FROM recipient_reputation WHERE network = $1 AND address = $2`, + [network, address], + ); + + const r = local[0]; + const g = rep[0]; + const now = Date.now(); + const knownForMs = r ? now - r.first_seen.getTime() : g ? now - g.first_seen.getTime() : 0; + const trust = (r?.trust ?? Trust.UNKNOWN) as Trust; + const paymentsFromThisVault = r?.paid_count ?? 0; + const otherVaults = Math.max((g?.vault_count ?? 0) - (paymentsFromThisVault > 0 ? 1 : 0), 0); + const restrictedBy = g?.blocked_by ?? 0; + + const flags: string[] = []; + if (trust === Trust.UNKNOWN) flags.push('This vault has never paid this address.'); + if (trust === Trust.BLOCKED) flags.push('This address is blocked by this vault.'); + if (trust === Trust.RESTRICTED) flags.push('This address is restricted by this vault.'); + if (r?.activates_at && r.activates_at.getTime() > now) { + flags.push(`Still activating, for another ${fmtDuration(r.activates_at.getTime() - now)}.`); + } + if (restrictedBy > 0) { + flags.push( + `${restrictedBy} vault${restrictedBy === 1 ? '' : 's'} on this network have restricted or blocked it.`, + ); + } + if (knownForMs > 0 && knownForMs < DAY) flags.push('First seen less than a day ago.'); + if (paymentsFromThisVault === 0 && otherVaults > 0) { + flags.push(`Paid by ${otherVaults} other vault${otherVaults === 1 ? '' : 's'}, but not by this one.`); + } + + const summary = flags.length + ? flags[0] + : paymentsFromThisVault > 0 + ? `Paid ${paymentsFromThisVault} time${paymentsFromThisVault === 1 ? '' : 's'} before, first seen ${fmtDuration(knownForMs)} ago.` + : 'Nothing known about this address.'; + + return { + address, + trust, + knownForMs, + paymentsFromThisVault, + otherVaults, + restrictedBy, + flags, + summary, + }; +} + +/** + * Outflow against the envelope, from the indexed history rather than the chain, so a dashboard + * can show the trend without a round trip per asset. + */ +export type OutflowWindow = { + coinType: string; + spentInWindow: bigint; + envelopeLimit: bigint; + /** 0 to 10,000. */ + usedBps: number; + dailyCap: bigint; + spentToday: bigint; +}; + +export async function outflow( + network: string, + vaultId: string, + policy: Policy, +): Promise { + const windowStart = new Date(Date.now() - (policy.envelopeWindow || DAY)); + const dayStart = new Date(Date.now() - DAY); + const { rows } = await pool.query<{ + coin_type: string; + balance: string; + daily_max: string; + in_window: string | null; + today: string | null; + }>( + `SELECT a.coin_type, + a.balance, + a.daily_max, + (SELECT sum(p.amount) FROM proposals p + WHERE p.network = a.network AND p.vault_id = a.vault_id + AND p.coin_type = a.coin_type AND p.status = 2 AND p.settled_at >= $3) AS in_window, + (SELECT sum(p.amount) FROM proposals p + WHERE p.network = a.network AND p.vault_id = a.vault_id + AND p.coin_type = a.coin_type AND p.status = 2 AND p.settled_at >= $4) AS today + FROM assets a + WHERE a.network = $1 AND a.vault_id = $2 AND a.approved`, + [network, vaultId, windowStart, dayStart], + ); + + return rows.map((row) => { + const balance = fromNumeric(row.balance); + const spent = fromNumeric(row.in_window); + // Measured against the balance plus what already left, which approximates the basis the + // contract pinned when the window opened. The contract's own number is authoritative. + const basis = balance + spent; + const limit = policy.envelopeBps === 0 ? 0n : (basis * BigInt(policy.envelopeBps)) / 10_000n; + return { + coinType: row.coin_type, + spentInWindow: spent, + envelopeLimit: limit, + usedBps: limit === 0n ? 0 : Number((spent * 10_000n) / limit), + dailyCap: fromNumeric(row.daily_max), + spentToday: fromNumeric(row.today), + }; + }); +} + +/** The posture report and the maximum-loss numbers, computed from indexed state. */ +export async function riskReport(network: string, vaultId: string, policy: Policy) { + const { rows } = await pool.query<{ + coin_type: string; + approved: boolean; + low_max: string; + high_max: string; + per_tx_max: string; + daily_max: string; + balance: string; + }>( + `SELECT coin_type, approved, low_max, high_max, per_tx_max, daily_max, balance + FROM assets WHERE network = $1 AND vault_id = $2`, + [network, vaultId], + ); + const { rows: vrows } = await pool.query<{ mode: number; guardians: string }>( + `SELECT v.mode, + (SELECT count(*) FROM members m + WHERE m.network = v.network AND m.vault_id = v.vault_id AND (m.roles & 8) <> 0) AS guardians + FROM vaults v WHERE v.network = $1 AND v.vault_id = $2`, + [network, vaultId], + ); + const mode = (vrows[0]?.mode ?? Mode.NORMAL) as Mode; + const guardians = Number(vrows[0]?.guardians ?? 0); + + const assets = rows.map((r) => ({ + coinType: r.coin_type, + limits: { + approved: r.approved, + lowMax: fromNumeric(r.low_max), + highMax: fromNumeric(r.high_max), + perTxMax: fromNumeric(r.per_tx_max), + dailyMax: fromNumeric(r.daily_max), + } satisfies AssetLimits, + balance: fromNumeric(r.balance), + })); + + return { + posture: postureItems({ + policy, + guardians, + assets: assets.map((a) => ({ symbol: a.coinType, limits: a.limits })), + }), + maxLoss: assets.map((a) => ({ + coinType: a.coinType, + ...computeMaxLoss(policy, a.limits, a.balance, mode), + })), + }; +} diff --git a/server/src/api.ts b/server/src/api.ts new file mode 100644 index 0000000..8d39c9f --- /dev/null +++ b/server/src/api.ts @@ -0,0 +1,223 @@ +import express, { type Request, type Response } from 'express'; +import { fetchVault, grpcClient, Status } from '@skur/sdk'; +import { config } from './config.ts'; +import { fromNumeric, pool } from './db.ts'; +import { describeWait } from './notify.ts'; +import { outflow, recipientAdvisory, riskReport } from './advisory.ts'; + +/** + * The read API. + * + * Deliberately read-only and deliberately not required: every endpoint here answers a question + * faster than the chain can, and none of them answers one the chain cannot. An interface that + * loses this service shows a slower dashboard; it does not lose the ability to move money, read + * the policy or approve a payment. That is the test every endpoint had to pass. + */ +const client = grpcClient(config.network, config.grpcUrl); + +/** bigint does not survive JSON.stringify, and silently throwing on it is worse than a string. */ +function send(res: Response, body: unknown) { + res.type('application/json').send( + JSON.stringify(body, (_, v) => (typeof v === 'bigint' ? v.toString() : v)), + ); +} + +/** Express 5 types a route parameter as possibly repeated; these routes take exactly one. */ +function param(req: Request, name: string): string { + const v = req.params[name]; + return Array.isArray(v) ? (v[0] ?? '') : (v ?? ''); +} + +function wrap(fn: (req: Request, res: Response) => Promise) { + return (req: Request, res: Response) => { + fn(req, res).catch((e: unknown) => { + const message = e instanceof Error ? e.message : String(e); + res.status(500); + send(res, { error: message }); + }); + }; +} + +export function makeApi() { + const app = express(); + app.use(express.json()); + + app.get('/health', wrap(async (_req, res) => { + const { rows } = await pool.query<{ cursor: string | null; events_seen: string; last_event_at: Date | null }>( + `SELECT cursor, events_seen, last_event_at FROM indexer_cursor WHERE network = $1`, + [config.network], + ); + send(res, { + ok: true, + network: config.network, + packageId: config.packageId, + indexer: rows[0] ?? null, + }); + })); + + app.get('/vaults', wrap(async (_req, res) => { + const { rows } = await pool.query( + `SELECT v.vault_id, v.name, v.mode, v.policy_version, v.created_at, + (SELECT count(*) FROM members m WHERE m.network = v.network AND m.vault_id = v.vault_id) AS members, + (SELECT count(*) FROM proposals p + WHERE p.network = v.network AND p.vault_id = v.vault_id AND p.status = $2) AS pending + FROM vaults v WHERE v.network = $1 ORDER BY v.created_at DESC`, + [config.network, Status.PENDING], + ); + send(res, { vaults: rows }); + })); + + /** Vaults an address is a member of, which is how an interface finds "my vaults". */ + app.get('/members/:address/vaults', wrap(async (req, res) => { + const { rows } = await pool.query( + `SELECT m.vault_id, m.roles, v.name, v.mode + FROM members m JOIN vaults v + ON v.network = m.network AND v.vault_id = m.vault_id + WHERE m.network = $1 AND m.address = $2 + ORDER BY v.created_at DESC`, + [config.network, param(req, 'address')], + ); + send(res, { vaults: rows }); + })); + + app.get('/vaults/:id', wrap(async (req, res) => { + // The policy is read from the chain, never from the projection: it is the thing that decides, + // and a stale copy of it is worse than no copy. + const onchain = await fetchVault(client, param(req, 'id')); + const { rows: members } = await pool.query( + `SELECT address, roles FROM members WHERE network = $1 AND vault_id = $2 ORDER BY roles DESC`, + [config.network, param(req, 'id')], + ); + const { rows: assets } = await pool.query( + `SELECT coin_type, approved, low_max, high_max, per_tx_max, daily_max, balance + FROM assets WHERE network = $1 AND vault_id = $2 ORDER BY coin_type`, + [config.network, param(req, 'id')], + ); + send(res, { vault: onchain, members, assets }); + })); + + app.get('/vaults/:id/proposals', wrap(async (req, res) => { + const limit = Math.min(Number(req.query.limit ?? 50), 200); + const status = req.query.status === undefined ? null : Number(req.query.status); + const { rows } = await pool.query( + `SELECT * FROM proposals + WHERE network = $1 AND vault_id = $2 AND ($3::int IS NULL OR status = $3) + ORDER BY proposal_id DESC LIMIT $4`, + [config.network, param(req, 'id'), status, limit], + ); + send(res, { + proposals: rows.map((p) => ({ + ...p, + amount: fromNumeric(p.amount as string), + wait: p.status === Status.PENDING ? describeWait(new Date(p.executable_at as string).getTime()) : null, + })), + }); + })); + + /** The queue, from the point of view of one signer: what is waiting on them specifically. */ + app.get('/vaults/:id/queue/:address', wrap(async (req, res) => { + const { rows } = await pool.query( + `SELECT p.*, + EXISTS (SELECT 1 FROM proposal_votes v + WHERE v.network = p.network AND v.vault_id = p.vault_id + AND v.proposal_id = p.proposal_id AND v.voter = $3) AS voted, + coalesce((SELECT m.roles FROM members m + WHERE m.network = p.network AND m.vault_id = p.vault_id + AND m.address = $3), 0) AS roles + FROM proposals p + WHERE p.network = $1 AND p.vault_id = $2 AND p.status = $4 + ORDER BY p.opened_at DESC`, + [config.network, param(req, 'id'), param(req, 'address'), Status.PENDING], + ); + send(res, { + proposals: rows.map((p) => ({ + ...p, + amount: fromNumeric(p.amount as string), + needsYou: + !p.voted && + ((p.kind === 0 && (Number(p.roles) & 2) !== 0) || + (p.kind !== 0 && (Number(p.roles) & 1) !== 0) || + (Number(p.req_guardians) > 0 && (Number(p.roles) & 8) !== 0)), + })), + }); + })); + + app.get('/vaults/:id/events', wrap(async (req, res) => { + const limit = Math.min(Number(req.query.limit ?? 100), 500); + const { rows } = await pool.query( + `SELECT tx_digest, event_index, name, occurred_at, payload + FROM events WHERE network = $1 AND vault_id = $2 + ORDER BY occurred_at DESC, event_index DESC LIMIT $3`, + [config.network, param(req, 'id'), limit], + ); + send(res, { events: rows }); + })); + + app.get('/vaults/:id/recipients', wrap(async (req, res) => { + const { rows } = await pool.query( + `SELECT address, label, trust, activates_at, paid_count, total_paid, last_paid + FROM recipients WHERE network = $1 AND vault_id = $2 ORDER BY last_paid DESC NULLS LAST`, + [config.network, param(req, 'id')], + ); + send(res, { + recipients: rows.map((r) => ({ ...r, total_paid: fromNumeric(r.total_paid as string) })), + }); + })); + + /** The advisory a confirmation screen should show before anyone signs. */ + app.get('/vaults/:id/recipients/:address/advisory', wrap(async (req, res) => { + send(res, await recipientAdvisory(config.network, param(req, 'id'), param(req, 'address'))); + })); + + app.get('/vaults/:id/outflow', wrap(async (req, res) => { + const vault = await fetchVault(client, param(req, 'id')); + send(res, { outflow: await outflow(config.network, param(req, 'id'), vault.policy) }); + })); + + app.get('/vaults/:id/risk', wrap(async (req, res) => { + const vault = await fetchVault(client, param(req, 'id')); + send(res, await riskReport(config.network, param(req, 'id'), vault.policy)); + })); + + /** Subscribe an address to notifications for a vault. */ + app.post('/subscriptions', wrap(async (req, res) => { + const { vaultId, address, channel, endpoint, events, secret } = req.body ?? {}; + if (!vaultId || !address || !channel || !endpoint) { + res.status(400); + send(res, { error: 'vaultId, address, channel and endpoint are required' }); + return; + } + if (!['webhook', 'email', 'log'].includes(channel)) { + res.status(400); + send(res, { error: 'channel must be webhook, email or log' }); + return; + } + const { rows } = await pool.query( + `INSERT INTO subscriptions (network, vault_id, address, channel, endpoint, events, secret) + VALUES ($1,$2,$3,$4,$5,$6,$7) + ON CONFLICT (network, vault_id, address, channel, endpoint) DO UPDATE + SET events = EXCLUDED.events, secret = EXCLUDED.secret, active = true + RETURNING id`, + [config.network, vaultId, address, channel, endpoint, events ?? [], secret ?? null], + ); + send(res, { id: rows[0].id }); + })); + + app.delete('/subscriptions/:id', wrap(async (req, res) => { + await pool.query(`UPDATE subscriptions SET active = false WHERE id = $1`, [param(req, 'id')]); + send(res, { ok: true }); + })); + + app.get('/subscriptions/:address/notifications', wrap(async (req, res) => { + const { rows } = await pool.query( + `SELECT n.id, n.vault_id, n.rule, n.title, n.body, n.severity, n.created_at, n.delivered_at + FROM notifications n JOIN subscriptions s ON s.id = n.subscription_id + WHERE s.network = $1 AND s.address = $2 + ORDER BY n.created_at DESC LIMIT 100`, + [config.network, param(req, 'address')], + ); + send(res, { notifications: rows }); + })); + + return app; +} diff --git a/server/src/config.ts b/server/src/config.ts new file mode 100644 index 0000000..cd2feab --- /dev/null +++ b/server/src/config.ts @@ -0,0 +1,18 @@ +import type { Network } from '@skur/sdk'; + +function required(name: string): string { + const v = process.env[name]; + if (!v) throw new Error(`${name} is not set; copy .env.example and fill it in`); + return v; +} + +export const config = { + databaseUrl: required('DATABASE_URL'), + network: (process.env.SKUR_NETWORK ?? 'testnet') as Network, + packageId: required('SKUR_PACKAGE_ID'), + grpcUrl: process.env.SKUR_GRPC_URL, + indexIntervalMs: Number(process.env.INDEX_INTERVAL_MS ?? 4000), + port: Number(process.env.PORT ?? 8787), + /** Page size for each pass of the indexer. */ + batchSize: Number(process.env.INDEX_BATCH ?? 50), +}; diff --git a/server/src/db.ts b/server/src/db.ts new file mode 100644 index 0000000..b40659d --- /dev/null +++ b/server/src/db.ts @@ -0,0 +1,35 @@ +import { Pool, type PoolClient } from 'pg'; +import { config } from './config.ts'; + +export const pool = new Pool({ connectionString: config.databaseUrl, max: 10 }); + +/** Run a unit of work in one transaction, rolling back on any throw. */ +export async function withTx(fn: (c: PoolClient) => Promise): Promise { + const c = await pool.connect(); + try { + await c.query('BEGIN'); + const out = await fn(c); + await c.query('COMMIT'); + return out; + } catch (e) { + await c.query('ROLLBACK'); + throw e; + } finally { + c.release(); + } +} + +/** Postgres has no u64, and amounts can exceed a double. NUMERIC in, bigint out. */ +export function toNumeric(v: bigint): string { + return v.toString(); +} + +export function fromNumeric(v: string | number | null | undefined): bigint { + if (v === null || v === undefined) return 0n; + return BigInt(String(v).split('.')[0]); +} + +/** Move timestamps are milliseconds since the epoch. */ +export function toTimestamp(ms: number): Date { + return new Date(ms); +} diff --git a/server/src/indexer.ts b/server/src/indexer.ts new file mode 100644 index 0000000..ccafbc6 --- /dev/null +++ b/server/src/indexer.ts @@ -0,0 +1,113 @@ +import { grpcClient, listVaultEvents } from '@skur/sdk'; +import { config } from './config.ts'; +import { pool, withTx } from './db.ts'; +import { ensureVault, project } from './project.ts'; +import { deliverPending, queueNotifications } from './notify.ts'; + +/** + * The indexer. + * + * It walks the package's events forwards from a stored cursor, projects each one, queues whatever + * notifications it implies, and only then advances the cursor — so a crash re-reads a batch rather + * than skipping it, and every write is idempotent on the event's ledger position to make that + * safe. + * + * Transport is gRPC. `hasNextPage` can be true with an empty page because a gRPC server bounds how + * much ledger one request scans, so the loop keeps going while the server says there is more + * rather than stopping on an empty result. + */ +const client = grpcClient(config.network, config.grpcUrl); + +async function readCursor(): Promise { + const { rows } = await pool.query<{ cursor: string | null }>( + `SELECT cursor FROM indexer_cursor WHERE network = $1`, + [config.network], + ); + if (rows.length === 0) { + await pool.query(`INSERT INTO indexer_cursor (network) VALUES ($1)`, [config.network]); + return null; + } + return rows[0].cursor; +} + +export async function indexOnce(): Promise<{ events: number; notifications: number; done: boolean }> { + const cursor = await readCursor(); + const page = await listVaultEvents(client, { + packageId: config.packageId, + limit: config.batchSize, + // No cursor yet means the start of the package's history, read oldest first. + ...(cursor ? { after: cursor } : { order: 'ascending' as const }), + }); + + if (page.events.length === 0) { + if (page.hasNextPage && page.endCursor) { + // A scan-limited page: nothing matched in the range read, but moving the cursor makes + // progress rather than reading the same empty range forever. + await pool.query( + `UPDATE indexer_cursor SET cursor = $2, updated_at = now() WHERE network = $1`, + [config.network, page.endCursor], + ); + } + return { events: 0, notifications: 0, done: !page.hasNextPage }; + } + + const notifications = await withTx(async (c) => { + let queued = 0; + for (const decoded of page.events) { + await ensureVault(c, config.network, decoded.event); + // `events` is the idempotency gate: if the row is already there, this event has been + // applied and its counters must not be moved again. + const seen = await c.query( + `SELECT 1 FROM events WHERE network = $1 AND tx_digest = $2 AND event_index = $3`, + [config.network, decoded.position.transactionDigest, decoded.position.eventIndex], + ); + if (seen.rowCount) continue; + await project(c, config.network, decoded); + queued += await queueNotifications(c, config.network, decoded); + } + const last = page.events[page.events.length - 1]; + await c.query( + `UPDATE indexer_cursor + SET cursor = $2, last_event_at = $3, events_seen = events_seen + $4, updated_at = now() + WHERE network = $1`, + [ + config.network, + page.endCursor, + new Date(last.event.at), + page.events.length, + ], + ); + return queued; + }); + + return { events: page.events.length, notifications, done: !page.hasNextPage }; +} + +/** Catch up to the tip, then poll. */ +export async function runIndexer(signal?: AbortSignal) { + console.log(`indexing ${config.packageId} on ${config.network}`); + while (!signal?.aborted) { + try { + let done = false; + while (!done && !signal?.aborted) { + const r = await indexOnce(); + done = r.done; + if (r.events) { + console.log(`+${r.events} events, ${r.notifications} notifications queued`); + } + } + const sent = await deliverPending(); + if (sent) console.log(`delivered ${sent} notifications`); + } catch (e) { + console.error('index pass failed:', e instanceof Error ? e.message : e); + } + await new Promise((r) => setTimeout(r, config.indexIntervalMs)); + } +} + +if (import.meta.url === `file://${process.argv[1]}`) { + const ac = new AbortController(); + process.on('SIGINT', () => ac.abort()); + process.on('SIGTERM', () => ac.abort()); + runIndexer(ac.signal).then(() => pool.end()); +} diff --git a/server/src/main.ts b/server/src/main.ts new file mode 100644 index 0000000..9f2955c --- /dev/null +++ b/server/src/main.ts @@ -0,0 +1,25 @@ +import { config } from './config.ts'; +import { pool } from './db.ts'; +import { makeApi } from './api.ts'; +import { runIndexer } from './indexer.ts'; + +/** + * One process runs both the indexer and the read API. They share a pool and a cursor, and keeping + * them together means a deployment cannot end up with an API serving a store nothing is filling. + * Split them when there is a reason to; `npm run index` already runs the indexer alone. + */ +const ac = new AbortController(); +const server = makeApi().listen(config.port, () => { + console.log(`api on :${config.port} (${config.network})`); +}); + +runIndexer(ac.signal); + +async function shutdown() { + ac.abort(); + server.close(); + await pool.end(); + process.exit(0); +} +process.on('SIGINT', shutdown); +process.on('SIGTERM', shutdown); diff --git a/server/src/migrate.ts b/server/src/migrate.ts new file mode 100644 index 0000000..e331def --- /dev/null +++ b/server/src/migrate.ts @@ -0,0 +1,49 @@ +import { readdir, readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { config } from './config.ts'; +import { pool, withTx } from './db.ts'; + +/** + * Migrations are plain SQL, applied in filename order, recorded by name. There is no down path: + * a projection store is rebuilt from events rather than migrated backwards. + */ +const dir = new URL('../migrations/', import.meta.url).pathname; + +async function main() { + await pool.query(` + CREATE TABLE IF NOT EXISTS schema_migrations ( + name TEXT PRIMARY KEY, + applied_at TIMESTAMPTZ NOT NULL DEFAULT now() + )`); + + const files = (await readdir(dir)).filter((f) => f.endsWith('.sql')).sort(); + const { rows } = await pool.query<{ name: string }>('SELECT name FROM schema_migrations'); + const done = new Set(rows.map((r) => r.name)); + + for (const file of files) { + if (done.has(file)) continue; + const sql = await readFile(join(dir, file), 'utf8'); + await withTx(async (c) => { + await c.query(sql); + await c.query('INSERT INTO schema_migrations (name) VALUES ($1)', [file]); + }); + console.log(`applied ${file}`); + } + + await pool.query( + `INSERT INTO networks (name, package_id) VALUES ($1, $2) + ON CONFLICT (name) DO UPDATE SET package_id = EXCLUDED.package_id`, + [config.network, config.packageId], + ); + await pool.query( + `INSERT INTO indexer_cursor (network) VALUES ($1) ON CONFLICT (network) DO NOTHING`, + [config.network], + ); + console.log(`ready: ${config.network} at ${config.packageId}`); + await pool.end(); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/server/src/notify.ts b/server/src/notify.ts new file mode 100644 index 0000000..1be72f1 --- /dev/null +++ b/server/src/notify.ts @@ -0,0 +1,360 @@ +import { createHmac } from 'node:crypto'; +import type { PoolClient } from 'pg'; +import { + KIND_LABELS, + MODE_LABELS, + Kind, + Mode, + Role, + STATUS_LABELS, + Status, + TIER_LABELS, + Tier, + Trust, + describeReasons, + fmtDuration, + short, + type DecodedEvent, +} from '@skur/sdk'; +import { pool } from './db.ts'; + +/** + * Who needs to be told, and why. + * + * The rule is the point of the whole service: an approver should hear about the queue, an + * executor about what is ready, and a guardian about the things only a guardian can stop. Sending + * everything to everyone is the same as sending nothing, because nobody reads the eleventh alert. + * + * `roles` is a bitmask of who the message is for; zero means every member of the vault. + */ +type Rule = { + rule: string; + title: string; + body: string; + severity: 'info' | 'action' | 'alert'; + roles: number; +}; + +const fmtAmount = (v: bigint) => v.toLocaleString('en-US'); + +export function rulesFor({ event }: DecodedEvent): Rule[] { + switch (event.name) { + case 'ProposalOpened': { + const out: Rule[] = []; + const who = event.kind === Kind.TRANSFER ? Role.APPROVER : Role.OWNER; + const label = KIND_LABELS[event.kind] ?? 'Proposal'; + + if (event.kind === Kind.TRANSFER) { + const reasons = describeReasons(event.reasons); + out.push({ + rule: 'transfer.opened', + title: `${TIER_LABELS[event.tier]} payment awaiting approval`, + body: [ + `${fmtAmount(event.amount)} to ${short(event.recipient)}${event.memo ? ` — ${event.memo}` : ''}.`, + `Needs ${event.reqApprovals} approval${event.reqApprovals === 1 ? '' : 's'}${ + event.reqGuardians ? ` and ${event.reqGuardians} guardian confirmation${event.reqGuardians === 1 ? '' : 's'}` : '' + }.`, + reasons.length ? `Scored ${TIER_LABELS[event.tier]} because: ${reasons.join('; ')}.` : '', + ] + .filter(Boolean) + .join(' '), + severity: 'action', + roles: who, + }); + if (event.tier === Tier.CRITICAL) { + out.push({ + rule: 'transfer.critical', + title: 'A critical payment is open and can be vetoed', + body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, at ${(event.exposureBps / 100).toFixed(1)}% of holdings. You can veto it until it executes.`, + severity: 'alert', + roles: Role.GUARDIAN, + }); + } + } else { + out.push({ + rule: 'governance.opened', + title: `${label} awaiting owner approval`, + body: `Opened by ${short(event.proposer)}.`, + severity: 'action', + roles: who, + }); + } + + // The one notification that matters most: somebody is trying to make the vault weaker. + if (event.reductionMask !== 0) { + out.push({ + rule: 'governance.weakening', + title: `${label} would weaken this vault`, + body: `It cannot take effect before ${new Date(event.executableAt).toUTCString()}, and any guardian can veto it until then.`, + severity: 'alert', + roles: Role.GUARDIAN | Role.OWNER, + }); + } + if (event.kind === Kind.RECOVERY) { + out.push({ + rule: 'recovery.opened', + title: 'A signer recovery has been proposed', + body: `Proposed by ${short(event.proposer)}. Any owner can cancel it before it executes.`, + severity: 'alert', + roles: Role.OWNER, + }); + } + return out; + } + + case 'Approved': + // Only the approval that completes the set is worth an interruption. + if (event.approvals < event.reqApprovals) return []; + return [ + { + rule: 'proposal.ready', + title: 'A payment has all its approvals', + body: `Proposal #${event.proposal} is fully approved. It executes once its waiting period has elapsed.`, + severity: 'action', + roles: Role.EXECUTOR, + }, + ]; + + case 'BreakerTripped': + return [ + { + rule: 'breaker.tripped', + title: 'The circuit breaker stopped a payment and froze the vault', + body: `${fmtAmount(event.amount)} would have taken the window past its loss envelope of ${fmtAmount(event.envelopeLimit)} against a basis of ${fmtAmount(event.envelopeBasis)}. The money did not move. The vault is now in Lockdown and needs owners, a guardian and time to reopen.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'ModeChanged': + if (event.to === Mode.NORMAL) { + return [ + { + rule: 'mode.normal', + title: 'The vault is back to normal', + body: `Lowered from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, + severity: 'info', + roles: 0, + }, + ]; + } + return [ + { + rule: 'mode.raised', + title: `The vault is now in ${MODE_LABELS[event.to]}`, + body: [ + `Raised from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, + event.to === Mode.LOCKDOWN + ? 'Nothing outgoing executes until owners and a guardian agree to reopen it.' + : 'Caps are halved and every payment is escalated one tier.', + describeReasons(event.reasons).join('; '), + ] + .filter(Boolean) + .join(' '), + severity: 'alert', + roles: 0, + }, + ]; + + case 'Settled': + if (event.status === Status.VETOED) { + return [ + { + rule: 'proposal.vetoed', + title: 'A guardian vetoed a proposal', + body: `Proposal #${event.proposal} was vetoed by ${short(event.actor)}. The vault moved to Elevated.`, + severity: 'alert', + roles: 0, + }, + ]; + } + if (event.status === Status.EXPIRED) { + return [ + { + rule: 'proposal.expired', + title: 'A proposal expired before it executed', + body: `Proposal #${event.proposal} (${KIND_LABELS[event.kind]}) ran out of time. Its approvals no longer count for anything.`, + severity: 'info', + roles: Role.APPROVER | Role.OWNER, + }, + ]; + } + return []; + + case 'Executed': + if (event.kind !== Kind.TRANSFER) return []; + return [ + { + rule: 'transfer.executed', + title: 'A payment went out', + body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, executed by ${short(event.executor)}. ${fmtAmount(event.balanceAfter)} remains.`, + severity: 'info', + roles: 0, + }, + ]; + + case 'RecipientTrustChanged': + if (event.to !== Trust.BLOCKED && event.to !== Trust.RESTRICTED) return []; + return [ + { + rule: 'recipient.restricted', + title: `A recipient was ${event.to === Trust.BLOCKED ? 'blocked' : 'restricted'}`, + body: `${short(event.recipient)} was set by ${short(event.actor)}. Payments to it are ${event.to === Trust.BLOCKED ? 'refused' : 'treated as critical'} from now on.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'Recovered': + return [ + { + rule: 'recovery.executed', + title: 'A signer was replaced', + body: `${short(event.lost)} was replaced by ${short(event.replacement)} with the same roles. The policy was not changed, and the vault is now Elevated.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'PolicyChanged': + return [ + { + rule: 'policy.changed', + title: `The policy is now at version ${event.version}`, + body: event.reductionMask === 0 + ? 'The change only tightened the vault.' + : 'The change gave up one or more controls. It served its delay and was not vetoed.', + severity: event.reductionMask === 0 ? 'info' : 'alert', + roles: 0, + }, + ]; + + default: + return []; + } +} + +/** + * Queue notifications for an event. The unique constraint on + * `(subscription, tx_digest, event_index, rule)` is what makes a replayed event silent. + */ +export async function queueNotifications( + c: PoolClient, + network: string, + decoded: DecodedEvent, +): Promise { + const rules = rulesFor(decoded); + if (rules.length === 0) return 0; + const { event, position } = decoded; + let queued = 0; + + for (const r of rules) { + const { rows } = await c.query<{ id: string }>( + `SELECT s.id + FROM subscriptions s + LEFT JOIN members m + ON m.network = s.network AND m.vault_id = s.vault_id AND m.address = s.address + WHERE s.active + AND s.network = $1 + AND s.vault_id = $2 + AND ($3 = 0 OR (coalesce(m.roles, 0) & $3) <> 0) + AND (cardinality(s.events) = 0 OR $4 = ANY(s.events))`, + [network, event.vault, r.roles, r.rule], + ); + for (const row of rows) { + const res = await c.query( + `INSERT INTO notifications ( + subscription_id, network, vault_id, tx_digest, event_index, rule, title, body, severity + ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) + ON CONFLICT DO NOTHING`, + [ + row.id, + network, + event.vault, + position.transactionDigest, + position.eventIndex, + r.rule, + r.title, + r.body, + r.severity, + ], + ); + queued += res.rowCount ?? 0; + } + } + return queued; +} + +/** + * Deliver what is queued. A webhook is signed with the subscription's secret so the receiver can + * tell a real notification from anything else that finds the URL. + */ +export async function deliverPending(limit = 25): Promise { + const { rows } = await pool.query<{ + id: string; + channel: string; + endpoint: string; + secret: string | null; + vault_id: string; + rule: string; + title: string; + body: string; + severity: string; + attempts: number; + }>( + `SELECT n.id, s.channel, s.endpoint, s.secret, n.vault_id, n.rule, n.title, n.body, + n.severity, n.attempts + FROM notifications n + JOIN subscriptions s ON s.id = n.subscription_id + WHERE n.delivered_at IS NULL AND n.attempts < 6 AND s.active + ORDER BY n.created_at + LIMIT $1`, + [limit], + ); + + let sent = 0; + for (const n of rows) { + const payload = JSON.stringify({ + vault: n.vault_id, + rule: n.rule, + title: n.title, + body: n.body, + severity: n.severity, + }); + try { + if (n.channel === 'webhook') { + const headers: Record = { 'content-type': 'application/json' }; + if (n.secret) { + headers['x-skur-signature'] = createHmac('sha256', n.secret).update(payload).digest('hex'); + } + const res = await fetch(n.endpoint, { method: 'POST', headers, body: payload }); + if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); + } else if (n.channel === 'log') { + console.log(`[${n.severity}] ${n.title} — ${n.body}`); + } else { + // Email needs a provider. Rather than pretend, the row is left for whoever wires one up. + throw new Error(`channel ${n.channel} has no transport configured`); + } + await pool.query( + `UPDATE notifications SET delivered_at = now(), attempts = attempts + 1 WHERE id = $1`, + [n.id], + ); + sent++; + } catch (e) { + await pool.query( + `UPDATE notifications SET attempts = attempts + 1, last_error = $2 WHERE id = $1`, + [n.id, e instanceof Error ? e.message : String(e)], + ); + } + } + return sent; +} + +/** Used by the API to describe a waiting proposal in words rather than timestamps. */ +export function describeWait(executableAt: number, now = Date.now()): string { + const left = executableAt - now; + if (left <= 0) return 'executable now'; + return `executable in ${fmtDuration(left)}`; +} + +export { STATUS_LABELS }; diff --git a/server/src/project.ts b/server/src/project.ts new file mode 100644 index 0000000..7c78402 --- /dev/null +++ b/server/src/project.ts @@ -0,0 +1,296 @@ +import type { PoolClient } from 'pg'; +import { Status, type DecodedEvent, type SkurEvent } from '@skur/sdk'; +import { toNumeric, toTimestamp } from './db.ts'; + +/** + * Apply one event to the projections. + * + * Every statement is an upsert keyed on the chain's own identity for the row, so replaying the + * ledger converges on the same state rather than doubling anything. The one place that needs care + * is a counter: `paid_count` and `total_paid` are accumulated, so they are only ever touched from + * inside the idempotency guard in `ingest`, which has already established that this exact event + * has not been applied before. + */ +export async function project( + c: PoolClient, + network: string, + { event, position }: DecodedEvent, +): Promise { + const at = toTimestamp(event.at); + const vault = event.vault; + const key = [network, vault]; + + switch (event.name) { + case 'VaultCreated': + await c.query( + `INSERT INTO vaults (network, vault_id, name, creator, created_at) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (network, vault_id) DO UPDATE + SET name = EXCLUDED.name, creator = EXCLUDED.creator`, + [...key, event.vaultName, event.creator, at], + ); + break; + + case 'Deposited': + await c.query( + `INSERT INTO assets (network, vault_id, coin_type, balance, updated_at) + VALUES ($1, $2, $3, $4, $5) + ON CONFLICT (network, vault_id, coin_type) DO UPDATE + SET balance = EXCLUDED.balance, updated_at = EXCLUDED.updated_at`, + [...key, event.asset, toNumeric(event.balance), at], + ); + break; + + case 'ProposalOpened': + await c.query( + `INSERT INTO proposals ( + network, vault_id, proposal_id, kind, status, proposer, coin_type, amount, recipient, + memo, tier, reasons, exposure_bps, req_approvals, req_guardians, reduction_mask, + opened_at, executable_at, expires_at + ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19) + ON CONFLICT (network, vault_id, proposal_id) DO UPDATE SET + kind = EXCLUDED.kind, status = EXCLUDED.status, proposer = EXCLUDED.proposer, + coin_type = EXCLUDED.coin_type, amount = EXCLUDED.amount, + recipient = EXCLUDED.recipient, memo = EXCLUDED.memo, tier = EXCLUDED.tier, + reasons = EXCLUDED.reasons, exposure_bps = EXCLUDED.exposure_bps, + req_approvals = EXCLUDED.req_approvals, req_guardians = EXCLUDED.req_guardians, + reduction_mask = EXCLUDED.reduction_mask, opened_at = EXCLUDED.opened_at, + executable_at = EXCLUDED.executable_at, expires_at = EXCLUDED.expires_at`, + [ + ...key, + event.proposal.toString(), + event.kind, + Status.PENDING, + event.proposer, + event.asset, + toNumeric(event.amount), + event.recipient === '0x0000000000000000000000000000000000000000000000000000000000000000' + ? null + : event.recipient, + event.memo, + event.tier, + event.reasons, + event.exposureBps, + event.reqApprovals, + event.reqGuardians, + event.reductionMask, + at, + toTimestamp(event.executableAt), + toTimestamp(event.expiresAt), + ], + ); + break; + + case 'Approved': + await c.query( + `INSERT INTO proposal_votes (network, vault_id, proposal_id, voter, kind, voted_at) + VALUES ($1,$2,$3,$4,'approval',$5) + ON CONFLICT DO NOTHING`, + [...key, event.proposal.toString(), event.approver, at], + ); + await c.query( + `UPDATE proposals SET approvals = $4 + WHERE network = $1 AND vault_id = $2 AND proposal_id = $3`, + [...key, event.proposal.toString(), event.approvals], + ); + break; + + case 'Confirmed': + await c.query( + `INSERT INTO proposal_votes (network, vault_id, proposal_id, voter, kind, voted_at) + VALUES ($1,$2,$3,$4,'confirmation',$5) + ON CONFLICT DO NOTHING`, + [...key, event.proposal.toString(), event.guardian, at], + ); + await c.query( + `UPDATE proposals SET confirmations = $4 + WHERE network = $1 AND vault_id = $2 AND proposal_id = $3`, + [...key, event.proposal.toString(), event.confirmations], + ); + break; + + case 'Settled': + await c.query( + `UPDATE proposals SET status = $4, settled_at = $5 + WHERE network = $1 AND vault_id = $2 AND proposal_id = $3`, + [...key, event.proposal.toString(), event.status, at], + ); + break; + + case 'Executed': { + await c.query( + `UPDATE proposals SET status = $4, settled_at = $5, tier = $6 + WHERE network = $1 AND vault_id = $2 AND proposal_id = $3`, + [...key, event.proposal.toString(), Status.EXECUTED, at, event.tier], + ); + if (event.asset) { + await c.query( + `INSERT INTO assets (network, vault_id, coin_type, balance, updated_at) + VALUES ($1,$2,$3,$4,$5) + ON CONFLICT (network, vault_id, coin_type) DO UPDATE + SET balance = EXCLUDED.balance, updated_at = EXCLUDED.updated_at`, + [...key, event.asset, toNumeric(event.balanceAfter), at], + ); + } + if (event.recipient) { + await c.query( + `INSERT INTO recipients (network, vault_id, address, paid_count, total_paid, first_seen, last_paid) + VALUES ($1,$2,$3,1,$4,$5,$5) + ON CONFLICT (network, vault_id, address) DO UPDATE SET + paid_count = recipients.paid_count + 1, + total_paid = recipients.total_paid + EXCLUDED.total_paid, + last_paid = EXCLUDED.last_paid`, + [...key, event.recipient, toNumeric(event.amount), at], + ); + await c.query( + `INSERT INTO recipient_reputation (network, address, vault_count, payment_count, first_seen, last_seen) + VALUES ($1,$2,1,1,$3,$3) + ON CONFLICT (network, address) DO UPDATE SET + payment_count = recipient_reputation.payment_count + 1, + last_seen = EXCLUDED.last_seen, + vault_count = ( + SELECT count(DISTINCT vault_id) FROM recipients + WHERE network = $1 AND address = $2 AND paid_count > 0 + )`, + [network, event.recipient, at], + ); + } + break; + } + + case 'BreakerTripped': + await c.query( + `UPDATE proposals SET status = $4, settled_at = $5 + WHERE network = $1 AND vault_id = $2 AND proposal_id = $3`, + [...key, event.proposal.toString(), Status.BLOCKED, at], + ); + break; + + case 'ModeChanged': + await c.query( + `UPDATE vaults SET mode = $3, posture_reasons = $4, updated_at = $5 + WHERE network = $1 AND vault_id = $2`, + [...key, event.to, event.reasons, at], + ); + break; + + case 'PolicyChanged': + await c.query( + `UPDATE vaults SET policy_version = $3, updated_at = $4 + WHERE network = $1 AND vault_id = $2`, + [...key, event.version.toString(), at], + ); + break; + + case 'LimitsChanged': + await c.query( + `INSERT INTO assets ( + network, vault_id, coin_type, approved, low_max, high_max, per_tx_max, daily_max, updated_at + ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) + ON CONFLICT (network, vault_id, coin_type) DO UPDATE SET + approved = EXCLUDED.approved, low_max = EXCLUDED.low_max, + high_max = EXCLUDED.high_max, per_tx_max = EXCLUDED.per_tx_max, + daily_max = EXCLUDED.daily_max, updated_at = EXCLUDED.updated_at`, + [ + ...key, + event.asset, + event.approved, + toNumeric(event.lowMax), + toNumeric(event.highMax), + toNumeric(event.perTxMax), + toNumeric(event.dailyMax), + at, + ], + ); + break; + + case 'MemberChanged': + if (event.rolesAfter === 0) { + await c.query( + `DELETE FROM members WHERE network = $1 AND vault_id = $2 AND address = $3`, + [...key, event.member], + ); + } else { + await c.query( + `INSERT INTO members (network, vault_id, address, roles, updated_at) + VALUES ($1,$2,$3,$4,$5) + ON CONFLICT (network, vault_id, address) DO UPDATE + SET roles = EXCLUDED.roles, updated_at = EXCLUDED.updated_at`, + [...key, event.member, event.rolesAfter, at], + ); + } + break; + + case 'RecipientRegistered': + await c.query( + `INSERT INTO recipients (network, vault_id, address, label, trust, activates_at, first_seen) + VALUES ($1,$2,$3,$4,$5,$6,$7) + ON CONFLICT (network, vault_id, address) DO UPDATE SET + label = EXCLUDED.label, trust = EXCLUDED.trust, activates_at = EXCLUDED.activates_at`, + [...key, event.recipient, event.label, event.trust, toTimestamp(event.activatesAt), at], + ); + break; + + case 'RecipientTrustChanged': + await c.query( + `INSERT INTO recipients (network, vault_id, address, trust, first_seen) + VALUES ($1,$2,$3,$4,$5) + ON CONFLICT (network, vault_id, address) DO UPDATE SET trust = EXCLUDED.trust`, + [...key, event.recipient, event.to, at], + ); + // A blocked destination is the strongest signal the system produces about an address, so it + // is counted across vaults even though no contract reads it. + await c.query( + `INSERT INTO recipient_reputation (network, address, first_seen, last_seen, blocked_by) + VALUES ($1,$2,$3,$3,$4) + ON CONFLICT (network, address) DO UPDATE SET + last_seen = EXCLUDED.last_seen, + blocked_by = ( + SELECT count(*) FROM recipients + WHERE network = $1 AND address = $2 AND trust IN (4, 5) + )`, + [network, event.recipient, at, event.to >= 4 ? 1 : 0], + ); + break; + + case 'Recovered': + await c.query( + `DELETE FROM members WHERE network = $1 AND vault_id = $2 AND address = $3`, + [...key, event.lost], + ); + await c.query( + `INSERT INTO members (network, vault_id, address, roles, updated_at) + VALUES ($1,$2,$3,$4,$5) + ON CONFLICT (network, vault_id, address) DO UPDATE + SET roles = EXCLUDED.roles, updated_at = EXCLUDED.updated_at`, + [...key, event.replacement, event.roles, at], + ); + break; + } + + await c.query( + `INSERT INTO events (network, tx_digest, event_index, vault_id, name, checkpoint, occurred_at, payload) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8) + ON CONFLICT (network, tx_digest, event_index) DO NOTHING`, + [ + network, + position.transactionDigest, + position.eventIndex, + vault, + event.name, + position.checkpoint ?? null, + at, + JSON.stringify(event, (_, v) => (typeof v === 'bigint' ? v.toString() : v)), + ], + ); +} + +/** A `VaultCreated` row may be missing if indexing started mid-history; make one so FKs hold. */ +export async function ensureVault(c: PoolClient, network: string, event: SkurEvent) { + await c.query( + `INSERT INTO vaults (network, vault_id, name, creator, created_at) + VALUES ($1,$2,'(discovered)','0x0',$3) + ON CONFLICT (network, vault_id) DO NOTHING`, + [network, event.vault, toTimestamp(event.at)], + ); +} diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..fc39497 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2023", + "module": "NodeNext", + "moduleResolution": "nodenext", + "lib": ["ES2023"], + "strict": true, + "noEmit": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowImportingTsExtensions": true, + "types": ["node"] + }, + "include": ["src"] +} diff --git a/sui/.gitignore b/sui/.gitignore new file mode 100644 index 0000000..c06878c --- /dev/null +++ b/sui/.gitignore @@ -0,0 +1,3 @@ +build/ +Move.lock +.env diff --git a/sui/Move.toml b/sui/Move.toml new file mode 100644 index 0000000..d3cab7f --- /dev/null +++ b/sui/Move.toml @@ -0,0 +1,15 @@ +[package] +name = "skur" +edition = "2024.beta" +license = "MIT" +authors = ["Olajumoke Emmanuel"] +published-at = "0x0" + +# The Sui framework is an implicit dependency, resolved from the toolchain that builds this +# package. That keeps the build hermetic and pins the framework to the CLI you deploy with. + +[addresses] +skur = "0x0" + +[dev-addresses] +skur = "0x0" diff --git a/sui/scripts/publish.sh b/sui/scripts/publish.sh new file mode 100755 index 0000000..84307be --- /dev/null +++ b/sui/scripts/publish.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Publish the Skur package and record where it landed. +# +# Usage: scripts/publish.sh [testnet|devnet|localnet|mainnet] +# +# Writes deployments/.json, which is the only place an address is configured. Nothing in +# the app, the SDK or the backend hardcodes a package id. +set -euo pipefail + +NETWORK="${1:-testnet}" +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +OUT="$HERE/deployments/$NETWORK.json" + +command -v sui >/dev/null || { echo "the sui CLI is not on PATH" >&2; exit 1; } + +echo "building" +sui move build --path "$HERE" + +echo "testing before publishing" +sui move test --path "$HERE" + +echo "switching to $NETWORK" +sui client switch --env "$NETWORK" >/dev/null + +ADDRESS="$(sui client active-address)" +echo "publishing as $ADDRESS" + +RESULT="$(sui client publish --path "$HERE" --gas-budget 500000000 --json)" + +PACKAGE_ID="$(printf '%s' "$RESULT" | python3 -c ' +import json,sys +d = json.load(sys.stdin) +for c in d.get("objectChanges", []): + if c.get("type") == "published": + print(c["packageId"]); break +')" +DIGEST="$(printf '%s' "$RESULT" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("digest",""))')" + +[ -n "$PACKAGE_ID" ] || { echo "could not find the published package id in the output" >&2; exit 1; } + +python3 - "$OUT" "$NETWORK" "$PACKAGE_ID" "$DIGEST" "$ADDRESS" <<'PY' +import json, sys, datetime +out, network, package, digest, deployer = sys.argv[1:6] +json.dump({ + "network": network, + "packageId": package, + "publishedAtDigest": digest, + "deployer": deployer, + "publishedAt": datetime.datetime.now(datetime.UTC).isoformat(), + "vaults": [], +}, open(out, "w"), indent=2) +print(f"wrote {out}") +PY + +echo +echo "package: $PACKAGE_ID" +echo "explorer: https://suiscan.xyz/$NETWORK/object/$PACKAGE_ID" diff --git a/sui/scripts/test.sh b/sui/scripts/test.sh new file mode 100755 index 0000000..8185daa --- /dev/null +++ b/sui/scripts/test.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +# Run the Move test suite, with coverage when the CLI was built with it. +set -euo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +command -v sui >/dev/null || { echo "the sui CLI is not on PATH" >&2; exit 1; } +sui move test --path "$HERE" "$@" diff --git a/sui/sources/policy.move b/sui/sources/policy.move new file mode 100644 index 0000000..48654fe --- /dev/null +++ b/sui/sources/policy.move @@ -0,0 +1,341 @@ +/// The policy: seventeen fields that decide how much authorization a payment needs, how long it +/// waits, and how much can leave in a window. Plus the two things a policy module must be able to +/// answer: is this policy internally coherent, and does this change weaken the vault? +/// +/// Durations are milliseconds, because that is the unit `sui::clock` reports. The TypeScript +/// engine keeps the same fields in seconds and converts once, at the SDK boundary. +module skur::policy; + +use skur::types; + +// ---------------------------------------------------------------- validation failure codes +// Returned (not aborted) by `validate`, so an interface can dry-run a draft policy and show the +// precise reason. `assert_valid` turns a non-zero code into an abort with the same number. +const E_OK: u64 = 0; +const E_APPROVALS_LOW_ZERO: u64 = 1; +const E_APPROVALS_HIGH_BELOW_LOW: u64 = 2; +const E_APPROVALS_CRITICAL_BELOW_HIGH: u64 = 3; +const E_GOVERNANCE_ZERO: u64 = 4; +const E_GUARDIAN_REQUIRED_WITHOUT_THRESHOLD: u64 = 5; +const E_CRITICAL_DELAY_BELOW_HIGH: u64 = 6; +const E_HIGH_EXPOSURE_ABOVE_CRITICAL: u64 = 7; +const E_EXPOSURE_ABOVE_FULL: u64 = 8; +const E_HARD_BLOCK_BELOW_CRITICAL: u64 = 9; +const E_HARD_BLOCK_ABOVE_FULL: u64 = 10; +const E_ENVELOPE_ABOVE_FULL: u64 = 11; +const E_ENVELOPE_WINDOW_TOO_SHORT: u64 = 12; +const E_TTL_BELOW_LONGEST_DELAY: u64 = 13; + +const E_LIMITS_LOW_ABOVE_HIGH: u64 = 20; +const E_LIMITS_PER_TX_ABOVE_DAILY: u64 = 21; + +const E_NO_OWNER: u64 = 30; +const E_NO_EXECUTOR: u64 = 31; +const E_GOVERNANCE_EXCEEDS_OWNERS: u64 = 32; +const E_CRITICAL_EXCEEDS_APPROVERS: u64 = 33; +const E_GUARDIAN_THRESHOLD_EXCEEDS_GUARDIANS: u64 = 34; + +public fun e_ok(): u64 { E_OK } + +/// A proposal must stay executable for at least an hour after its delay elapses, otherwise a +/// policy could be written whose transfers expire before anyone can execute them. +const MIN_EXECUTION_WINDOW_MS: u64 = 3_600_000; + +public fun min_execution_window_ms(): u64 { MIN_EXECUTION_WINDOW_MS } + +// ---------------------------------------------------------------- the policy +public struct Policy has copy, drop, store { + /// Approvals required at each risk tier. Monotonic: low <= high <= critical. + approvals_low: u8, + approvals_high: u8, + approvals_critical: u8, + /// Owner approvals required for any governance action (policy, members, limits, trust). + governance_threshold: u8, + /// Guardian confirmations required when a guardian is in the loop. + guardian_threshold: u8, + /// Whether a critical transfer needs guardian confirmation on top of approver approvals. + guardian_required_critical: bool, + /// Timelocks, in milliseconds. + delay_high: u64, + delay_critical: u64, + recipient_activation_delay: u64, + policy_change_delay: u64, + recovery_delay: u64, + /// How long a proposal remains executable before it expires. + proposal_ttl: u64, + /// Share of the asset's balance, in basis points, that escalates a transfer. + /// Zero disables the threshold. + high_exposure_bps: u64, + critical_exposure_bps: u64, + /// Share of balance that is refused outright, whatever the approvals. Zero disables it. + hard_block_exposure_bps: u64, + /// The circuit breaker: how much of the balance may leave per window before the vault latches + /// into Lockdown. Zero disables the breaker. + envelope_bps: u64, + envelope_window: u64, +} + +public fun new( + approvals_low: u8, + approvals_high: u8, + approvals_critical: u8, + governance_threshold: u8, + guardian_threshold: u8, + guardian_required_critical: bool, + delay_high: u64, + delay_critical: u64, + recipient_activation_delay: u64, + policy_change_delay: u64, + recovery_delay: u64, + proposal_ttl: u64, + high_exposure_bps: u64, + critical_exposure_bps: u64, + hard_block_exposure_bps: u64, + envelope_bps: u64, + envelope_window: u64, +): Policy { + Policy { + approvals_low, + approvals_high, + approvals_critical, + governance_threshold, + guardian_threshold, + guardian_required_critical, + delay_high, + delay_critical, + recipient_activation_delay, + policy_change_delay, + recovery_delay, + proposal_ttl, + high_exposure_bps, + critical_exposure_bps, + hard_block_exposure_bps, + envelope_bps, + envelope_window, + } +} + +public fun approvals_low(p: &Policy): u8 { p.approvals_low } +public fun approvals_high(p: &Policy): u8 { p.approvals_high } +public fun approvals_critical(p: &Policy): u8 { p.approvals_critical } +public fun governance_threshold(p: &Policy): u8 { p.governance_threshold } +public fun guardian_threshold(p: &Policy): u8 { p.guardian_threshold } +public fun guardian_required_critical(p: &Policy): bool { p.guardian_required_critical } +public fun delay_high(p: &Policy): u64 { p.delay_high } +public fun delay_critical(p: &Policy): u64 { p.delay_critical } +public fun recipient_activation_delay(p: &Policy): u64 { p.recipient_activation_delay } +public fun policy_change_delay(p: &Policy): u64 { p.policy_change_delay } +public fun recovery_delay(p: &Policy): u64 { p.recovery_delay } +public fun proposal_ttl(p: &Policy): u64 { p.proposal_ttl } +public fun high_exposure_bps(p: &Policy): u64 { p.high_exposure_bps } +public fun critical_exposure_bps(p: &Policy): u64 { p.critical_exposure_bps } +public fun hard_block_exposure_bps(p: &Policy): u64 { p.hard_block_exposure_bps } +public fun envelope_bps(p: &Policy): u64 { p.envelope_bps } +public fun envelope_window(p: &Policy): u64 { p.envelope_window } + +// ---------------------------------------------------------------- per-asset limits +public struct AssetLimits has copy, drop, store { + /// An asset must be approved before it can be proposed at all. + approved: bool, + /// Above `low_max` a transfer is at least high tier; above `high_max` it is critical. + low_max: u64, + high_max: u64, + /// Absolute caps. Zero means no cap. + per_tx_max: u64, + daily_max: u64, +} + +public fun new_limits( + approved: bool, + low_max: u64, + high_max: u64, + per_tx_max: u64, + daily_max: u64, +): AssetLimits { + AssetLimits { approved, low_max, high_max, per_tx_max, daily_max } +} + +public fun limits_approved(l: &AssetLimits): bool { l.approved } +public fun limits_low_max(l: &AssetLimits): u64 { l.low_max } +public fun limits_high_max(l: &AssetLimits): u64 { l.high_max } +public fun limits_per_tx_max(l: &AssetLimits): u64 { l.per_tx_max } +public fun limits_daily_max(l: &AssetLimits): u64 { l.daily_max } + +// ---------------------------------------------------------------- validation +/// Returns `E_OK` when the policy is coherent, otherwise the first failure's code. +public fun validate(p: &Policy): u64 { + let bps = types::bps(); + if (p.approvals_low == 0) return E_APPROVALS_LOW_ZERO; + if (p.approvals_high < p.approvals_low) return E_APPROVALS_HIGH_BELOW_LOW; + if (p.approvals_critical < p.approvals_high) return E_APPROVALS_CRITICAL_BELOW_HIGH; + if (p.governance_threshold == 0) return E_GOVERNANCE_ZERO; + if (p.guardian_required_critical && p.guardian_threshold == 0) { + return E_GUARDIAN_REQUIRED_WITHOUT_THRESHOLD + }; + if (p.delay_critical < p.delay_high) return E_CRITICAL_DELAY_BELOW_HIGH; + if (p.critical_exposure_bps != 0 && p.high_exposure_bps > p.critical_exposure_bps) { + return E_HIGH_EXPOSURE_ABOVE_CRITICAL + }; + if (p.critical_exposure_bps > bps || p.high_exposure_bps > bps) return E_EXPOSURE_ABOVE_FULL; + if (p.hard_block_exposure_bps != 0 && p.hard_block_exposure_bps < p.critical_exposure_bps) { + return E_HARD_BLOCK_BELOW_CRITICAL + }; + if (p.hard_block_exposure_bps > bps) return E_HARD_BLOCK_ABOVE_FULL; + if (p.envelope_bps > bps) return E_ENVELOPE_ABOVE_FULL; + if (p.envelope_bps != 0 && p.envelope_window < MIN_EXECUTION_WINDOW_MS) { + return E_ENVELOPE_WINDOW_TOO_SHORT + }; + if (p.proposal_ttl < longest_delay(p) + MIN_EXECUTION_WINDOW_MS) { + return E_TTL_BELOW_LONGEST_DELAY + }; + E_OK +} + +public fun longest_delay(p: &Policy): u64 { + let mut longest = p.delay_critical; + if (p.policy_change_delay > longest) longest = p.policy_change_delay; + if (p.recovery_delay > longest) longest = p.recovery_delay; + if (p.recipient_activation_delay > longest) longest = p.recipient_activation_delay; + longest +} + +public fun assert_valid(p: &Policy) { + let code = validate(p); + assert!(code == E_OK, code); +} + +public fun validate_limits(l: &AssetLimits): u64 { + if (l.low_max > l.high_max) return E_LIMITS_LOW_ABOVE_HIGH; + if (l.per_tx_max != 0 && l.daily_max != 0 && l.per_tx_max > l.daily_max) { + return E_LIMITS_PER_TX_ABOVE_DAILY + }; + E_OK +} + +public fun assert_limits_valid(l: &AssetLimits) { + let code = validate_limits(l); + assert!(code == E_OK, code); +} + +/// A policy is only meaningful against a real roster: a threshold nobody can reach is a frozen +/// vault, so the counts are validated together with the policy on every change to either. +public fun validate_counts( + p: &Policy, + owners: u64, + approvers: u64, + executors: u64, + guardians: u64, +): u64 { + if (owners < 1) return E_NO_OWNER; + if (executors < 1) return E_NO_EXECUTOR; + if (owners < (p.governance_threshold as u64)) return E_GOVERNANCE_EXCEEDS_OWNERS; + if (approvers < (p.approvals_critical as u64)) return E_CRITICAL_EXCEEDS_APPROVERS; + if (guardians < (p.guardian_threshold as u64)) { + return E_GUARDIAN_THRESHOLD_EXCEEDS_GUARDIANS + }; + E_OK +} + +public fun assert_counts_valid( + p: &Policy, + owners: u64, + approvers: u64, + executors: u64, + guardians: u64, +) { + let code = validate_counts(p, owners, approvers, executors, guardians); + assert!(code == E_OK, code); +} + +// ---------------------------------------------------------------- what weakened +// One bit per field that can be loosened. The vault records the mask on the proposal, so a signer +// sees exactly which controls a policy change gives up, and a non-zero mask routes the change +// through the policy-change delay with a guardian veto. +const R_APPROVALS_LOW: u32 = 1; +const R_APPROVALS_HIGH: u32 = 1 << 1; +const R_APPROVALS_CRITICAL: u32 = 1 << 2; +const R_GOVERNANCE: u32 = 1 << 3; +const R_GUARDIAN_THRESHOLD: u32 = 1 << 4; +const R_GUARDIAN_NOT_REQUIRED: u32 = 1 << 5; +const R_DELAY_HIGH: u32 = 1 << 6; +const R_DELAY_CRITICAL: u32 = 1 << 7; +const R_ACTIVATION_DELAY: u32 = 1 << 8; +const R_POLICY_CHANGE_DELAY: u32 = 1 << 9; +const R_RECOVERY_DELAY: u32 = 1 << 10; +const R_PROPOSAL_TTL: u32 = 1 << 11; +const R_HIGH_EXPOSURE: u32 = 1 << 12; +const R_CRITICAL_EXPOSURE: u32 = 1 << 13; +const R_HARD_BLOCK: u32 = 1 << 14; +const R_ENVELOPE: u32 = 1 << 15; +const R_ENVELOPE_WINDOW: u32 = 1 << 16; + +const R_ASSET_NEWLY_APPROVED: u32 = 1; +const R_LOW_MAX: u32 = 1 << 1; +const R_HIGH_MAX: u32 = 1 << 2; +const R_PER_TX_CAP: u32 = 1 << 3; +const R_DAILY_CAP: u32 = 1 << 4; + +public fun r_approvals_low(): u32 { R_APPROVALS_LOW } +public fun r_guardian_not_required(): u32 { R_GUARDIAN_NOT_REQUIRED } +public fun r_envelope(): u32 { R_ENVELOPE } +public fun r_asset_newly_approved(): u32 { R_ASSET_NEWLY_APPROVED } +public fun r_daily_cap(): u32 { R_DAILY_CAP } + +/// For a threshold where zero means "disabled", moving to zero is the loosest possible move and +/// moving away from zero can only tighten. +fun threshold_loosens(a: u64, b: u64): bool { + if (a == 0) return false; + if (b == 0) return true; + b > a +} + +/// Which controls `b` gives up relative to `a`. Zero means the change only tightens. +public fun reductions(a: &Policy, b: &Policy): u32 { + let mut m: u32 = 0; + if (b.approvals_low < a.approvals_low) m = m | R_APPROVALS_LOW; + if (b.approvals_high < a.approvals_high) m = m | R_APPROVALS_HIGH; + if (b.approvals_critical < a.approvals_critical) m = m | R_APPROVALS_CRITICAL; + if (b.governance_threshold < a.governance_threshold) m = m | R_GOVERNANCE; + if (b.guardian_threshold < a.guardian_threshold) m = m | R_GUARDIAN_THRESHOLD; + if (a.guardian_required_critical && !b.guardian_required_critical) { + m = m | R_GUARDIAN_NOT_REQUIRED + }; + if (b.delay_high < a.delay_high) m = m | R_DELAY_HIGH; + if (b.delay_critical < a.delay_critical) m = m | R_DELAY_CRITICAL; + if (b.recipient_activation_delay < a.recipient_activation_delay) m = m | R_ACTIVATION_DELAY; + if (b.policy_change_delay < a.policy_change_delay) m = m | R_POLICY_CHANGE_DELAY; + if (b.recovery_delay < a.recovery_delay) m = m | R_RECOVERY_DELAY; + // A longer lifetime keeps a stale approval set alive for longer, so it loosens. + if (b.proposal_ttl > a.proposal_ttl) m = m | R_PROPOSAL_TTL; + if (threshold_loosens(a.high_exposure_bps, b.high_exposure_bps)) m = m | R_HIGH_EXPOSURE; + if (threshold_loosens(a.critical_exposure_bps, b.critical_exposure_bps)) { + m = m | R_CRITICAL_EXPOSURE + }; + if (threshold_loosens(a.hard_block_exposure_bps, b.hard_block_exposure_bps)) { + m = m | R_HARD_BLOCK + }; + if (threshold_loosens(a.envelope_bps, b.envelope_bps)) m = m | R_ENVELOPE; + if (a.envelope_bps != 0 && b.envelope_window < a.envelope_window) m = m | R_ENVELOPE_WINDOW; + m +} + +public fun limit_reductions(a: &AssetLimits, b: &AssetLimits): u32 { + let mut m: u32 = 0; + if (!a.approved && b.approved) m = m | R_ASSET_NEWLY_APPROVED; + if (b.low_max > a.low_max) m = m | R_LOW_MAX; + if (b.high_max > a.high_max) m = m | R_HIGH_MAX; + if (threshold_loosens(a.per_tx_max, b.per_tx_max)) m = m | R_PER_TX_CAP; + if (threshold_loosens(a.daily_max, b.daily_max)) m = m | R_DAILY_CAP; + m +} + +/// Raising a recipient's trust, or lifting a restriction, is a security-reducing move; lowering it +/// is always allowed to take effect at once. +public fun trust_reduces(from: u8, to: u8): bool { + let restricted = types::trust_restricted(); + let blocked = types::trust_blocked(); + let from_held_back = from == restricted || from == blocked || from == types::trust_unknown(); + if (from_held_back && to != restricted && to != blocked) return true; + if (to == blocked || to == restricted) return false; + to > from +} diff --git a/sui/sources/risk.move b/sui/sources/risk.move new file mode 100644 index 0000000..d0bd760 --- /dev/null +++ b/sui/sources/risk.move @@ -0,0 +1,168 @@ +/// The risk engine. Given a payment and the state of the vault around it, decide what tier it is, +/// why, and therefore how much authorization it needs. +/// +/// This is deterministic and pure: the same function the interface dry-runs to preview a transfer +/// is the function the vault calls when it executes one, so a preview can never promise something +/// the vault would refuse. +module skur::risk; + +use skur::policy::Policy; +use skur::types; + +/// Everything the classifier reads. Collected into one struct so the vault, the simulator and the +/// tests all pass the same shape. +public struct RiskInput has copy, drop { + amount: u64, + /// The asset's balance in the vault *before* this transfer. + asset_balance: u64, + low_max: u64, + high_max: u64, + daily_max: u64, + /// Already executed out of this asset in the live 24-hour bucket. + day_spent: u64, + trust: u8, + /// The recipient's activation delay has not elapsed yet. + in_probation: bool, + mode: u8, + high_exposure_bps: u64, + critical_exposure_bps: u64, +} + +public fun new_input( + amount: u64, + asset_balance: u64, + low_max: u64, + high_max: u64, + daily_max: u64, + day_spent: u64, + trust: u8, + in_probation: bool, + mode: u8, + high_exposure_bps: u64, + critical_exposure_bps: u64, +): RiskInput { + RiskInput { + amount, + asset_balance, + low_max, + high_max, + daily_max, + day_spent, + trust, + in_probation, + mode, + high_exposure_bps, + critical_exposure_bps, + } +} + +public struct RiskOutput has copy, drop { + tier: u8, + /// Bitmask of `types::reason_*`: every reason the tier landed where it did. + reasons: u16, + exposure_bps: u64, +} + +public fun tier(o: &RiskOutput): u8 { o.tier } +public fun reasons(o: &RiskOutput): u16 { o.reasons } +public fun exposure(o: &RiskOutput): u64 { o.exposure_bps } + +/// A transfer's share of the asset's holdings, in basis points. Taking everything, or taking +/// anything from an empty balance, is full exposure. +public fun exposure_bps(amount: u64, balance: u64): u64 { + let bps = types::bps(); + if (amount == 0) return 0; + if (balance == 0 || amount >= balance) return bps; + (((amount as u128) * (bps as u128)) / (balance as u128)) as u64 +} + +/// One step up the ladder. Already critical stays critical. +fun bump(t: u8): u8 { + if (t == types::tier_low()) types::tier_high() else types::tier_critical() +} + +fun at_least(t: u8, floor: u8): u8 { + if (t >= floor) t else floor +} + +/// Five independent signals, each able to raise the tier and none able to lower it. +public fun classify(i: &RiskInput): RiskOutput { + let low = types::tier_low(); + let high = types::tier_high(); + let critical = types::tier_critical(); + + let mut tier = low; + let mut reasons: u16 = 0; + + // 1. Absolute size, against this asset's own limits. + if (i.amount > i.high_max) { + tier = critical; + reasons = reasons | types::reason_amount_critical(); + } else if (i.amount > i.low_max) { + tier = high; + reasons = reasons | types::reason_amount_high(); + }; + + // 2. Share of the treasury. A small absolute amount out of a small balance still hurts. + let exposure = exposure_bps(i.amount, i.asset_balance); + if (i.critical_exposure_bps != 0 && exposure >= i.critical_exposure_bps) { + tier = critical; + reasons = reasons | types::reason_exposure_critical(); + } else if (i.high_exposure_bps != 0 && exposure >= i.high_exposure_bps) { + tier = at_least(tier, high); + reasons = reasons | types::reason_exposure_high(); + }; + + // 3. Who is receiving it. An address the vault has never paid is the signature of a drain. + if (i.trust == types::trust_restricted()) { + tier = critical; + reasons = reasons | types::reason_recipient_restricted(); + } else if (i.trust == types::trust_unknown()) { + tier = bump(tier); + reasons = reasons | types::reason_recipient_unknown() | types::reason_recipient_probation(); + } else if (i.trust == types::trust_new() && i.in_probation) { + tier = bump(tier); + reasons = reasons | types::reason_recipient_probation(); + }; + + // 4. Velocity. Crossing half the day's allowance is enough to escalate, so a drain split into + // pieces runs into a higher bar partway through instead of at the very end. + if (i.daily_max != 0 + && ((i.day_spent as u128) + (i.amount as u128)) * 2 > (i.daily_max as u128)) { + tier = at_least(tier, high); + reasons = reasons | types::reason_velocity_pressure(); + }; + + // 5. The vault's own posture. Elevated means something already looked wrong. + if (i.mode == types::mode_elevated()) { + tier = bump(tier); + reasons = reasons | types::reason_mode_elevated(); + }; + + RiskOutput { tier, reasons, exposure_bps: exposure } +} + +/// What a tier costs: approvals, guardian confirmations, and the wait before execution. +public fun requirements(p: &Policy, tier: u8): (u8, u8, u64) { + if (tier == types::tier_low()) { + (p.approvals_low(), 0, 0) + } else if (tier == types::tier_high()) { + (p.approvals_high(), 0, p.delay_high()) + } else { + let guardians = if (p.guardian_required_critical()) p.guardian_threshold() else 0; + (p.approvals_critical(), guardians, p.delay_critical()) + } +} + +/// Elevated halves the caps, never below one unit, so a vault that has already seen something +/// wrong keeps paying salaries but cannot be emptied at the usual rate. +public fun effective_caps(per_tx_max: u64, daily_max: u64, mode: u8): (u64, u64) { + if (mode != types::mode_elevated()) return (per_tx_max, daily_max); + (half(per_tx_max), half(daily_max)) +} + +fun half(x: u64): u64 { + if (x == 0) return 0; + let h = x / 2; + if (h == 0) 1 else h +} diff --git a/sui/sources/types.move b/sui/sources/types.move new file mode 100644 index 0000000..2322e78 --- /dev/null +++ b/sui/sources/types.move @@ -0,0 +1,143 @@ +/// Shared vocabulary for the Skur authorization layer: roles, risk tiers, recipient trust, +/// security modes, proposal kinds and the reasons a payment was escalated. +/// +/// These are the same values the TypeScript engine and the interfaces use, so a tier shown to a +/// signer is the tier the chain computed. +module skur::types; + +// ---------------------------------------------------------------- roles (a bitmask per member) +const ROLE_OWNER: u8 = 1; +const ROLE_APPROVER: u8 = 2; +const ROLE_EXECUTOR: u8 = 4; +const ROLE_GUARDIAN: u8 = 8; +/// A proposer may open proposals and nothing else. It is the role an automated agent holds: it +/// can ask the treasury to pay, it cannot approve, confirm or execute, and so it can never move +/// money on its own however thoroughly it is compromised. +const ROLE_PROPOSER: u8 = 16; +const ROLE_TREASURY_MASK: u8 = 23; // owner | approver | executor | proposer +/// Any role that is allowed to open a proposal. +const ROLE_CAN_PROPOSE: u8 = 23; +const ROLE_ALL: u8 = 31; + +public fun role_owner(): u8 { ROLE_OWNER } +public fun role_approver(): u8 { ROLE_APPROVER } +public fun role_executor(): u8 { ROLE_EXECUTOR } +public fun role_guardian(): u8 { ROLE_GUARDIAN } +public fun role_proposer(): u8 { ROLE_PROPOSER } +public fun role_treasury_mask(): u8 { ROLE_TREASURY_MASK } + +public fun has_role(bits: u8, role: u8): bool { bits & role == role } + +/// True when the member holds at least one of the roles in `mask`. +public fun has_any(bits: u8, mask: u8): bool { bits & mask != 0 } + +public fun can_propose(bits: u8): bool { has_any(bits, ROLE_CAN_PROPOSE) } + +/// A guardian is the second control plane: it may hold no treasury role, and no treasury member +/// may hold it. That is what stops one stolen credential from both proposing and vetoing. +public fun roles_valid(bits: u8): bool { + if (bits == 0) return false; + if (bits > ROLE_ALL) return false; + if (has_role(bits, ROLE_GUARDIAN) && (bits & ROLE_TREASURY_MASK) != 0) return false; + true +} + +// ---------------------------------------------------------------- risk tiers +const TIER_LOW: u8 = 0; +const TIER_HIGH: u8 = 1; +const TIER_CRITICAL: u8 = 2; + +public fun tier_low(): u8 { TIER_LOW } +public fun tier_high(): u8 { TIER_HIGH } +public fun tier_critical(): u8 { TIER_CRITICAL } + +// ---------------------------------------------------------------- recipient trust +const TRUST_UNKNOWN: u8 = 0; +const TRUST_NEW: u8 = 1; +const TRUST_VERIFIED: u8 = 2; +const TRUST_TRUSTED: u8 = 3; +const TRUST_RESTRICTED: u8 = 4; +const TRUST_BLOCKED: u8 = 5; + +public fun trust_unknown(): u8 { TRUST_UNKNOWN } +public fun trust_new(): u8 { TRUST_NEW } +public fun trust_verified(): u8 { TRUST_VERIFIED } +public fun trust_trusted(): u8 { TRUST_TRUSTED } +public fun trust_restricted(): u8 { TRUST_RESTRICTED } +public fun trust_blocked(): u8 { TRUST_BLOCKED } +public fun trust_valid(t: u8): bool { t <= TRUST_BLOCKED } + +// ---------------------------------------------------------------- security modes +const MODE_NORMAL: u8 = 0; +const MODE_ELEVATED: u8 = 1; +const MODE_LOCKDOWN: u8 = 2; + +public fun mode_normal(): u8 { MODE_NORMAL } +public fun mode_elevated(): u8 { MODE_ELEVATED } +public fun mode_lockdown(): u8 { MODE_LOCKDOWN } + +// ---------------------------------------------------------------- proposal kinds +const KIND_TRANSFER: u8 = 0; +const KIND_POLICY_UPDATE: u8 = 1; +const KIND_ASSET_LIMITS: u8 = 2; +const KIND_MEMBER_SET: u8 = 3; +const KIND_RECIPIENT_TRUST: u8 = 4; +const KIND_MODE_RELAX: u8 = 5; +const KIND_RECOVERY: u8 = 6; + +public fun kind_transfer(): u8 { KIND_TRANSFER } +public fun kind_policy_update(): u8 { KIND_POLICY_UPDATE } +public fun kind_asset_limits(): u8 { KIND_ASSET_LIMITS } +public fun kind_member_set(): u8 { KIND_MEMBER_SET } +public fun kind_recipient_trust(): u8 { KIND_RECIPIENT_TRUST } +public fun kind_mode_relax(): u8 { KIND_MODE_RELAX } +public fun kind_recovery(): u8 { KIND_RECOVERY } + +// ---------------------------------------------------------------- proposal status +const STATUS_PENDING: u8 = 1; +const STATUS_EXECUTED: u8 = 2; +const STATUS_CANCELLED: u8 = 3; +const STATUS_VETOED: u8 = 4; +const STATUS_EXPIRED: u8 = 5; +/// Refused at execution by a control that must survive the attempt: the circuit breaker. The +/// transaction still succeeds, because the latch it sets has to persist. +const STATUS_BLOCKED: u8 = 6; + +public fun status_pending(): u8 { STATUS_PENDING } +public fun status_executed(): u8 { STATUS_EXECUTED } +public fun status_cancelled(): u8 { STATUS_CANCELLED } +public fun status_vetoed(): u8 { STATUS_VETOED } +public fun status_expired(): u8 { STATUS_EXPIRED } +public fun status_blocked(): u8 { STATUS_BLOCKED } + +// ---------------------------------------------------------------- why a payment was escalated +const REASON_AMOUNT_HIGH: u16 = 1; +const REASON_AMOUNT_CRITICAL: u16 = 2; +const REASON_EXPOSURE_HIGH: u16 = 4; +const REASON_EXPOSURE_CRITICAL: u16 = 8; +const REASON_RECIPIENT_PROBATION: u16 = 16; +const REASON_RECIPIENT_RESTRICTED: u16 = 32; +const REASON_MODE_ELEVATED: u16 = 64; +const REASON_VELOCITY_PRESSURE: u16 = 128; +const REASON_RECIPIENT_UNKNOWN: u16 = 256; +const REASON_ENVELOPE_PRESSURE: u16 = 512; + +public fun reason_amount_high(): u16 { REASON_AMOUNT_HIGH } +public fun reason_amount_critical(): u16 { REASON_AMOUNT_CRITICAL } +public fun reason_exposure_high(): u16 { REASON_EXPOSURE_HIGH } +public fun reason_exposure_critical(): u16 { REASON_EXPOSURE_CRITICAL } +public fun reason_recipient_probation(): u16 { REASON_RECIPIENT_PROBATION } +public fun reason_recipient_restricted(): u16 { REASON_RECIPIENT_RESTRICTED } +public fun reason_mode_elevated(): u16 { REASON_MODE_ELEVATED } +public fun reason_velocity_pressure(): u16 { REASON_VELOCITY_PRESSURE } +public fun reason_recipient_unknown(): u16 { REASON_RECIPIENT_UNKNOWN } +public fun reason_envelope_pressure(): u16 { REASON_ENVELOPE_PRESSURE } + +/// Basis points denominator, and one hour in milliseconds (Sui clocks are millisecond-based). +const BPS: u64 = 10_000; +const HOUR_MS: u64 = 3_600_000; +const DAY_MS: u64 = 86_400_000; + +public fun bps(): u64 { BPS } +public fun hour_ms(): u64 { HOUR_MS } +public fun day_ms(): u64 { DAY_MS } diff --git a/sui/sources/vault.move b/sui/sources/vault.move new file mode 100644 index 0000000..9907f66 --- /dev/null +++ b/sui/sources/vault.move @@ -0,0 +1,1639 @@ +/// The Skur vault: a shared object that holds a treasury and will only let it move when the +/// policy, the recipient's standing, the day's outflow, the loss envelope and the vault's own +/// security posture all agree. +/// +/// A plain multisig answers one question — did k of n sign? A Skur vault answers a harder one: +/// given everything that has happened recently, *should* this payment go out right now, and if so +/// how much authorization does it need? Every control below is enforced here, in Move, not in an +/// interface or a backend. +module skur::vault; + +use std::string::String; +use std::type_name::{Self, TypeName}; +use sui::bag::{Self, Bag}; +use sui::balance::{Self, Balance}; +use sui::clock::{Self, Clock}; +use sui::coin::{Self, Coin}; +use sui::event; +use sui::table::{Self, Table}; +use sui::vec_set::{Self, VecSet}; +use skur::policy::{Self, Policy, AssetLimits}; +use skur::risk; +use skur::types; + +// ---------------------------------------------------------------- errors +const E_NOT_MEMBER: u64 = 100; +const E_NOT_OWNER: u64 = 101; +const E_NOT_APPROVER: u64 = 102; +const E_NOT_EXECUTOR: u64 = 103; +const E_NOT_GUARDIAN: u64 = 104; +const E_CANNOT_PROPOSE: u64 = 105; +const E_INVALID_ROLES: u64 = 106; +const E_LOCKDOWN: u64 = 107; +const E_ASSET_NOT_APPROVED: u64 = 108; +const E_UNKNOWN_PROPOSAL: u64 = 109; +const E_NOT_PENDING: u64 = 110; +const E_WRONG_KIND: u64 = 111; +const E_WRONG_ASSET: u64 = 112; +const E_TOO_EARLY: u64 = 113; +const E_EXPIRED: u64 = 114; +const E_NOT_EXPIRED: u64 = 115; +const E_NOT_ENOUGH_APPROVALS: u64 = 116; +const E_NOT_ENOUGH_GUARDIANS: u64 = 117; +const E_RECIPIENT_BLOCKED: u64 = 118; +const E_RECIPIENT_IN_PROBATION: u64 = 119; +const E_PER_TX_CAP: u64 = 120; +const E_DAILY_CAP: u64 = 121; +const E_HARD_BLOCK: u64 = 122; +const E_INSUFFICIENT_BALANCE: u64 = 123; +const E_ZERO_AMOUNT: u64 = 124; +const E_NOT_VETOABLE: u64 = 125; +const E_ALREADY_REGISTERED: u64 = 126; +const E_UNKNOWN_RECIPIENT: u64 = 127; +const E_INVALID_TRUST: u64 = 128; +const E_INVALID_MODE: u64 = 129; +const E_NOT_A_RELAXATION: u64 = 130; +const E_NOT_PROPOSER_OR_OWNER: u64 = 131; +const E_LAST_OWNER: u64 = 132; +const E_GUARDIAN_HAS_TREASURY_ROLE: u64 = 133; +const E_ASSET_ALREADY_SET_UP: u64 = 134; +const E_ROSTER_MISMATCH: u64 = 135; +const E_SELF_RECOVERY: u64 = 136; +const E_NO_SUCH_MEMBER: u64 = 137; + +// ---------------------------------------------------------------- state +/// Cumulative outflow, counted per asset in anchored windows. +/// +/// The envelope is measured against `envelope_basis`, the balance when the window opened, not the +/// live balance. Measuring against the live balance would let a drain shrink its own denominator +/// and keep every later transfer under the same percentage. +public struct Velocity has copy, drop, store { + day_anchor: u64, + day_spent: u64, + envelope_anchor: u64, + envelope_spent: u64, + envelope_basis: u64, +} + +/// A payment destination and how much the vault trusts it. +public struct Recipient has copy, drop, store { + trust: u8, + registered_at: u64, + /// Until this moment the recipient is in probation and every payment is escalated. + activates_at: u64, + paid_count: u64, + last_paid: u64, + label: String, +} + +/// One pending or settled request. Every kind shares the same lifecycle — propose, approve, +/// optionally confirm, wait, execute — so there is exactly one path through which anything +/// changes, and exactly one place where the final checks run. +public struct Proposal has store { + id: u64, + kind: u8, + status: u8, + proposer: address, + created_at: u64, + /// Not executable before this moment: the tier's timelock, and for a new recipient, their + /// activation time, whichever is later. + executable_at: u64, + expires_at: u64, + /// Requirements pinned when the proposal was opened. At execution the live requirements are + /// recomputed and the stricter of the two applies, so tightening the policy affects proposals + /// already in flight while loosening it cannot rescue one. + req_approvals: u8, + req_guardians: u8, + tier: u8, + reasons: u16, + exposure_bps: u64, + policy_version: u64, + /// Which controls this proposal would give up. Non-zero routes it through the policy-change + /// delay and makes it vetoable. + reduction_mask: u32, + approvals: VecSet
      , + confirmations: VecSet
      , + // transfer payload + asset: Option, + amount: u64, + recipient: address, + memo: String, + // governance payloads + new_policy: Option, + new_limits: Option, + member: address, + member_prev: address, + member_roles: u8, + trust_level: u8, + target_mode: u8, +} + +public struct Vault has key, store { + id: UID, + name: String, + policy: Policy, + /// Bumped on every policy change, so a proposal can tell whether the rules moved under it. + policy_version: u64, + mode: u8, + /// Why the vault last escalated its posture; a bitmask of `types::reason_*`. + posture_reasons: u16, + members: Table, + owner_count: u64, + approver_count: u64, + executor_count: u64, + guardian_count: u64, + limits: Table, + /// `TypeName` -> `Balance`. One vault holds every asset the organization approved. + funds: Bag, + velocity: Table, + recipients: Table, + proposals: Table, + next_proposal: u64, + pending_count: u64, + created_at: u64, +} + +// ---------------------------------------------------------------- events +public struct VaultCreated has copy, drop { + vault: ID, + name: String, + creator: address, + owner_count: u64, + guardian_count: u64, + at: u64, +} + +public struct Deposited has copy, drop { + vault: ID, + asset: TypeName, + amount: u64, + balance: u64, + from: address, + at: u64, +} + +public struct ProposalOpened has copy, drop { + vault: ID, + proposal: u64, + kind: u8, + proposer: address, + asset: Option, + amount: u64, + recipient: address, + tier: u8, + reasons: u16, + exposure_bps: u64, + req_approvals: u8, + req_guardians: u8, + executable_at: u64, + expires_at: u64, + reduction_mask: u32, + memo: String, + at: u64, +} + +public struct Approved has copy, drop { + vault: ID, + proposal: u64, + approver: address, + approvals: u64, + req_approvals: u8, + at: u64, +} + +public struct Confirmed has copy, drop { + vault: ID, + proposal: u64, + guardian: address, + confirmations: u64, + req_guardians: u8, + at: u64, +} + +public struct Settled has copy, drop { + vault: ID, + proposal: u64, + kind: u8, + status: u8, + actor: address, + at: u64, +} + +public struct Executed has copy, drop { + vault: ID, + proposal: u64, + kind: u8, + asset: Option, + amount: u64, + recipient: address, + executor: address, + tier: u8, + balance_after: u64, + day_spent: u64, + at: u64, +} + +/// The breaker refused a transfer that was otherwise fully authorized. +public struct BreakerTripped has copy, drop { + vault: ID, + proposal: u64, + asset: TypeName, + amount: u64, + envelope_spent: u64, + envelope_limit: u64, + envelope_basis: u64, + at: u64, +} + +public struct ModeChanged has copy, drop { + vault: ID, + from: u8, + to: u8, + actor: address, + reasons: u16, + at: u64, +} + +public struct PolicyChanged has copy, drop { + vault: ID, + proposal: u64, + version: u64, + reduction_mask: u32, + at: u64, +} + +public struct LimitsChanged has copy, drop { + vault: ID, + proposal: u64, + asset: TypeName, + approved: bool, + low_max: u64, + high_max: u64, + per_tx_max: u64, + daily_max: u64, + reduction_mask: u32, + at: u64, +} + +public struct MemberChanged has copy, drop { + vault: ID, + proposal: u64, + member: address, + roles_before: u8, + roles_after: u8, + at: u64, +} + +public struct RecipientRegistered has copy, drop { + vault: ID, + recipient: address, + trust: u8, + activates_at: u64, + label: String, + actor: address, + at: u64, +} + +public struct RecipientTrustChanged has copy, drop { + vault: ID, + proposal: u64, + recipient: address, + from: u8, + to: u8, + actor: address, + at: u64, +} + +public struct Recovered has copy, drop { + vault: ID, + proposal: u64, + lost: address, + replacement: address, + roles: u8, + at: u64, +} + +// ---------------------------------------------------------------- creation +/// A vault under construction. It has no abilities, so the transaction that opened it must also +/// finish it: `begin`, then any number of `setup_asset` / `setup_recipient` calls, then `finish`, +/// all in one programmable transaction block. There is no window in which a half-configured +/// vault is reachable by anyone. +public struct VaultSetup { + vault: Vault, +} + +public fun begin( + name: String, + policy: Policy, + members: vector
      , + roles: vector, + clock: &Clock, + ctx: &mut TxContext, +): VaultSetup { + assert!(members.length() == roles.length(), E_ROSTER_MISMATCH); + policy.assert_valid(); + let now = clock::timestamp_ms(clock); + + let mut vault = Vault { + id: object::new(ctx), + name, + policy, + policy_version: 1, + mode: types::mode_normal(), + posture_reasons: 0, + members: table::new(ctx), + owner_count: 0, + approver_count: 0, + executor_count: 0, + guardian_count: 0, + limits: table::new(ctx), + funds: bag::new(ctx), + velocity: table::new(ctx), + recipients: table::new(ctx), + proposals: table::new(ctx), + next_proposal: 1, + pending_count: 0, + created_at: now, + }; + + let mut i = 0; + while (i < members.length()) { + let who = members[i]; + let bits = roles[i]; + assert!(types::roles_valid(bits), E_INVALID_ROLES); + assert!(!vault.members.contains(who), E_ALREADY_REGISTERED); + vault.members.add(who, bits); + tally(&mut vault, bits, true); + i = i + 1; + }; + + VaultSetup { vault } +} + +/// Approve an asset the vault may hold and pay out, with its tier boundaries and caps. +public fun setup_asset( + s: &mut VaultSetup, + approved: bool, + low_max: u64, + high_max: u64, + per_tx_max: u64, + daily_max: u64, +) { + let key = type_name::get(); + assert!(!s.vault.limits.contains(key), E_ASSET_ALREADY_SET_UP); + let limits = policy::new_limits(approved, low_max, high_max, per_tx_max, daily_max); + limits.assert_limits_valid(); + s.vault.limits.add(key, limits); + s.vault.velocity.add(key, Velocity { + day_anchor: s.vault.created_at, + day_spent: 0, + envelope_anchor: s.vault.created_at, + envelope_spent: 0, + envelope_basis: 0, + }); +} + +/// Seed the address book. Recipients added at setup still serve their activation delay, so a +/// vault cannot be created with a pre-trusted drain address that is immediately cheap to pay. +public fun setup_recipient(s: &mut VaultSetup, who: address, label: String) { + assert!(!s.vault.recipients.contains(who), E_ALREADY_REGISTERED); + let activates_at = s.vault.created_at + s.vault.policy.recipient_activation_delay(); + s.vault.recipients.add(who, Recipient { + trust: types::trust_new(), + registered_at: s.vault.created_at, + activates_at, + paid_count: 0, + last_paid: 0, + label, + }); +} + +/// Validate the finished roster against the policy and publish the vault as a shared object. +public fun finish(s: VaultSetup, ctx: &TxContext) { + let VaultSetup { vault } = s; + vault.policy.assert_counts_valid( + vault.owner_count, + vault.approver_count, + vault.executor_count, + vault.guardian_count, + ); + event::emit(VaultCreated { + vault: object::id(&vault), + name: vault.name, + creator: ctx.sender(), + owner_count: vault.owner_count, + guardian_count: vault.guardian_count, + at: vault.created_at, + }); + transfer::share_object(vault); +} + +// ---------------------------------------------------------------- roster bookkeeping +fun tally(v: &mut Vault, bits: u8, add: bool) { + let d = if (add) 1 else 0; + if (types::has_role(bits, types::role_owner())) { + v.owner_count = if (add) v.owner_count + 1 else v.owner_count - 1; + }; + if (types::has_role(bits, types::role_approver())) { + v.approver_count = if (add) v.approver_count + 1 else v.approver_count - 1; + }; + if (types::has_role(bits, types::role_executor())) { + v.executor_count = if (add) v.executor_count + 1 else v.executor_count - 1; + }; + if (types::has_role(bits, types::role_guardian())) { + v.guardian_count = if (add) v.guardian_count + 1 else v.guardian_count - 1; + }; + let _ = d; +} + +fun roles_of(v: &Vault, who: address): u8 { + if (v.members.contains(who)) *v.members.borrow(who) else 0 +} + +fun assert_role(v: &Vault, who: address, role: u8, code: u64) { + assert!(types::has_role(roles_of(v, who), role), code); +} + +fun assert_not_lockdown(v: &Vault) { + assert!(v.mode != types::mode_lockdown(), E_LOCKDOWN); +} + +// ---------------------------------------------------------------- read access +public fun name(v: &Vault): String { v.name } +public fun policy(v: &Vault): &Policy { &v.policy } +public fun policy_version(v: &Vault): u64 { v.policy_version } +public fun mode(v: &Vault): u8 { v.mode } +public fun posture_reasons(v: &Vault): u16 { v.posture_reasons } +public fun owner_count(v: &Vault): u64 { v.owner_count } +public fun approver_count(v: &Vault): u64 { v.approver_count } +public fun executor_count(v: &Vault): u64 { v.executor_count } +public fun guardian_count(v: &Vault): u64 { v.guardian_count } +public fun pending_count(v: &Vault): u64 { v.pending_count } +public fun proposal_count(v: &Vault): u64 { v.next_proposal - 1 } +public fun member_roles(v: &Vault, who: address): u8 { roles_of(v, who) } + +public fun balance_of(v: &Vault): u64 { + let key = type_name::get(); + if (!v.funds.contains(key)) return 0; + balance::value(v.funds.borrow>(key)) +} + +public fun limits_of(v: &Vault): AssetLimits { + let key = type_name::get(); + if (!v.limits.contains(key)) { + policy::new_limits(false, 0, 0, 0, 0) + } else { + *v.limits.borrow(key) + } +} + +public fun recipient_trust(v: &Vault, who: address): u8 { + if (!v.recipients.contains(who)) return types::trust_unknown(); + v.recipients.borrow(who).trust +} + +public fun recipient_activates_at(v: &Vault, who: address): u64 { + if (!v.recipients.contains(who)) return 0; + v.recipients.borrow(who).activates_at +} + +/// Day spent and envelope spent for an asset, after rolling any window that has already closed. +public fun outflow_of(v: &Vault, clock: &Clock): (u64, u64) { + let key = type_name::get(); + if (!v.velocity.contains(key)) return (0, 0); + let vel = *v.velocity.borrow(key); + let now = clock::timestamp_ms(clock); + let day = if (now >= vel.day_anchor + types::day_ms()) 0 else vel.day_spent; + let window = v.policy.envelope_window(); + let env = if (window != 0 && now >= vel.envelope_anchor + window) 0 else vel.envelope_spent; + (day, env) +} + +public fun proposal_status(v: &Vault, id: u64): u8 { + if (!v.proposals.contains(id)) return 0; + v.proposals.borrow(id).status +} + +public fun proposal_approvals(v: &Vault, id: u64): u64 { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + v.proposals.borrow(id).approvals.size() +} + +public fun proposal_confirmations(v: &Vault, id: u64): u64 { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + v.proposals.borrow(id).confirmations.size() +} + +/// Approvals that would still count right now: a removed signer's approval is not one. +public fun live_approvals(v: &Vault, id: u64): u64 { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + count_live(v, &v.proposals.borrow(id).approvals, types::role_approver()) +} + +public fun live_confirmations(v: &Vault, id: u64): u64 { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + count_live(v, &v.proposals.borrow(id).confirmations, types::role_guardian()) +} + +fun count_live(v: &Vault, set: &VecSet
      , role: u8): u64 { + let keys = set.keys(); + let mut n = 0; + let mut i = 0; + while (i < keys.length()) { + if (types::has_role(roles_of(v, keys[i]), role)) n = n + 1; + i = i + 1; + }; + n +} + +// ---------------------------------------------------------------- deposits +/// Anyone may fund an approved asset. Deposits are never gated: the controls exist to govern money +/// leaving, and refusing incoming funds would only strand them. +public fun deposit(v: &mut Vault, c: Coin, clock: &Clock, ctx: &TxContext) { + let key = type_name::get(); + assert!(v.limits.contains(key) && v.limits.borrow(key).limits_approved(), E_ASSET_NOT_APPROVED); + let amount = c.value(); + assert!(amount > 0, E_ZERO_AMOUNT); + let incoming = c.into_balance(); + if (v.funds.contains(key)) { + balance::join(v.funds.borrow_mut>(key), incoming); + } else { + v.funds.add(key, incoming); + }; + event::emit(Deposited { + vault: object::id(v), + asset: key, + amount, + balance: balance_of(v), + from: ctx.sender(), + at: clock::timestamp_ms(clock), + }); +} + +// ---------------------------------------------------------------- recipients +/// Any owner may add a recipient at the restrictive default: trust `NEW`, serving an activation +/// delay. Raising trust beyond that is a governance action with a timelock. +public fun register_recipient( + v: &mut Vault, + who: address, + label: String, + clock: &Clock, + ctx: &TxContext, +) { + assert_not_lockdown(v); + assert_role(v, ctx.sender(), types::role_owner(), E_NOT_OWNER); + assert!(!v.recipients.contains(who), E_ALREADY_REGISTERED); + let now = clock::timestamp_ms(clock); + let activates_at = now + v.policy.recipient_activation_delay(); + v.recipients.add(who, Recipient { + trust: types::trust_new(), + registered_at: now, + activates_at, + paid_count: 0, + last_paid: 0, + label, + }); + event::emit(RecipientRegistered { + vault: object::id(v), + recipient: who, + trust: types::trust_new(), + activates_at, + label, + actor: ctx.sender(), + at: now, + }); +} + +/// A guardian may block or restrict a recipient immediately and alone. This is the one unilateral +/// power in the system and it can only ever stop money, never move it. +public fun guardian_restrict( + v: &mut Vault, + who: address, + to: u8, + clock: &Clock, + ctx: &TxContext, +) { + assert_role(v, ctx.sender(), types::role_guardian(), E_NOT_GUARDIAN); + assert!(to == types::trust_restricted() || to == types::trust_blocked(), E_INVALID_TRUST); + let now = clock::timestamp_ms(clock); + let from = if (v.recipients.contains(who)) { + let r = v.recipients.borrow_mut(who); + let before = r.trust; + r.trust = to; + before + } else { + v.recipients.add(who, Recipient { + trust: to, + registered_at: now, + activates_at: now, + paid_count: 0, + last_paid: 0, + label: b"".to_string(), + }); + types::trust_unknown() + }; + event::emit(RecipientTrustChanged { + vault: object::id(v), + proposal: 0, + recipient: who, + from, + to, + actor: ctx.sender(), + at: now, + }); +} + +// ---------------------------------------------------------------- security modes +/// Any owner or guardian may raise the posture at once; a guardian may go straight to Lockdown. +/// Lowering it is never unilateral — see `propose_mode_relax`. +public fun raise_mode(v: &mut Vault, to: u8, reasons: u16, clock: &Clock, ctx: &TxContext) { + let bits = roles_of(v, ctx.sender()); + assert!(bits != 0, E_NOT_MEMBER); + assert!(to == types::mode_elevated() || to == types::mode_lockdown(), E_INVALID_MODE); + assert!(to > v.mode, E_NOT_A_RELAXATION); + if (to == types::mode_lockdown()) { + assert!( + types::has_role(bits, types::role_guardian()) + || types::has_role(bits, types::role_owner()), + E_NOT_GUARDIAN, + ); + } else { + assert!(types::has_any(bits, types::role_treasury_mask() | types::role_guardian()), E_NOT_MEMBER); + }; + set_mode(v, to, reasons, ctx.sender(), clock); +} + +fun set_mode(v: &mut Vault, to: u8, reasons: u16, actor: address, clock: &Clock) { + let from = v.mode; + if (from == to) return; + v.mode = to; + v.posture_reasons = if (to == types::mode_normal()) 0 else v.posture_reasons | reasons; + event::emit(ModeChanged { + vault: object::id(v), + from, + to, + actor, + reasons, + at: clock::timestamp_ms(clock), + }); +} + +const E_ALREADY_VOTED: u64 = 138; +const E_NOT_A_MEMBER_CHANGE: u64 = 139; + +// ---------------------------------------------------------------- proposal plumbing +fun count_with_role(v: &Vault, keys: &vector
      , role: u8): u64 { + let mut n = 0; + let mut i = 0; + while (i < keys.length()) { + if (types::has_role(roles_of(v, keys[i]), role)) n = n + 1; + i = i + 1; + }; + n +} + +fun blank( + id: u64, + kind: u8, + proposer: address, + now: u64, + executable_at: u64, + expires_at: u64, + req_approvals: u8, + req_guardians: u8, + policy_version: u64, + reduction_mask: u32, +): Proposal { + Proposal { + id, + kind, + status: types::status_pending(), + proposer, + created_at: now, + executable_at, + expires_at, + req_approvals, + req_guardians, + tier: types::tier_low(), + reasons: 0, + exposure_bps: 0, + policy_version, + reduction_mask, + approvals: vec_set::empty(), + confirmations: vec_set::empty(), + asset: option::none(), + amount: 0, + recipient: @0x0, + memo: b"".to_string(), + new_policy: option::none(), + new_limits: option::none(), + member: @0x0, + member_prev: @0x0, + member_roles: 0, + trust_level: 0, + target_mode: 0, + } +} + +fun larger(a: u8, b: u8): u8 { if (a > b) a else b } +fun later(a: u64, b: u64): u64 { if (a > b) a else b } + +/// Common checks for anyone acting on a live proposal. +fun assert_live(v: &Vault, id: u64, now: u64) { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + let p = v.proposals.borrow(id); + assert!(p.status == types::status_pending(), E_NOT_PENDING); + assert!(now < p.expires_at, E_EXPIRED); +} + +fun settle(v: &mut Vault, id: u64, status: u8, actor: address, now: u64) { + let kind = { + let p = v.proposals.borrow_mut(id); + p.status = status; + p.kind + }; + v.pending_count = v.pending_count - 1; + event::emit(Settled { vault: object::id(v), proposal: id, kind, status, actor, at: now }); +} + +// ---------------------------------------------------------------- opening a transfer +/// Score a payment and open it for approval. Everything that can refuse the payment outright is +/// checked here *and* again at execution, because the state it reads can change in between. +public fun propose_transfer( + v: &mut Vault, + amount: u64, + recipient: address, + memo: String, + clock: &Clock, + ctx: &mut TxContext, +): u64 { + assert_not_lockdown(v); + let sender = ctx.sender(); + assert!(types::can_propose(roles_of(v, sender)), E_CANNOT_PROPOSE); + assert!(amount > 0, E_ZERO_AMOUNT); + + let key = type_name::get(); + assert!(v.limits.contains(key) && v.limits.borrow(key).limits_approved(), E_ASSET_NOT_APPROVED); + + let now = clock::timestamp_ms(clock); + let limits = limits_of(v); + let asset_balance = balance_of(v); + let trust = recipient_trust(v, recipient); + assert!(trust != types::trust_blocked(), E_RECIPIENT_BLOCKED); + + let (per_tx, daily) = risk::effective_caps( + limits.limits_per_tx_max(), + limits.limits_daily_max(), + v.mode, + ); + assert!(per_tx == 0 || amount <= per_tx, E_PER_TX_CAP); + let (day_spent, _) = outflow_of(v, clock); + assert!(daily == 0 || day_spent + amount <= daily, E_DAILY_CAP); + + let hard_block = v.policy.hard_block_exposure_bps(); + let exposure = risk::exposure_bps(amount, asset_balance); + assert!(hard_block == 0 || exposure < hard_block, E_HARD_BLOCK); + + let activates_at = recipient_activates_at(v, recipient); + let input = risk::new_input( + amount, + asset_balance, + limits.limits_low_max(), + limits.limits_high_max(), + daily, + day_spent, + trust, + now < activates_at, + v.mode, + v.policy.high_exposure_bps(), + v.policy.critical_exposure_bps(), + ); + let assessment = risk::classify(&input); + let (req_approvals, req_guardians, delay) = risk::requirements(&v.policy, assessment.tier()); + + // A new recipient's activation delay is a floor on execution, not a separate wait: the two + // run concurrently and the later one governs. + let executable_at = later(now + delay, activates_at); + let expires_at = now + v.policy.proposal_ttl(); + + let id = v.next_proposal; + v.next_proposal = id + 1; + let mut p = blank( + id, + types::kind_transfer(), + sender, + now, + executable_at, + expires_at, + req_approvals, + req_guardians, + v.policy_version, + 0, + ); + p.asset = option::some(key); + p.amount = amount; + p.recipient = recipient; + p.memo = memo; + p.tier = assessment.tier(); + p.reasons = assessment.reasons(); + p.exposure_bps = assessment.exposure(); + v.proposals.add(id, p); + v.pending_count = v.pending_count + 1; + + event::emit(ProposalOpened { + vault: object::id(v), + proposal: id, + kind: types::kind_transfer(), + proposer: sender, + asset: option::some(key), + amount, + recipient, + tier: assessment.tier(), + reasons: assessment.reasons(), + exposure_bps: assessment.exposure(), + req_approvals, + req_guardians, + executable_at, + expires_at, + reduction_mask: 0, + memo, + at: now, + }); + id +} + +/// What a transfer would cost before anyone commits to it. Pure, and identical to the logic +/// `propose_transfer` and `execute_transfer` run, so a preview cannot overpromise. +public fun preview_transfer( + v: &Vault, + amount: u64, + recipient: address, + clock: &Clock, +): (u8, u16, u64, u8, u8, u64) { + let limits = limits_of(v); + let (day_spent, _) = outflow_of(v, clock); + let now = clock::timestamp_ms(clock); + let (_, daily) = risk::effective_caps( + limits.limits_per_tx_max(), + limits.limits_daily_max(), + v.mode, + ); + let input = risk::new_input( + amount, + balance_of(v), + limits.limits_low_max(), + limits.limits_high_max(), + daily, + day_spent, + recipient_trust(v, recipient), + now < recipient_activates_at(v, recipient), + v.mode, + v.policy.high_exposure_bps(), + v.policy.critical_exposure_bps(), + ); + let a = risk::classify(&input); + let (req_approvals, req_guardians, delay) = risk::requirements(&v.policy, a.tier()); + (a.tier(), a.reasons(), a.exposure(), req_approvals, req_guardians, delay) +} + +// ---------------------------------------------------------------- voting +/// Approvers approve payments; owners approve governance. One signer, one approval, and the +/// approval is recorded against the address so a removed signer's vote stops counting. +public fun approve(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + assert_live(v, id, now); + let sender = ctx.sender(); + let kind = v.proposals.borrow(id).kind; + let role = if (kind == types::kind_transfer()) { + types::role_approver() + } else { + types::role_owner() + }; + let code = if (kind == types::kind_transfer()) E_NOT_APPROVER else E_NOT_OWNER; + assert_role(v, sender, role, code); + + let (count, req) = { + let p = v.proposals.borrow_mut(id); + assert!(!p.approvals.contains(&sender), E_ALREADY_VOTED); + p.approvals.insert(sender); + (p.approvals.size(), p.req_approvals) + }; + event::emit(Approved { + vault: object::id(v), + proposal: id, + approver: sender, + approvals: count, + req_approvals: req, + at: now, + }); +} + +/// A guardian's positive signature, required for critical transfers, recovery and leaving a +/// raised posture. +public fun confirm(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + assert_live(v, id, now); + let sender = ctx.sender(); + assert_role(v, sender, types::role_guardian(), E_NOT_GUARDIAN); + let (count, req) = { + let p = v.proposals.borrow_mut(id); + assert!(!p.confirmations.contains(&sender), E_ALREADY_VOTED); + p.confirmations.insert(sender); + (p.confirmations.size(), p.req_guardians) + }; + event::emit(Confirmed { + vault: object::id(v), + proposal: id, + guardian: sender, + confirmations: count, + req_guardians: req, + at: now, + }); +} + +/// A guardian stops a critical transfer, any weakening of the vault, a recovery or a relaxation — +/// alone, and without ever gaining a way to move funds. Vetoing also raises the posture, because +/// a guardian reaching for the brake is itself a signal. +public fun veto(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + assert_live(v, id, now); + let sender = ctx.sender(); + assert_role(v, sender, types::role_guardian(), E_NOT_GUARDIAN); + { + let p = v.proposals.borrow(id); + let vetoable = p.reduction_mask != 0 + || (p.kind == types::kind_transfer() && p.tier == types::tier_critical()) + || p.kind == types::kind_recovery() + || p.kind == types::kind_mode_relax(); + assert!(vetoable, E_NOT_VETOABLE); + }; + settle(v, id, types::status_vetoed(), sender, now); + if (v.mode == types::mode_normal()) { + set_mode(v, types::mode_elevated(), types::reason_mode_elevated(), sender, clock); + }; +} + +/// The proposer withdraws their own request; any owner can withdraw anyone's. +public fun cancel(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + assert_live(v, id, now); + let sender = ctx.sender(); + let is_proposer = v.proposals.borrow(id).proposer == sender; + assert!( + is_proposer || types::has_role(roles_of(v, sender), types::role_owner()), + E_NOT_PROPOSER_OR_OWNER, + ); + settle(v, id, types::status_cancelled(), sender, now); +} + +/// Anyone may retire a proposal whose lifetime has run out, so a stale approval set cannot sit +/// waiting to be reused. +public fun expire(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + let now = clock::timestamp_ms(clock); + { + let p = v.proposals.borrow(id); + assert!(p.status == types::status_pending(), E_NOT_PENDING); + assert!(now >= p.expires_at, E_NOT_EXPIRED); + }; + settle(v, id, types::status_expired(), ctx.sender(), now); +} + +// ---------------------------------------------------------------- executing a transfer +/// The last gate. Every condition is re-evaluated against the state as it is *now*, not as it was +/// when the proposal was opened: +/// +/// * the approval set is recounted against live roles, so a removed signer no longer counts; +/// * the payment is reclassified, and the stricter of the pinned and live requirements applies; +/// * the recipient's trust and activation are re-read; +/// * the caps and the hard block are re-applied against the live balance and the live day; +/// * the loss envelope is checked last, and if the payment would cross it the vault latches into +/// Lockdown instead of paying. +public fun execute_transfer(v: &mut Vault, id: u64, clock: &Clock, ctx: &mut TxContext) { + let sender = ctx.sender(); + assert_role(v, sender, types::role_executor(), E_NOT_EXECUTOR); + assert_not_lockdown(v); + assert!(v.proposals.contains(id), E_UNKNOWN_PROPOSAL); + let now = clock::timestamp_ms(clock); + let key = type_name::get(); + + let ( + kind, + status, + created_at, + executable_at, + expires_at, + pin_approvals, + pin_guardians, + amount, + recipient, + asset, + ) = { + let p = v.proposals.borrow(id); + ( + p.kind, + p.status, + p.created_at, + p.executable_at, + p.expires_at, + p.req_approvals, + p.req_guardians, + p.amount, + p.recipient, + p.asset, + ) + }; + assert!(kind == types::kind_transfer(), E_WRONG_KIND); + assert!(status == types::status_pending(), E_NOT_PENDING); + assert!(asset.is_some() && *asset.borrow() == key, E_WRONG_ASSET); + assert!(now < expires_at, E_EXPIRED); + + // The asset must still be approved: revoking approval stops payments already in flight. + assert!(v.limits.contains(key) && v.limits.borrow(key).limits_approved(), E_ASSET_NOT_APPROVED); + + let asset_balance = balance_of(v); + assert!(asset_balance >= amount, E_INSUFFICIENT_BALANCE); + + let trust = recipient_trust(v, recipient); + assert!(trust != types::trust_blocked(), E_RECIPIENT_BLOCKED); + let activates_at = recipient_activates_at(v, recipient); + assert!(now >= activates_at, E_RECIPIENT_IN_PROBATION); + + let limits = limits_of(v); + let (per_tx, daily) = risk::effective_caps( + limits.limits_per_tx_max(), + limits.limits_daily_max(), + v.mode, + ); + assert!(per_tx == 0 || amount <= per_tx, E_PER_TX_CAP); + let (day_spent, _) = outflow_of(v, clock); + assert!(daily == 0 || day_spent + amount <= daily, E_DAILY_CAP); + + let hard_block = v.policy.hard_block_exposure_bps(); + let exposure = risk::exposure_bps(amount, asset_balance); + assert!(hard_block == 0 || exposure < hard_block, E_HARD_BLOCK); + + // Reclassify, then take the stricter of what was pinned and what the rules now demand. + let input = risk::new_input( + amount, + asset_balance, + limits.limits_low_max(), + limits.limits_high_max(), + daily, + day_spent, + trust, + false, + v.mode, + v.policy.high_exposure_bps(), + v.policy.critical_exposure_bps(), + ); + let assessment = risk::classify(&input); + let (live_approvals_req, live_guardians_req, live_delay) = + risk::requirements(&v.policy, assessment.tier()); + let need_approvals = larger(pin_approvals, live_approvals_req); + let need_guardians = larger(pin_guardians, live_guardians_req); + assert!(now >= later(executable_at, created_at + live_delay), E_TOO_EARLY); + + let approval_keys = *v.proposals.borrow(id).approvals.keys(); + let confirm_keys = *v.proposals.borrow(id).confirmations.keys(); + assert!( + count_with_role(v, &approval_keys, types::role_approver()) >= (need_approvals as u64), + E_NOT_ENOUGH_APPROVALS, + ); + assert!( + count_with_role(v, &confirm_keys, types::role_guardian()) >= (need_guardians as u64), + E_NOT_ENOUGH_GUARDIANS, + ); + + // The circuit breaker, checked last and charged atomically with the payment. + let envelope_bps = v.policy.envelope_bps(); + let window = v.policy.envelope_window(); + let (tripped, envelope_spent, envelope_limit, envelope_basis, day_after) = { + let vel = v.velocity.borrow_mut(key); + if (now >= vel.day_anchor + types::day_ms()) { + vel.day_anchor = now; + vel.day_spent = 0; + }; + if (window != 0 && now >= vel.envelope_anchor + window) { + vel.envelope_anchor = now; + vel.envelope_spent = 0; + vel.envelope_basis = asset_balance; + }; + // The first charge of the vault's life opens the window against today's balance. + if (vel.envelope_basis == 0) vel.envelope_basis = asset_balance; + + let basis = vel.envelope_basis; + let spent = vel.envelope_spent; + let limit = if (envelope_bps == 0) { + 0 + } else { + (((basis as u128) * (envelope_bps as u128)) / (types::bps() as u128)) as u64 + }; + if (envelope_bps != 0 && (spent as u128) + (amount as u128) > (limit as u128)) { + (true, spent, limit, basis, 0) + } else { + vel.envelope_spent = spent + amount; + vel.day_spent = vel.day_spent + amount; + (false, vel.envelope_spent, limit, basis, vel.day_spent) + } + }; + + if (tripped) { + // Not an abort: the latch has to survive the attempt, so the transaction succeeds, the + // money stays, and the vault is frozen for everyone until owners and guardians agree to + // reopen it. + settle(v, id, types::status_blocked(), sender, now); + event::emit(BreakerTripped { + vault: object::id(v), + proposal: id, + asset: key, + amount, + envelope_spent, + envelope_limit, + envelope_basis, + at: now, + }); + set_mode( + v, + types::mode_lockdown(), + types::reason_envelope_pressure() | types::reason_velocity_pressure(), + sender, + clock, + ); + return + }; + + // Effects before the transfer: the proposal is spent before any value moves. + { + let p = v.proposals.borrow_mut(id); + p.status = types::status_executed(); + p.tier = assessment.tier(); + p.reasons = assessment.reasons(); + p.exposure_bps = exposure; + }; + v.pending_count = v.pending_count - 1; + if (v.recipients.contains(recipient)) { + let r = v.recipients.borrow_mut(recipient); + r.paid_count = r.paid_count + 1; + r.last_paid = now; + }; + + let paid = balance::split(v.funds.borrow_mut>(key), amount); + transfer::public_transfer(coin::from_balance(paid, ctx), recipient); + + event::emit(Executed { + vault: object::id(v), + proposal: id, + kind: types::kind_transfer(), + asset: option::some(key), + amount, + recipient, + executor: sender, + tier: assessment.tier(), + balance_after: balance_of(v), + day_spent: day_after, + at: now, + }); +} + +// ---------------------------------------------------------------- governance +/// Governance proposals share one authorization rule: owner approvals up to the governance +/// threshold, and if the change gives anything up, the policy-change delay plus a guardian veto +/// window on top. A change that only tightens the vault takes effect as soon as owners agree. +fun open_governance( + v: &mut Vault, + kind: u8, + reduction_mask: u32, + delay: u64, + now: u64, + sender: address, +): u64 { + assert_role(v, sender, types::role_owner(), E_NOT_OWNER); + // A vault in Lockdown cannot be talked into weakening itself. + if (reduction_mask != 0) assert_not_lockdown(v); + let id = v.next_proposal; + v.next_proposal = id + 1; + let p = blank( + id, + kind, + sender, + now, + now + delay, + now + v.policy.proposal_ttl(), + v.policy.governance_threshold(), + 0, + v.policy_version, + reduction_mask, + ); + v.proposals.add(id, p); + v.pending_count = v.pending_count + 1; + id +} + +fun emit_opened(v: &Vault, id: u64, kind: u8, sender: address, mask: u32, memo: String) { + let p = v.proposals.borrow(id); + event::emit(ProposalOpened { + vault: object::id(v), + proposal: id, + kind, + proposer: sender, + asset: p.asset, + amount: p.amount, + recipient: p.recipient, + tier: types::tier_low(), + reasons: 0, + exposure_bps: 0, + req_approvals: p.req_approvals, + req_guardians: p.req_guardians, + executable_at: p.executable_at, + expires_at: p.expires_at, + reduction_mask: mask, + memo, + at: p.created_at, + }); +} + +/// Shared final check for every governance kind. +fun authorize_governance(v: &Vault, id: u64, kind: u8, now: u64): u32 { + let p = v.proposals.borrow(id); + assert!(p.kind == kind, E_WRONG_KIND); + assert!(p.status == types::status_pending(), E_NOT_PENDING); + assert!(now < p.expires_at, E_EXPIRED); + assert!(now >= p.executable_at, E_TOO_EARLY); + let keys = *p.approvals.keys(); + assert!( + count_with_role(v, &keys, types::role_owner()) + >= (v.policy.governance_threshold() as u64), + E_NOT_ENOUGH_APPROVALS, + ); + p.reduction_mask +} + +// --- the policy itself +public fun propose_policy( + v: &mut Vault, + next: Policy, + clock: &Clock, + ctx: &TxContext, +): u64 { + next.assert_valid(); + next.assert_counts_valid(v.owner_count, v.approver_count, v.executor_count, v.guardian_count); + let mask = policy::reductions(&v.policy, &next); + let now = clock::timestamp_ms(clock); + let delay = if (mask == 0) 0 else v.policy.policy_change_delay(); + let id = open_governance(v, types::kind_policy_update(), mask, delay, now, ctx.sender()); + v.proposals.borrow_mut(id).new_policy = option::some(next); + emit_opened(v, id, types::kind_policy_update(), ctx.sender(), mask, b"policy".to_string()); + id +} + +public fun execute_policy(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + let mask = authorize_governance(v, id, types::kind_policy_update(), now); + let next = *v.proposals.borrow(id).new_policy.borrow(); + // Re-validated against the roster as it stands now, not as it stood when proposed. + next.assert_valid(); + next.assert_counts_valid(v.owner_count, v.approver_count, v.executor_count, v.guardian_count); + v.policy = next; + v.policy_version = v.policy_version + 1; + settle(v, id, types::status_executed(), ctx.sender(), now); + event::emit(PolicyChanged { + vault: object::id(v), + proposal: id, + version: v.policy_version, + reduction_mask: mask, + at: now, + }); +} + +// --- per-asset limits +public fun propose_asset_limits( + v: &mut Vault, + approved: bool, + low_max: u64, + high_max: u64, + per_tx_max: u64, + daily_max: u64, + clock: &Clock, + ctx: &TxContext, +): u64 { + let next = policy::new_limits(approved, low_max, high_max, per_tx_max, daily_max); + next.assert_limits_valid(); + let key = type_name::get(); + let current = limits_of(v); + let mask = policy::limit_reductions(¤t, &next); + let now = clock::timestamp_ms(clock); + let delay = if (mask == 0) 0 else v.policy.policy_change_delay(); + let id = open_governance(v, types::kind_asset_limits(), mask, delay, now, ctx.sender()); + { + let p = v.proposals.borrow_mut(id); + p.new_limits = option::some(next); + p.asset = option::some(key); + }; + emit_opened(v, id, types::kind_asset_limits(), ctx.sender(), mask, b"limits".to_string()); + id +} + +public fun execute_asset_limits(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + let key = type_name::get(); + let mask = authorize_governance(v, id, types::kind_asset_limits(), now); + let next = { + let p = v.proposals.borrow(id); + assert!(p.asset.is_some() && *p.asset.borrow() == key, E_WRONG_ASSET); + *p.new_limits.borrow() + }; + if (v.limits.contains(key)) { + *v.limits.borrow_mut(key) = next; + } else { + v.limits.add(key, next); + v.velocity.add(key, Velocity { + day_anchor: now, + day_spent: 0, + envelope_anchor: now, + envelope_spent: 0, + envelope_basis: 0, + }); + }; + settle(v, id, types::status_executed(), ctx.sender(), now); + event::emit(LimitsChanged { + vault: object::id(v), + proposal: id, + asset: key, + approved: next.limits_approved(), + low_max: next.limits_low_max(), + high_max: next.limits_high_max(), + per_tx_max: next.limits_per_tx_max(), + daily_max: next.limits_daily_max(), + reduction_mask: mask, + at: now, + }); +} + +// --- the roster +/// Set a member's roles. Zero removes them. Granting any role an address did not already hold is +/// treated as security-reducing: a new key is a new way in, so it waits and can be vetoed. +public fun propose_member( + v: &mut Vault, + who: address, + roles: u8, + clock: &Clock, + ctx: &TxContext, +): u64 { + assert!(roles == 0 || types::roles_valid(roles), E_INVALID_ROLES); + let before = roles_of(v, who); + assert!(before != roles, E_NOT_A_MEMBER_CHANGE); + let granted = roles & (before ^ 255); + let mask: u32 = if (granted != 0) 1 else 0; + let now = clock::timestamp_ms(clock); + let delay = if (mask == 0) 0 else v.policy.policy_change_delay(); + let id = open_governance(v, types::kind_member_set(), mask, delay, now, ctx.sender()); + { + let p = v.proposals.borrow_mut(id); + p.member = who; + p.member_roles = roles; + }; + emit_opened(v, id, types::kind_member_set(), ctx.sender(), mask, b"member".to_string()); + id +} + +public fun execute_member(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + authorize_governance(v, id, types::kind_member_set(), now); + let (who, roles) = { + let p = v.proposals.borrow(id); + (p.member, p.member_roles) + }; + let before = apply_roles(v, who, roles); + // The roster must still satisfy the policy after the change, so a vault can never be left + // with a threshold nobody can reach. + v.policy.assert_counts_valid( + v.owner_count, + v.approver_count, + v.executor_count, + v.guardian_count, + ); + settle(v, id, types::status_executed(), ctx.sender(), now); + event::emit(MemberChanged { + vault: object::id(v), + proposal: id, + member: who, + roles_before: before, + roles_after: roles, + at: now, + }); +} + +fun apply_roles(v: &mut Vault, who: address, roles: u8): u8 { + let before = roles_of(v, who); + if (before != 0) { + tally(v, before, false); + v.members.remove(who); + }; + if (roles != 0) { + assert!(types::roles_valid(roles), E_GUARDIAN_HAS_TREASURY_ROLE); + v.members.add(who, roles); + tally(v, roles, true); + }; + before +} + +// --- recipient trust +public fun propose_recipient_trust( + v: &mut Vault, + who: address, + to: u8, + clock: &Clock, + ctx: &TxContext, +): u64 { + assert!(types::trust_valid(to), E_INVALID_TRUST); + let from = recipient_trust(v, who); + let mask: u32 = if (policy::trust_reduces(from, to)) 1 else 0; + let now = clock::timestamp_ms(clock); + let delay = if (mask == 0) 0 else v.policy.policy_change_delay(); + let id = open_governance(v, types::kind_recipient_trust(), mask, delay, now, ctx.sender()); + { + let p = v.proposals.borrow_mut(id); + p.recipient = who; + p.trust_level = to; + }; + emit_opened(v, id, types::kind_recipient_trust(), ctx.sender(), mask, b"trust".to_string()); + id +} + +public fun execute_recipient_trust(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + authorize_governance(v, id, types::kind_recipient_trust(), now); + let (who, to) = { + let p = v.proposals.borrow(id); + (p.recipient, p.trust_level) + }; + let from = if (v.recipients.contains(who)) { + let r = v.recipients.borrow_mut(who); + let before = r.trust; + r.trust = to; + before + } else { + v.recipients.add(who, Recipient { + trust: to, + registered_at: now, + activates_at: now + v.policy.recipient_activation_delay(), + paid_count: 0, + last_paid: 0, + label: b"".to_string(), + }); + types::trust_unknown() + }; + settle(v, id, types::status_executed(), ctx.sender(), now); + event::emit(RecipientTrustChanged { + vault: object::id(v), + proposal: id, + recipient: who, + from, + to, + actor: ctx.sender(), + at: now, + }); +} + +// --- leaving a raised posture +/// Lowering the posture takes owners, guardians and time, in that order. Nothing about a frozen +/// vault can be undone by whoever froze it alone. +public fun propose_mode_relax( + v: &mut Vault, + to: u8, + clock: &Clock, + ctx: &TxContext, +): u64 { + assert!(to < v.mode, E_NOT_A_RELAXATION); + let now = clock::timestamp_ms(clock); + let sender = ctx.sender(); + assert_role(v, sender, types::role_owner(), E_NOT_OWNER); + let id = v.next_proposal; + v.next_proposal = id + 1; + let mut p = blank( + id, + types::kind_mode_relax(), + sender, + now, + now + v.policy.policy_change_delay(), + now + v.policy.proposal_ttl(), + v.policy.governance_threshold(), + v.policy.guardian_threshold(), + v.policy_version, + 1, + ); + p.target_mode = to; + v.proposals.add(id, p); + v.pending_count = v.pending_count + 1; + emit_opened(v, id, types::kind_mode_relax(), sender, 1, b"relax".to_string()); + id +} + +public fun execute_mode_relax(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + let (to, confirm_keys) = { + let p = v.proposals.borrow(id); + assert!(p.kind == types::kind_mode_relax(), E_WRONG_KIND); + assert!(p.status == types::status_pending(), E_NOT_PENDING); + assert!(now < p.expires_at, E_EXPIRED); + assert!(now >= p.executable_at, E_TOO_EARLY); + let keys = *p.approvals.keys(); + assert!( + count_with_role(v, &keys, types::role_owner()) + >= (v.policy.governance_threshold() as u64), + E_NOT_ENOUGH_APPROVALS, + ); + (p.target_mode, *p.confirmations.keys()) + }; + assert!( + count_with_role(v, &confirm_keys, types::role_guardian()) + >= (v.policy.guardian_threshold() as u64), + E_NOT_ENOUGH_GUARDIANS, + ); + assert!(to < v.mode, E_NOT_A_RELAXATION); + settle(v, id, types::status_executed(), ctx.sender(), now); + set_mode(v, to, 0, ctx.sender(), clock); +} + +// --- recovery +/// Replace a signer whose key is gone. Guardians propose it, the recovery delay runs, any owner +/// can cancel it, the roles move across unchanged, the policy is untouched, and the vault comes +/// out of it in Elevated — because a recovery means something went wrong. +public fun propose_recovery( + v: &mut Vault, + lost: address, + replacement: address, + clock: &Clock, + ctx: &TxContext, +): u64 { + let sender = ctx.sender(); + assert_role(v, sender, types::role_guardian(), E_NOT_GUARDIAN); + assert!(replacement != sender, E_SELF_RECOVERY); + assert!(roles_of(v, lost) != 0, E_NO_SUCH_MEMBER); + assert!(roles_of(v, replacement) == 0, E_ALREADY_REGISTERED); + let now = clock::timestamp_ms(clock); + let id = v.next_proposal; + v.next_proposal = id + 1; + let mut p = blank( + id, + types::kind_recovery(), + sender, + now, + now + v.policy.recovery_delay(), + now + v.policy.proposal_ttl(), + 0, + v.policy.guardian_threshold(), + v.policy_version, + 1, + ); + p.member_prev = lost; + p.member = replacement; + p.member_roles = roles_of(v, lost); + v.proposals.add(id, p); + v.pending_count = v.pending_count + 1; + emit_opened(v, id, types::kind_recovery(), sender, 1, b"recovery".to_string()); + id +} + +public fun execute_recovery(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { + let now = clock::timestamp_ms(clock); + let (lost, replacement, confirm_keys) = { + let p = v.proposals.borrow(id); + assert!(p.kind == types::kind_recovery(), E_WRONG_KIND); + assert!(p.status == types::status_pending(), E_NOT_PENDING); + assert!(now < p.expires_at, E_EXPIRED); + assert!(now >= p.executable_at, E_TOO_EARLY); + (p.member_prev, p.member, *p.confirmations.keys()) + }; + assert!( + count_with_role(v, &confirm_keys, types::role_guardian()) + >= (v.policy.guardian_threshold() as u64), + E_NOT_ENOUGH_GUARDIANS, + ); + // The roles are whatever the lost signer holds at this moment, not what they held when the + // recovery was proposed, so a recovery cannot be used to hand over roles acquired since. + let roles = roles_of(v, lost); + assert!(roles != 0, E_NO_SUCH_MEMBER); + assert!(roles_of(v, replacement) == 0, E_ALREADY_REGISTERED); + apply_roles(v, lost, 0); + apply_roles(v, replacement, roles); + v.policy.assert_counts_valid( + v.owner_count, + v.approver_count, + v.executor_count, + v.guardian_count, + ); + settle(v, id, types::status_executed(), ctx.sender(), now); + event::emit(Recovered { + vault: object::id(v), + proposal: id, + lost, + replacement, + roles, + at: now, + }); + if (v.mode == types::mode_normal()) { + set_mode(v, types::mode_elevated(), types::reason_mode_elevated(), ctx.sender(), clock); + }; +} diff --git a/sui/tests/engine_tests.move b/sui/tests/engine_tests.move new file mode 100644 index 0000000..c4e16b9 --- /dev/null +++ b/sui/tests/engine_tests.move @@ -0,0 +1,369 @@ +/// Vectors for the pure engines. These pin the numbers the interfaces and the simulator rely on: +/// if a tier moves here, it moves everywhere, and this suite says so. +#[test_only] +module skur::engine_tests; + +use skur::policy; +use skur::risk; +use skur::types; + +const HOUR: u64 = 3_600_000; +const DAY: u64 = 86_400_000; + +fun base(): policy::Policy { + policy::new( + 1, 2, 3, // approvals low / high / critical + 2, // governance threshold + 1, // guardian threshold + true, // guardian required for critical + HOUR, // delay high + DAY, // delay critical + 12 * HOUR, // recipient activation + 2 * DAY, // policy change + 3 * DAY, // recovery + 30 * DAY, // proposal ttl + 1_000, // high exposure 10% + 2_500, // critical exposure 25% + 9_000, // hard block 90% + 3_000, // envelope 30% + DAY, // envelope window + ) +} + +fun input(amount: u64, balance: u64, trust: u8, probation: bool, mode: u8): risk::RiskInput { + risk::new_input(amount, balance, 1_000, 10_000, 0, 0, trust, probation, mode, 1_000, 2_500) +} + +// ---------------------------------------------------------------- policy validation +#[test] +fun base_policy_is_valid() { + assert!(policy::validate(&base()) == policy::e_ok(), 0); +} + +#[test] +fun rejects_zero_low_approvals() { + let p = policy::new(0, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&p) == 1, 0); +} + +#[test] +fun rejects_non_monotonic_approvals() { + let p = policy::new(3, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&p) == 2, 0); + let q = policy::new(1, 3, 2, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&q) == 3, 0); +} + +#[test] +fun rejects_guardian_required_without_guardians() { + let p = policy::new(1, 2, 3, 2, 0, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&p) == 5, 0); +} + +#[test] +fun rejects_critical_delay_below_high() { + let p = policy::new(1, 2, 3, 2, 1, true, DAY, HOUR, 0, 0, 0, 30 * DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&p) == 6, 0); +} + +#[test] +fun rejects_high_exposure_above_critical() { + let p = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 3_000, 2_500, 0, 0, 0); + assert!(policy::validate(&p) == 7, 0); +} + +#[test] +fun rejects_hard_block_below_critical() { + let p = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 1_000, 2_500, 2_000, 0, 0); + assert!(policy::validate(&p) == 9, 0); +} + +#[test] +fun rejects_envelope_window_under_an_hour() { + let p = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, 30 * DAY, 0, 0, 0, 3_000, 60_000); + assert!(policy::validate(&p) == 12, 0); +} + +/// A policy whose transfers would expire before their own timelock elapses is unusable, and the +/// vault refuses to hold one. +#[test] +fun rejects_ttl_shorter_than_the_longest_delay() { + let p = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, DAY, 0, 0, 0, 0, 0); + assert!(policy::validate(&p) == 13, 0); +} + +#[test] +fun ttl_must_clear_the_longest_delay_by_an_hour() { + let exact = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, DAY + HOUR, 0, 0, 0, 0, 0); + assert!(policy::validate(&exact) == policy::e_ok(), 0); + let short = policy::new(1, 2, 3, 2, 1, true, HOUR, DAY, 0, 0, 0, DAY + HOUR - 1, 0, 0, 0, 0, 0); + assert!(policy::validate(&short) == 13, 1); +} + +#[test] +fun counts_must_satisfy_the_policy() { + let p = base(); + assert!(policy::validate_counts(&p, 2, 3, 1, 1) == policy::e_ok(), 0); + assert!(policy::validate_counts(&p, 0, 3, 1, 1) == 30, 1); // no owner + assert!(policy::validate_counts(&p, 2, 3, 0, 1) == 31, 2); // no executor + assert!(policy::validate_counts(&p, 1, 3, 1, 1) == 32, 3); // governance > owners + assert!(policy::validate_counts(&p, 2, 2, 1, 1) == 33, 4); // critical > approvers + assert!(policy::validate_counts(&p, 2, 3, 1, 0) == 34, 5); // guardian threshold > guardians +} + +#[test] +fun limits_must_be_coherent() { + assert!(policy::validate_limits(&policy::new_limits(true, 10, 5, 0, 0)) == 20, 0); + assert!(policy::validate_limits(&policy::new_limits(true, 1, 5, 100, 50)) == 21, 1); + // Zero means "no cap", so a zero daily cap cannot be below a per-transaction cap. + assert!( + policy::validate_limits(&policy::new_limits(true, 1, 5, 100, 0)) == policy::e_ok(), + 2, + ); +} + +// ---------------------------------------------------------------- what counts as weakening +#[test] +fun tightening_reports_no_reduction() { + let a = base(); + let b = policy::new( + 2, 3, 4, 3, 2, true, 2 * HOUR, 2 * DAY, DAY, 3 * DAY, 4 * DAY, 30 * DAY, + 500, 1_500, 8_000, 2_000, DAY, + ); + assert!(policy::reductions(&a, &b) == 0, 0); +} + +#[test] +fun fewer_approvals_is_a_reduction() { + let a = base(); + let b = policy::new( + 1, 1, 3, 2, 1, true, HOUR, DAY, 12 * HOUR, 2 * DAY, 3 * DAY, 30 * DAY, + 1_000, 2_500, 9_000, 3_000, DAY, + ); + assert!(policy::reductions(&a, &b) != 0, 0); +} + +#[test] +fun dropping_the_guardian_requirement_is_a_reduction() { + let a = base(); + let b = policy::new( + 1, 2, 3, 2, 1, false, HOUR, DAY, 12 * HOUR, 2 * DAY, 3 * DAY, 30 * DAY, + 1_000, 2_500, 9_000, 3_000, DAY, + ); + assert!(policy::reductions(&a, &b) == policy::r_guardian_not_required(), 0); +} + +/// Disabling a threshold by setting it to zero is the loosest move available, and must not be +/// mistaken for tightening just because the number went down. +#[test] +fun zeroing_the_envelope_is_a_reduction() { + let a = base(); + let b = policy::new( + 1, 2, 3, 2, 1, true, HOUR, DAY, 12 * HOUR, 2 * DAY, 3 * DAY, 30 * DAY, + 1_000, 2_500, 9_000, 0, DAY, + ); + assert!(policy::reductions(&a, &b) == policy::r_envelope(), 0); +} + +#[test] +fun a_longer_proposal_lifetime_is_a_reduction() { + let a = base(); + let b = policy::new( + 1, 2, 3, 2, 1, true, HOUR, DAY, 12 * HOUR, 2 * DAY, 3 * DAY, 60 * DAY, + 1_000, 2_500, 9_000, 3_000, DAY, + ); + assert!(policy::reductions(&a, &b) != 0, 0); +} + +#[test] +fun weakening_a_cap_to_zero_is_a_reduction() { + let a = policy::new_limits(true, 100, 1_000, 500, 5_000); + let b = policy::new_limits(true, 100, 1_000, 0, 5_000); + assert!(policy::limit_reductions(&a, &b) != 0, 0); + let c = policy::new_limits(true, 100, 1_000, 400, 5_000); + assert!(policy::limit_reductions(&a, &c) == 0, 1); +} + +#[test] +fun approving_a_new_asset_is_a_reduction() { + let a = policy::new_limits(false, 0, 0, 0, 0); + let b = policy::new_limits(true, 100, 1_000, 0, 0); + assert!(policy::limit_reductions(&a, &b) & policy::r_asset_newly_approved() != 0, 0); +} + +#[test] +fun lifting_a_restriction_reduces_but_imposing_one_does_not() { + assert!(policy::trust_reduces(types::trust_restricted(), types::trust_verified()), 0); + assert!(policy::trust_reduces(types::trust_new(), types::trust_trusted()), 1); + assert!(!policy::trust_reduces(types::trust_trusted(), types::trust_blocked()), 2); + assert!(!policy::trust_reduces(types::trust_verified(), types::trust_new()), 3); +} + +// ---------------------------------------------------------------- roles +#[test] +fun a_guardian_cannot_hold_a_treasury_role() { + assert!(types::roles_valid(types::role_guardian()), 0); + assert!(types::roles_valid(types::role_owner() | types::role_approver()), 1); + assert!(!types::roles_valid(types::role_guardian() | types::role_owner()), 2); + assert!(!types::roles_valid(types::role_guardian() | types::role_proposer()), 3); + assert!(!types::roles_valid(0), 4); +} + +#[test] +fun a_proposer_can_only_propose() { + let agent = types::role_proposer(); + assert!(types::can_propose(agent), 0); + assert!(!types::has_role(agent, types::role_approver()), 1); + assert!(!types::has_role(agent, types::role_executor()), 2); + assert!(!types::has_role(agent, types::role_owner()), 3); +} + +// ---------------------------------------------------------------- risk classification +#[test] +fun exposure_is_a_share_of_holdings() { + assert!(risk::exposure_bps(0, 1_000) == 0, 0); + assert!(risk::exposure_bps(100, 1_000) == 1_000, 1); + assert!(risk::exposure_bps(1_000, 1_000) == types::bps(), 2); + assert!(risk::exposure_bps(1_500, 1_000) == types::bps(), 3); + // Paying out of an empty balance is full exposure, not a division by zero. + assert!(risk::exposure_bps(5, 0) == types::bps(), 4); +} + +/// Exposure is computed in 128-bit space, so a treasury large enough to overflow a naive +/// `amount * 10_000` still classifies correctly. +#[test] +fun exposure_survives_a_large_treasury() { + let big = 1_000_000_000_000_000_000; // 1e18 + assert!(risk::exposure_bps(big / 4, big) == 2_500, 0); +} + +#[test] +fun amount_sets_the_tier() { + let low = risk::classify(&input(500, 1_000_000, types::trust_verified(), false, types::mode_normal())); + assert!(low.tier() == types::tier_low(), 0); + assert!(low.reasons() == 0, 1); + + let high = risk::classify(&input(5_000, 1_000_000, types::trust_verified(), false, types::mode_normal())); + assert!(high.tier() == types::tier_high(), 2); + assert!(high.reasons() & types::reason_amount_high() != 0, 3); + + let crit = risk::classify(&input(50_000, 10_000_000, types::trust_verified(), false, types::mode_normal())); + assert!(crit.tier() == types::tier_critical(), 4); + assert!(crit.reasons() & types::reason_amount_critical() != 0, 5); +} + +/// A small payment out of a small treasury is still a big payment. +#[test] +fun share_of_treasury_escalates_on_its_own() { + let o = risk::classify(&input(500, 4_000, types::trust_verified(), false, types::mode_normal())); + assert!(o.tier() == types::tier_high(), 0); + assert!(o.reasons() & types::reason_exposure_high() != 0, 1); + + let c = risk::classify(&input(900, 3_000, types::trust_verified(), false, types::mode_normal())); + assert!(c.tier() == types::tier_critical(), 2); + assert!(c.reasons() & types::reason_exposure_critical() != 0, 3); +} + +#[test] +fun an_unknown_recipient_escalates_one_step() { + let o = risk::classify(&input(500, 1_000_000, types::trust_unknown(), false, types::mode_normal())); + assert!(o.tier() == types::tier_high(), 0); + assert!(o.reasons() & types::reason_recipient_unknown() != 0, 1); + + // Already high on amount, an unknown recipient takes it to critical. + let c = risk::classify(&input(5_000, 1_000_000, types::trust_unknown(), false, types::mode_normal())); + assert!(c.tier() == types::tier_critical(), 2); +} + +#[test] +fun probation_escalates_only_until_it_elapses() { + let during = risk::classify(&input(500, 1_000_000, types::trust_new(), true, types::mode_normal())); + assert!(during.tier() == types::tier_high(), 0); + assert!(during.reasons() & types::reason_recipient_probation() != 0, 1); + + let after = risk::classify(&input(500, 1_000_000, types::trust_new(), false, types::mode_normal())); + assert!(after.tier() == types::tier_low(), 2); +} + +#[test] +fun a_restricted_recipient_is_always_critical() { + let o = risk::classify(&input(1, 1_000_000_000, types::trust_restricted(), false, types::mode_normal())); + assert!(o.tier() == types::tier_critical(), 0); + assert!(o.reasons() & types::reason_recipient_restricted() != 0, 1); +} + +#[test] +fun trusted_recipients_are_never_discounted_below_the_amount_tier() { + let o = risk::classify(&input(50_000, 10_000_000, types::trust_trusted(), false, types::mode_normal())); + assert!(o.tier() == types::tier_critical(), 0); +} + +/// Crossing half the day's allowance escalates, so splitting a drain hits the higher bar partway +/// through rather than never. +#[test] +fun velocity_pressure_escalates_mid_drain() { + let quiet = risk::new_input( + 100, 1_000_000, 1_000, 10_000, 10_000, 0, + types::trust_verified(), false, types::mode_normal(), 1_000, 2_500, + ); + assert!(risk::classify(&quiet).tier() == types::tier_low(), 0); + + let pressured = risk::new_input( + 100, 1_000_000, 1_000, 10_000, 10_000, 5_000, + types::trust_verified(), false, types::mode_normal(), 1_000, 2_500, + ); + let o = risk::classify(&pressured); + assert!(o.tier() == types::tier_high(), 1); + assert!(o.reasons() & types::reason_velocity_pressure() != 0, 2); +} + +#[test] +fun elevated_mode_escalates_everything() { + let o = risk::classify(&input(500, 1_000_000, types::trust_verified(), false, types::mode_elevated())); + assert!(o.tier() == types::tier_high(), 0); + assert!(o.reasons() & types::reason_mode_elevated() != 0, 1); + + let c = risk::classify(&input(5_000, 1_000_000, types::trust_verified(), false, types::mode_elevated())); + assert!(c.tier() == types::tier_critical(), 2); +} + +/// Several signals at once, each recorded, so a reviewer sees every reason and not just the +/// loudest one. +#[test] +fun reasons_accumulate() { + let i = risk::new_input( + 5_000, 20_000, 1_000, 10_000, 10_000, 6_000, + types::trust_unknown(), true, types::mode_elevated(), 1_000, 2_500, + ); + let o = risk::classify(&i); + assert!(o.tier() == types::tier_critical(), 0); + assert!(o.reasons() & types::reason_amount_high() != 0, 1); + assert!(o.reasons() & types::reason_exposure_critical() != 0, 2); + assert!(o.reasons() & types::reason_recipient_unknown() != 0, 3); + assert!(o.reasons() & types::reason_velocity_pressure() != 0, 4); + assert!(o.reasons() & types::reason_mode_elevated() != 0, 5); +} + +#[test] +fun requirements_follow_the_tier() { + let p = base(); + let (a, g, d) = risk::requirements(&p, types::tier_low()); + assert!(a == 1 && g == 0 && d == 0, 0); + let (a2, g2, d2) = risk::requirements(&p, types::tier_high()); + assert!(a2 == 2 && g2 == 0 && d2 == HOUR, 1); + let (a3, g3, d3) = risk::requirements(&p, types::tier_critical()); + assert!(a3 == 3 && g3 == 1 && d3 == DAY, 2); +} + +#[test] +fun elevated_halves_the_caps_but_never_to_zero() { + let (p, d) = risk::effective_caps(1_000, 10_000, types::mode_elevated()); + assert!(p == 500 && d == 5_000, 0); + let (p2, d2) = risk::effective_caps(1, 1, types::mode_elevated()); + assert!(p2 == 1 && d2 == 1, 1); + // No cap stays no cap; halving zero would silently freeze the asset. + let (p3, d3) = risk::effective_caps(0, 0, types::mode_elevated()); + assert!(p3 == 0 && d3 == 0, 2); + let (p4, d4) = risk::effective_caps(1_000, 10_000, types::mode_normal()); + assert!(p4 == 1_000 && d4 == 10_000, 3); +} diff --git a/sui/tests/vault_tests.move b/sui/tests/vault_tests.move new file mode 100644 index 0000000..c84fa40 --- /dev/null +++ b/sui/tests/vault_tests.move @@ -0,0 +1,935 @@ +/// End-to-end tests for the vault. Each one is written as the attack or the mistake it defends +/// against, because that is the only reason the control exists. +#[test_only] +module skur::vault_tests; + +use std::string; +use sui::clock::{Self, Clock}; +use sui::coin::{Self, Coin}; +use sui::test_scenario::{Self as ts, Scenario}; +use skur::policy::{Self, Policy}; +use skur::types; +use skur::vault::{Self, Vault}; + +/// A stand-in asset. `Coin` behaves exactly like any other coin type for the vault's +/// purposes, which is the point of keying the treasury by type. +public struct USDC has drop {} + +const OWNER: address = @0xA1; +const OWNER2: address = @0xA2; +const APPROVER: address = @0xA3; +const APPROVER2: address = @0xA4; +const GUARD: address = @0xB1; +const AGENT: address = @0xC1; +const BOB: address = @0xD1; +const EVE: address = @0xD2; +const NEWKEY: address = @0xE1; + +const HOUR: u64 = 3_600_000; +const DAY: u64 = 86_400_000; +const T0: u64 = 1_700_000_000_000; + +const TREASURY: u64 = 1_000_000; + +// abort codes under test +const E_LOCKDOWN: u64 = 107; +const E_NOT_PENDING: u64 = 110; +const E_TOO_EARLY: u64 = 113; +const E_EXPIRED: u64 = 114; +const E_NOT_ENOUGH_APPROVALS: u64 = 116; +const E_NOT_ENOUGH_GUARDIANS: u64 = 117; +const E_RECIPIENT_BLOCKED: u64 = 118; +const E_RECIPIENT_IN_PROBATION: u64 = 119; +const E_PER_TX_CAP: u64 = 120; +const E_DAILY_CAP: u64 = 121; +const E_HARD_BLOCK: u64 = 122; +const E_NOT_APPROVER: u64 = 102; +const E_NOT_EXECUTOR: u64 = 103; +const E_CANNOT_PROPOSE: u64 = 105; +const E_ALREADY_VOTED: u64 = 138; + +// ---------------------------------------------------------------- fixtures +fun make_policy(envelope_bps: u64, hard_block: u64, delay_high: u64): Policy { + policy::new( + 1, 2, 3, // approvals low / high / critical + 2, // governance threshold + 1, // guardian threshold + true, // guardian required for critical + delay_high, + DAY, // critical delay + 12 * HOUR, // recipient activation + 2 * DAY, // policy change + 3 * DAY, // recovery + 30 * DAY, // proposal lifetime + 1_000, // high exposure 10% + 2_500, // critical exposure 25% + hard_block, + envelope_bps, + DAY, // envelope window + ) +} + +fun base_policy(): Policy { make_policy(3_000, 9_000, HOUR) } + +fun boot(sc: &mut Scenario, p: Policy, per_tx: u64, daily: u64, clock: &Clock) { + ts::next_tx(sc, OWNER); + let owner = types::role_owner() | types::role_approver() | types::role_executor(); + let mut s = vault::begin( + string::utf8(b"Skur Treasury"), + p, + vector[OWNER, OWNER2, APPROVER, APPROVER2, GUARD, AGENT], + vector[ + owner, + owner, + types::role_approver(), + types::role_approver(), + types::role_guardian(), + types::role_proposer(), + ], + clock, + sc.ctx(), + ); + vault::setup_asset(&mut s, true, 1_000, 10_000, per_tx, daily); + vault::setup_recipient(&mut s, BOB, string::utf8(b"Payroll")); + vault::finish(s, sc.ctx()); +} + +fun fund(sc: &mut Scenario, clock: &Clock, amount: u64) { + ts::next_tx(sc, OWNER); + let mut v = ts::take_shared(sc); + let c = coin::mint_for_testing(amount, sc.ctx()); + vault::deposit(&mut v, c, clock, sc.ctx()); + ts::return_shared(v); +} + +fun propose(sc: &mut Scenario, who: address, amount: u64, to: address, clock: &Clock): u64 { + ts::next_tx(sc, who); + let mut v = ts::take_shared(sc); + let id = vault::propose_transfer( + &mut v, + amount, + to, + string::utf8(b"invoice"), + clock, + sc.ctx(), + ); + ts::return_shared(v); + id +} + +fun approve(sc: &mut Scenario, who: address, id: u64, clock: &Clock) { + ts::next_tx(sc, who); + let mut v = ts::take_shared(sc); + vault::approve(&mut v, id, clock, sc.ctx()); + ts::return_shared(v); +} + +fun confirm(sc: &mut Scenario, who: address, id: u64, clock: &Clock) { + ts::next_tx(sc, who); + let mut v = ts::take_shared(sc); + vault::confirm(&mut v, id, clock, sc.ctx()); + ts::return_shared(v); +} + +fun execute(sc: &mut Scenario, who: address, id: u64, clock: &Clock) { + ts::next_tx(sc, who); + let mut v = ts::take_shared(sc); + vault::execute_transfer(&mut v, id, clock, sc.ctx()); + ts::return_shared(v); +} + +fun balance(sc: &mut Scenario) : u64 { + ts::next_tx(sc, OWNER); + let v = ts::take_shared(sc); + let b = vault::balance_of(&v); + ts::return_shared(v); + b +} + +fun status(sc: &mut Scenario, id: u64): u8 { + ts::next_tx(sc, OWNER); + let v = ts::take_shared(sc); + let s = vault::proposal_status(&v, id); + ts::return_shared(v); + s +} + +fun current_mode(sc: &mut Scenario): u8 { + ts::next_tx(sc, OWNER); + let v = ts::take_shared(sc); + let m = vault::mode(&v); + ts::return_shared(v); + m +} + +fun tick(clock: &mut Clock, by: u64) { + clock::set_for_testing(clock, clock::timestamp_ms(clock) + by); +} + +/// Past the activation delay of the recipient seeded at setup, so routine payments are routine. +fun settled_clock(sc: &mut Scenario): Clock { + let mut clock = clock::create_for_testing(sc.ctx()); + clock::set_for_testing(&mut clock, T0); + clock +} + +// ---------------------------------------------------------------- the ordinary case +#[test] +fun a_routine_payment_needs_one_approval_and_no_wait() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); // the payroll address has finished activating + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + execute(&mut sc, OWNER, id, &clock); + + assert!(status(&mut sc, id) == types::status_executed(), 0); + assert!(balance(&mut sc) == TREASURY - 500, 1); + + ts::next_tx(&mut sc, BOB); + let paid = ts::take_from_sender>(&sc); + assert!(coin::value(&paid) == 500, 2); + ts::return_to_sender(&sc, paid); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun a_preview_matches_what_the_vault_will_demand() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + ts::next_tx(&mut sc, OWNER); + let v = ts::take_shared(&sc); + // 5_000 is above the routine maximum, so it is high tier: two approvals and an hour's wait. + let (tier, reasons, _, approvals, guardians, delay) = + vault::preview_transfer(&v, 5_000, BOB, &clock); + assert!(tier == types::tier_high(), 0); + assert!(reasons & types::reason_amount_high() != 0, 1); + assert!(approvals == 2 && guardians == 0 && delay == HOUR, 2); + ts::return_shared(v); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun an_unknown_recipient_is_escalated_without_being_registered() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + ts::next_tx(&mut sc, OWNER); + let v = ts::take_shared(&sc); + let (tier, reasons, _, approvals, _, _) = + vault::preview_transfer(&v, 500, EVE, &clock); + assert!(tier == types::tier_high(), 0); + assert!(reasons & types::reason_recipient_unknown() != 0, 1); + assert!(approvals == 2, 2); + ts::return_shared(v); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- stolen credentials +/// One stolen approver key cannot clear a high-tier payment, whatever it signs. +#[test] +#[expected_failure(abort_code = E_NOT_ENOUGH_APPROVALS)] +fun one_signer_cannot_clear_a_high_tier_payment() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 5_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + tick(&mut clock, 2 * HOUR); + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// A signer removed after approving stops counting. The approval set is recounted against the +/// live roster at execution, not trusted as a tally frozen at approval time. +#[test] +#[expected_failure(abort_code = E_NOT_ENOUGH_APPROVALS)] +fun a_removed_signers_approval_stops_counting() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 5_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, APPROVER, id, &clock); + + // Owners remove the approver. Removing a role grants nothing, so it takes effect at once. + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let gid = vault::propose_member(&mut v, APPROVER, 0, &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, gid, &clock); + approve(&mut sc, OWNER2, gid, &clock); + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_member(&mut v2, gid, &clock, sc.ctx()); + assert!(vault::member_roles(&v2, APPROVER) == 0, 0); + ts::return_shared(v2); + + tick(&mut clock, 2 * HOUR); + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_ALREADY_VOTED)] +fun an_approval_cannot_be_replayed() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 5_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_NOT_PENDING)] +fun a_payment_cannot_execute_twice() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + execute(&mut sc, OWNER, id, &clock); + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- recipients +/// A brand-new destination cannot be paid until its activation delay has run, however many +/// signatures it collects. +#[test] +#[expected_failure(abort_code = E_TOO_EARLY)] +fun a_new_recipient_cannot_skip_activation() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, APPROVER, id, &clock); + tick(&mut clock, 2 * HOUR); // past the tier delay, nowhere near activation + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// A guardian can block a destination while a payment to it is already approved and waiting. +#[test] +#[expected_failure(abort_code = E_RECIPIENT_BLOCKED)] +fun a_guardian_can_block_a_recipient_mid_flight() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + vault::guardian_restrict(&mut v, BOB, types::trust_blocked(), &clock, sc.ctx()); + ts::return_shared(v); + + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun registering_a_recipient_starts_it_at_the_restrictive_default() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + vault::register_recipient(&mut v, EVE, string::utf8(b"Vendor"), &clock, sc.ctx()); + assert!(vault::recipient_trust(&v, EVE) == types::trust_new(), 0); + assert!(vault::recipient_activates_at(&v, EVE) == T0 + 12 * HOUR, 1); + ts::return_shared(v); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- caps +#[test] +#[expected_failure(abort_code = E_PER_TX_CAP)] +fun the_per_transaction_cap_refuses_at_proposal_time() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 1_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + propose(&mut sc, OWNER, 2_000, BOB, &clock); + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// Splitting a withdrawal into pieces does not beat the daily cap: the day's outflow is counted +/// cumulatively, and the last piece is refused. +#[test] +#[expected_failure(abort_code = E_DAILY_CAP)] +fun splitting_a_drain_does_not_beat_the_daily_cap() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 0, 1_200, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let a = propose(&mut sc, OWNER, 600, BOB, &clock); + approve(&mut sc, OWNER, a, &clock); + execute(&mut sc, OWNER, a, &clock); + + // Half the day's allowance is now gone, so the next piece is escalated and waits an hour. + let b = propose(&mut sc, OWNER, 600, BOB, &clock); + approve(&mut sc, OWNER, b, &clock); + approve(&mut sc, APPROVER, b, &clock); + tick(&mut clock, 2 * HOUR); + execute(&mut sc, OWNER, b, &clock); + assert!(balance(&mut sc) == TREASURY - 1_200, 0); + + propose(&mut sc, OWNER, 1, BOB, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun the_daily_bucket_reopens_after_a_day() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 0, 1_200, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let a = propose(&mut sc, OWNER, 1_000, BOB, &clock); + approve(&mut sc, OWNER, a, &clock); + approve(&mut sc, APPROVER, a, &clock); + tick(&mut clock, 2 * HOUR); + execute(&mut sc, OWNER, a, &clock); + + tick(&mut clock, DAY + HOUR); + let b = propose(&mut sc, OWNER, 1_000, BOB, &clock); + approve(&mut sc, OWNER, b, &clock); + approve(&mut sc, APPROVER, b, &clock); + tick(&mut clock, 2 * HOUR); + execute(&mut sc, OWNER, b, &clock); + assert!(balance(&mut sc) == TREASURY - 2_000, 0); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// Above the hard block no amount of authorization is enough. It is the one control with no +/// override path at all. +#[test] +#[expected_failure(abort_code = E_HARD_BLOCK)] +fun the_hard_block_cannot_be_approved_around() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 0, 0, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + propose(&mut sc, OWNER, 950_000, BOB, &clock); + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- the circuit breaker +/// The envelope is the last gate. A payment that would cross it is not made, the money stays +/// where it is, and the vault latches into Lockdown — which has to persist, so the transaction +/// succeeds rather than reverting. +#[test] +fun crossing_the_loss_envelope_freezes_the_vault_instead_of_paying() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, make_policy(1_000, 9_000, HOUR), 0, 0, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + // 200_000 is 20% of the treasury; the envelope allows 10% per day. + let id = propose(&mut sc, OWNER, 200_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + approve(&mut sc, APPROVER, id, &clock); + confirm(&mut sc, GUARD, id, &clock); + tick(&mut clock, DAY + HOUR); + execute(&mut sc, OWNER, id, &clock); + + assert!(status(&mut sc, id) == types::status_blocked(), 0); + assert!(balance(&mut sc) == TREASURY, 1); + assert!(current_mode(&mut sc) == types::mode_lockdown(), 2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_LOCKDOWN)] +fun lockdown_stops_new_payments_from_being_opened() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, make_policy(1_000, 9_000, HOUR), 0, 0, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 200_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + approve(&mut sc, APPROVER, id, &clock); + confirm(&mut sc, GUARD, id, &clock); + tick(&mut clock, DAY + HOUR); + execute(&mut sc, OWNER, id, &clock); + + propose(&mut sc, OWNER, 100, BOB, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// Leaving Lockdown takes owners, a guardian and time, in that order. Whoever caused the freeze +/// cannot lift it alone. +#[test] +fun leaving_lockdown_takes_owners_a_guardian_and_time() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, make_policy(1_000, 9_000, HOUR), 0, 0, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 200_000, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + approve(&mut sc, APPROVER, id, &clock); + confirm(&mut sc, GUARD, id, &clock); + tick(&mut clock, DAY + HOUR); + execute(&mut sc, OWNER, id, &clock); + assert!(current_mode(&mut sc) == types::mode_lockdown(), 0); + + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let rid = vault::propose_mode_relax(&mut v, types::mode_normal(), &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, rid, &clock); + approve(&mut sc, OWNER2, rid, &clock); + confirm(&mut sc, GUARD, rid, &clock); + + tick(&mut clock, 2 * DAY + HOUR); + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_mode_relax(&mut v2, rid, &clock, sc.ctx()); + assert!(vault::mode(&v2) == types::mode_normal(), 1); + assert!(vault::posture_reasons(&v2) == 0, 2); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_NOT_ENOUGH_GUARDIANS)] +fun owners_alone_cannot_lift_a_freeze() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + vault::raise_mode(&mut v, types::mode_lockdown(), 0, &clock, sc.ctx()); + let rid = vault::propose_mode_relax(&mut v, types::mode_normal(), &clock, sc.ctx()); + ts::return_shared(v); + + clock::destroy_for_testing(clock); + ts::end(sc); + let _ = rid; +} + +// ---------------------------------------------------------------- guardians +#[test] +fun a_guardian_veto_stops_a_critical_payment_and_raises_the_posture() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 20_000, BOB, &clock); + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + vault::veto(&mut v, id, &clock, sc.ctx()); + ts::return_shared(v); + + assert!(status(&mut sc, id) == types::status_vetoed(), 0); + assert!(current_mode(&mut sc) == types::mode_elevated(), 1); + assert!(balance(&mut sc) == TREASURY, 2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// A guardian has no treasury role and so no way to open a payment, let alone execute one. +#[test] +#[expected_failure(abort_code = E_CANNOT_PROPOSE)] +fun a_guardian_cannot_open_a_payment() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + propose(&mut sc, GUARD, 100, BOB, &clock); + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- the agent proposer +/// An automated agent holds the proposer role: it can ask the treasury to pay, and that is all. +#[test] +fun an_agent_can_open_a_payment_that_people_still_have_to_clear() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, AGENT, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + execute(&mut sc, OWNER, id, &clock); + assert!(status(&mut sc, id) == types::status_executed(), 0); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_NOT_APPROVER)] +fun an_agent_cannot_approve_its_own_proposal() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + let id = propose(&mut sc, AGENT, 500, BOB, &clock); + approve(&mut sc, AGENT, id, &clock); + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_NOT_EXECUTOR)] +fun an_agent_cannot_execute() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + let id = propose(&mut sc, AGENT, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + execute(&mut sc, AGENT, id, &clock); + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- the policy firewall +#[test] +fun tightening_the_policy_takes_effect_as_soon_as_owners_agree() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + let tighter = make_policy(2_000, 8_000, 2 * HOUR); + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let id = vault::propose_policy(&mut v, tighter, &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_policy(&mut v2, id, &clock, sc.ctx()); + assert!(vault::policy_version(&v2) == 2, 0); + assert!(policy::delay_high(vault::policy(&v2)) == 2 * HOUR, 1); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// Weakening the vault waits out the policy-change delay, even with every owner's signature. +#[test] +#[expected_failure(abort_code = E_TOO_EARLY)] +fun loosening_the_policy_has_to_wait() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + let looser = make_policy(3_000, 9_000, HOUR / 2); + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let id = vault::propose_policy(&mut v, looser, &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_policy(&mut v2, id, &clock, sc.ctx()); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun loosening_the_policy_succeeds_once_the_delay_has_run() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + let looser = make_policy(3_000, 9_000, HOUR / 2); + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let id = vault::propose_policy(&mut v, looser, &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + + tick(&mut clock, 2 * DAY + HOUR); + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_policy(&mut v2, id, &clock, sc.ctx()); + assert!(policy::delay_high(vault::policy(&v2)) == HOUR / 2, 0); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// And a guardian can stop it outright inside that window. +#[test] +fun a_guardian_can_veto_a_weakening() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + let looser = make_policy(3_000, 9_000, HOUR / 2); + ts::next_tx(&mut sc, OWNER); + let mut v = ts::take_shared(&sc); + let id = vault::propose_policy(&mut v, looser, &clock, sc.ctx()); + ts::return_shared(v); + approve(&mut sc, OWNER, id, &clock); + approve(&mut sc, OWNER2, id, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v2 = ts::take_shared(&sc); + vault::veto(&mut v2, id, &clock, sc.ctx()); + ts::return_shared(v2); + assert!(status(&mut sc, id) == types::status_vetoed(), 0); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- recovery +/// A lost key is replaced by guardians, after a delay, with the same roles and nothing else +/// changed — and the vault comes out of it in a raised posture. +#[test] +fun recovery_moves_the_roles_and_leaves_the_vault_elevated() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + let id = vault::propose_recovery(&mut v, APPROVER, NEWKEY, &clock, sc.ctx()); + ts::return_shared(v); + confirm(&mut sc, GUARD, id, &clock); + + tick(&mut clock, 3 * DAY + HOUR); + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_recovery(&mut v2, id, &clock, sc.ctx()); + assert!(vault::member_roles(&v2, APPROVER) == 0, 0); + assert!(vault::member_roles(&v2, NEWKEY) == types::role_approver(), 1); + assert!(vault::policy_version(&v2) == 1, 2); // the policy is untouched + assert!(vault::mode(&v2) == types::mode_elevated(), 3); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_TOO_EARLY)] +fun recovery_cannot_skip_its_delay() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + let id = vault::propose_recovery(&mut v, APPROVER, NEWKEY, &clock, sc.ctx()); + ts::return_shared(v); + confirm(&mut sc, GUARD, id, &clock); + + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + vault::execute_recovery(&mut v2, id, &clock, sc.ctx()); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +/// A compromised guardian key cannot quietly install a new signer: any owner cancels it. +#[test] +fun any_owner_can_cancel_a_recovery() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + let id = vault::propose_recovery(&mut v, APPROVER, NEWKEY, &clock, sc.ctx()); + ts::return_shared(v); + + ts::next_tx(&mut sc, OWNER2); + let mut v2 = ts::take_shared(&sc); + vault::cancel(&mut v2, id, &clock, sc.ctx()); + ts::return_shared(v2); + assert!(status(&mut sc, id) == types::status_cancelled(), 0); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- lifetimes +#[test] +fun a_proposal_expires_and_cannot_be_revived() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + tick(&mut clock, 31 * DAY); + + ts::next_tx(&mut sc, EVE); + let mut v = ts::take_shared(&sc); + vault::expire(&mut v, id, &clock, sc.ctx()); + ts::return_shared(v); + assert!(status(&mut sc, id) == types::status_expired(), 0); + assert!(balance(&mut sc) == TREASURY, 1); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +#[expected_failure(abort_code = E_EXPIRED)] +fun an_expired_proposal_cannot_execute() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + let id = propose(&mut sc, OWNER, 500, BOB, &clock); + approve(&mut sc, OWNER, id, &clock); + tick(&mut clock, 31 * DAY); + execute(&mut sc, OWNER, id, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +// ---------------------------------------------------------------- posture +/// Elevated halves the caps and escalates every tier, so a vault that has seen something wrong +/// keeps running but at a lower rate. +#[test] +#[expected_failure(abort_code = E_PER_TX_CAP)] +fun elevated_halves_the_caps() { + let mut sc = ts::begin(OWNER); + let mut clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 1_000, 100_000, &clock); + fund(&mut sc, &clock, TREASURY); + tick(&mut clock, 13 * HOUR); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + vault::raise_mode(&mut v, types::mode_elevated(), 0, &clock, sc.ctx()); + ts::return_shared(v); + + propose(&mut sc, OWNER, 800, BOB, &clock); + + clock::destroy_for_testing(clock); + ts::end(sc); +} + +#[test] +fun deposits_are_never_gated() { + let mut sc = ts::begin(OWNER); + let clock = settled_clock(&mut sc); + boot(&mut sc, base_policy(), 50_000, 100_000, &clock); + + ts::next_tx(&mut sc, GUARD); + let mut v = ts::take_shared(&sc); + vault::raise_mode(&mut v, types::mode_lockdown(), 0, &clock, sc.ctx()); + ts::return_shared(v); + + // Even frozen, and even from a stranger, money can come in. + ts::next_tx(&mut sc, EVE); + let mut v2 = ts::take_shared(&sc); + let c = coin::mint_for_testing(42, sc.ctx()); + vault::deposit(&mut v2, c, &clock, sc.ctx()); + assert!(vault::balance_of(&v2) == 42, 0); + ts::return_shared(v2); + + clock::destroy_for_testing(clock); + ts::end(sc); +} From 1f38e087e98bd6b4be49f2f602bcb19c52a3f38b Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 09:41:59 +0100 Subject: [PATCH 15/44] feat(app): the Sui interface, and the docs for the new direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The interface (app/): - Next.js on @mysten/dapp-kit-react 2.x over gRPC, because dapp-kit 1.x is JSON-RPC only and Sui is decommissioning it - every action is gated on the role the contract requires, so a signer is never offered something the vault would refuse - the payment review is the vault's own preview_transfer, simulated live, so the interface cannot promise what execution would reject - the policy editor shows what a change gives up before it is proposed, and runs the attack scenarios against the edited policy - creating a vault is one transaction: nothing exists until all of it is valid Backend: the notification rules are now a pure module with 14 tests. Who gets interrupted is a correctness question, so it is tested like one. Docs: the security model with the fifteen invariants and the test that proves each, and the migration note — including the one deliberate behavioural change, where the breaker no longer reverts away its own latch. --- .gitignore | 8 + README.md | 147 +++++++----- app/.env.example | 9 + app/next.config.ts | 11 + app/package.json | 28 +++ app/scripts-sync-deployments.mjs | 22 ++ app/src/app/HomeApp.tsx | 143 ++++++++++++ app/src/app/VaultApp.tsx | 91 ++++++++ app/src/app/globals.css | 204 +++++++++++++++++ app/src/app/layout.tsx | 15 ++ app/src/app/page.tsx | 18 ++ app/src/app/providers.tsx | 34 +++ app/src/app/vault/[id]/page.tsx | 20 ++ app/src/components/CreateVault.tsx | 253 +++++++++++++++++++++ app/src/components/Overview.tsx | 248 ++++++++++++++++++++ app/src/components/People.tsx | 351 +++++++++++++++++++++++++++++ app/src/components/PolicyPanel.tsx | 265 ++++++++++++++++++++++ app/src/components/Queue.tsx | 343 ++++++++++++++++++++++++++++ app/src/components/Security.tsx | 228 +++++++++++++++++++ app/src/components/Send.tsx | 341 ++++++++++++++++++++++++++++ app/src/components/Shell.tsx | 52 +++++ app/src/components/ui.tsx | 161 +++++++++++++ app/src/config/deployments.json | 17 ++ app/src/config/index.ts | 25 ++ app/src/dapp-kit.ts | 28 +++ app/src/hooks/useVault.ts | 138 ++++++++++++ app/tsconfig.json | 21 ++ docs/MIGRATION_EVM_TO_SUI.md | 93 ++++++++ docs/SUI_SECURITY_MODEL.md | 127 +++++++++++ package.json | 27 ++- server/src/notify.ts | 236 +------------------ server/src/rules.ts | 231 +++++++++++++++++++ server/test/notify.test.ts | 201 +++++++++++++++++ 33 files changed, 3838 insertions(+), 298 deletions(-) create mode 100644 app/.env.example create mode 100644 app/next.config.ts create mode 100644 app/package.json create mode 100644 app/scripts-sync-deployments.mjs create mode 100644 app/src/app/HomeApp.tsx create mode 100644 app/src/app/VaultApp.tsx create mode 100644 app/src/app/globals.css create mode 100644 app/src/app/layout.tsx create mode 100644 app/src/app/page.tsx create mode 100644 app/src/app/providers.tsx create mode 100644 app/src/app/vault/[id]/page.tsx create mode 100644 app/src/components/CreateVault.tsx create mode 100644 app/src/components/Overview.tsx create mode 100644 app/src/components/People.tsx create mode 100644 app/src/components/PolicyPanel.tsx create mode 100644 app/src/components/Queue.tsx create mode 100644 app/src/components/Security.tsx create mode 100644 app/src/components/Send.tsx create mode 100644 app/src/components/Shell.tsx create mode 100644 app/src/components/ui.tsx create mode 100644 app/src/config/deployments.json create mode 100644 app/src/config/index.ts create mode 100644 app/src/dapp-kit.ts create mode 100644 app/src/hooks/useVault.ts create mode 100644 app/tsconfig.json create mode 100644 docs/MIGRATION_EVM_TO_SUI.md create mode 100644 docs/SUI_SECURITY_MODEL.md create mode 100644 server/src/rules.ts create mode 100644 server/test/notify.test.ts diff --git a/.gitignore b/.gitignore index 1d86deb..76d9915 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,14 @@ contracts/broadcast/**/dry-run/ node_modules/ web/dist/ web/coverage/ +sdk/dist/ +app/.next/ +app/out/ +app/next-env.d.ts + +# move +sui/build/ +sui/Move.lock # tooling .DS_Store diff --git a/README.md b/README.md index 18279b6..255cdc9 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,122 @@ # Skur -Programmable treasury security for onchain businesses. Protect funds with adaptive policies, loss limits, guardians, and risk-aware approvals. +**A programmable authorization and treasury security layer for Sui organizations.** -> A valid signature proves authorization. It does not prove that a transaction is safe. +> A valid signature proves authorization. It does not prove that a payment is safe. -Skur is a self-custodial vault whose security requirements change with transaction risk. Valid approvals are necessary but never sufficient: amount tiers, treasury exposure, recipient trust, cumulative outflow, guardian veto and security modes are all enforced by the vault contract itself. No Skur server sits in the execution path. +Every large onchain treasury loss of the last few years happened with valid signatures. The keys +were real, the threshold was met, the contract did what it was told. Nothing between the signature +and the money asked the second question: -## Repository layout +> Given the amount, the destination, what has already left today and what this organization knows +> right now, *should* this payment settle? -| Path | What it is | +Skur answers that question in Move, in a shared object anyone can read. It is not a wallet, and it +is not a nicer multisig — Sui has signature aggregation in the protocol already. It is the layer a +treasury sits behind. + +## What the vault enforces + +| Control | What it does | |---|---| -| [contracts/](contracts/) | Foundry project: `SkurVault`, `SkurFactory`, `SkurPolicyLib`, `SkurRisk`, the devnet stablecoin, tests, invariants and deploy script | -| [web/](web/) | Client-side interface (Vite, React, wagmi/viem). Reads contract state and events directly; submits user-signed transactions | -| [mobile/](mobile/) | iOS and Android app (Expo, React Native). Same vault reads, risk engine and error texts as the web app, shared from `web/src/lib`; signs with a key kept in the device keychain behind Face ID or Touch ID. | -| [docs/DECISIONS.md](docs/DECISIONS.md) | Every open question from the blueprint, resolved | -| [docs/SECURITY_MODEL.md](docs/SECURITY_MODEL.md) | Roles, lifecycle, the twelve invariants and the tests that prove each | -| [docs/scriipture-capability-report.md](docs/scriipture-capability-report.md) | Why the contracts are plain Solidity instead of Scriipture TypeScript | -| [scripts/export-abi.py](scripts/export-abi.py) | Copies ABIs from the Foundry build into the web app | +| **Risk-tiered authorization** | Five signals — amount against the asset's limits, share of holdings, recipient standing, the day's outflow, the vault's mode — each able to raise the tier and none able to lower it. The tier sets the approvals, the guardian sign-off and the wait. | +| **Recipient trust** | An address the vault has never paid is escalated every time. A newly registered one serves an activation delay before it can be paid at all. | +| **Velocity limits** | Per-transaction and 24-hour caps, counted cumulatively. Crossing half the day's allowance escalates everything after it, so splitting a drain meets a higher bar partway through rather than never. | +| **Loss-envelope circuit breaker** | A share of the balance that may leave per window, measured against the balance when the window *opened*. The payment that would cross it is not made; the vault latches into Lockdown instead. | +| **Guardians** | A role the contract refuses to combine with any treasury role. It can freeze, veto, block a recipient and start a recovery. It can never propose, approve or execute a payment. | +| **Policy firewall** | Any change that gives up a control — including the ones that look like tightening, such as zeroing a threshold to disable it — waits out a delay, can be vetoed by any guardian, and cannot be proposed in Lockdown. | +| **An agent role** | `PROPOSER` can open a payment and nothing else. A compromised automation key produces a queue nobody approved, not a withdrawal. | -## Ark Constellation devnet deployment +Details, with the test that proves each invariant, in +[docs/SUI_SECURITY_MODEL.md](docs/SUI_SECURITY_MODEL.md). -Chain id 9000, native token KASH. Sources are verified on the Blockscout explorer. +## Repository layout -| Contract | Address | +| Path | What it is | |---|---| -| SkurFactory | [`0x018c12BA8b085da81E434b9e4001e07CF48764E9`](https://explorer.34.60.137.196.sslip.io/address/0x018c12BA8b085da81E434b9e4001e07CF48764E9) | -| SkurVault implementation | [`0xE21C7ad3a56D187848F9915bb43f88820278DeA3`](https://explorer.34.60.137.196.sslip.io/address/0xE21C7ad3a56D187848F9915bb43f88820278DeA3) | -| SkurPolicyLib | [`0x6bAA1A24B55796d8346748EE3565e40d844bA576`](https://explorer.34.60.137.196.sslip.io/address/0x6bAA1A24B55796d8346748EE3565e40d844bA576) | -| SkurTestUSD (sUSD, 6 decimals, mintable) | [`0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a`](https://explorer.34.60.137.196.sslip.io/address/0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a) | -| Demo vault (Startup template) | [`0xCC31c7474267ca5600c2D530ebD7657A09c042Dc`](https://explorer.34.60.137.196.sslip.io/address/0xCC31c7474267ca5600c2D530ebD7657A09c042Dc) | - -The full record, including the deployer address, is in [contracts/deployments/9000.json](contracts/deployments/9000.json). Endpoints live only in `contracts/foundry.toml` and `web/src/config/chain.ts`. +| [sui/](sui/) | The Move package: `types`, `policy`, `risk`, `vault`, and the test suites named after the attacks they defend against | +| [sdk/](sdk/) | TypeScript SDK on `@mysten/sui` v2 — reads, PTB builders, event decoding, and the chain-agnostic engines (risk, policy rules, templates, maximum loss, posture, attack simulator) | +| [app/](app/) | The interface: Next.js, React, `@mysten/dapp-kit-react` | +| [server/](server/) | Node and PostgreSQL: the event indexer, the notification service and the advisory API | +| [docs/SUI_SECURITY_MODEL.md](docs/SUI_SECURITY_MODEL.md) | Roles, lifecycle, the fifteen invariants, the threat map and the known limitations | +| [docs/SUI_LANDSCAPE.md](docs/SUI_LANDSCAPE.md) | What exists on Sui today and what it does not do | +| [docs/SUI_POSITIONING.md](docs/SUI_POSITIONING.md) | The positioning and funding narrative | +| [docs/MIGRATION_EVM_TO_SUI.md](docs/MIGRATION_EVM_TO_SUI.md) | What moved, what changed shape, and why | +| [contracts/](contracts/), [web/](web/), [mobile/](mobile/) | The previous EVM build, kept for reference. See the migration note | + +## Transport: gRPC and GraphQL, never JSON-RPC + +JSON-RPC was switched off on Sui Foundation mainnet full nodes in the week of 27 July 2026, with +full decommissioning — code removal included — scheduled for mid-October 2026. + +Nothing here depends on it, directly or transitively. That is why the interface uses +`@mysten/dapp-kit-react` 2.x and not `@mysten/dapp-kit` 1.x, which is deprecated precisely because +it is JSON-RPC only. The SDK's read layer targets the transport-agnostic Core API, so the same code +runs over gRPC today and over anything implementing that contract later. ## Quick start -Dependencies are git submodules, so clone with `--recurse-submodules` (or run -`git submodule update --init --recursive` in an existing clone). - ```bash -# contracts -cd contracts -forge build -forge test # unit, fuzz and invariant suites -slither . --filter-paths "lib/|test/|script/" - -# interface -cd ../web +# the Move core +cd sui +sui move build +sui move test # the engine vectors and the end-to-end suite + +# the SDK +cd ../sdk +npm install && npm run build +npm test # the same vectors as the Move suite + +# the backend +cd ../server +cp .env.example .env # set DATABASE_URL and SKUR_PACKAGE_ID +createdb skur && npm install && npm run migrate +npm run dev # the indexer and the read API together + +# the interface +cd ../app npm install -npm run dev # http://localhost:5173, connect MetaMask on chain 9000 -npm test # risk-engine mirror vectors +npm run dev # http://localhost:3000 ``` -Get devnet KASH from the faucet at `https://faucet.34.60.137.196.sslip.io/` and mint sUSD by calling `mint(address,uint256)` on the test token. +The Sui CLI is the one prerequisite that is not an npm install: get it from +[the releases page](https://github.com/MystenLabs/sui/releases) or with +`cargo install --locked --git https://github.com/MystenLabs/sui.git sui`. -## Deploying your own instance +## Deploying ```bash -cd contracts -cp .env.example .env # set PRIVATE_KEY (devnet only) and DEMO_VAULT -forge script script/Deploy.s.sol --rpc-url ark_devnet --broadcast --private-key $PRIVATE_KEY -forge verify-contract
      src/SkurVault.sol:SkurVault --verifier blockscout \ - --verifier-url https://explorer-api.34.60.137.196.sslip.io/api --chain 9000 \ - --libraries src/SkurPolicyLib.sol:SkurPolicyLib: -python3 ../scripts/export-abi.py && cp deployments/9000.json ../web/src/config/deployments.json -``` +cd sui +scripts/publish.sh testnet # builds, tests, publishes, writes deployments/testnet.json -For a keyless deploy, `npx scriipture deploy` can broadcast the compiled artifact through a browser wallet. +cd ../sdk +SUI_PRIVATE_KEY=suiprivkey1... SKUR_NETWORK=testnet SKUR_PACKAGE_ID=0x... \ + node --experimental-strip-types scripts/seed.ts +``` -## How the vault decides +`sui/deployments/.json` is the only place a package address is configured. Nothing in the +app, the SDK or the backend hardcodes one. -1. A proposal is created. The vault classifies it LOW, HIGH or CRITICAL from amount, share of holdings, recipient trust, today's outflow and the security mode, and pins the required approvals, guardian confirmations and delay. -2. Approvers approve. Guardians confirm when the tier demands it. A guardian can veto any critical, probationary or security-reducing proposal at any time. -3. An executor executes. The vault re-checks every limit at that moment: recipient not blocked and past activation, per-transaction cap, hard exposure block, daily bucket, and the loss envelope. Exceeding the envelope trips the vault into Lockdown instead of paying. -4. Governance changes follow the same path with owner approvals. Anything that loosens security waits for the policy-change delay, is vetoable, and is refused while in Lockdown. +## How a payment goes out -Guardians can freeze, veto, confirm and recover. They hold no treasury role and can never move funds. +1. **Opened.** The vault classifies it routine, high risk or critical from the amount, the share of + holdings, the recipient's standing, the day's outflow and the security mode, and pins the + approvals, the guardian confirmations and the delay. +2. **Approved.** Approvers approve; guardians confirm when the tier demands it. A guardian can veto + any critical payment, any weakening of the vault, any recovery and any relaxation. +3. **Executed.** The vault re-checks everything against live state: the approval set is recounted + against the current roster, the payment is reclassified and the *stricter* of the pinned and + live requirements applies, the recipient's standing and activation are re-read, and the caps and + the hard block are re-applied. The loss envelope is checked last; a payment that would cross it + is refused and the vault latches into Lockdown. +4. **Governance** follows the same path with owner approvals. Anything that gives up a control waits + out the policy-change delay, is vetoable, and is refused in Lockdown. ## Status -V1 as scoped in the blueprint: vault creation, protected membership, four roles, native and ERC-20 deposits and transfer proposals, amount tiers, recipient trust with activation delay, per-transaction and 24-hour caps, circuit breaker, critical timelock and veto, three security modes, policy-change timelock, recovery, human-readable review, policy templates, policy simulator, maximum-loss view and posture indicator. Not yet done: independent audit and pilot. +Built and under test: the Move core with all seven proposal kinds, the SDK over gRPC and GraphQL, +the indexer and notification service on PostgreSQL, the interface, and seven starting policies — +startup, operating team, protocol/DAO, fund, payments company, nonprofit, family office. + +Not done, and not claimed: **no independent audit**, no mainnet deployment, no pilot. Do not put +real value behind Skur until an audit is complete. diff --git a/app/.env.example b/app/.env.example new file mode 100644 index 0000000..603ea61 --- /dev/null +++ b/app/.env.example @@ -0,0 +1,9 @@ +# Which network, and the package published on it. Both override sui/deployments/.json. +NEXT_PUBLIC_SKUR_NETWORK=testnet +NEXT_PUBLIC_SKUR_PACKAGE_ID=0x0 + +# A gRPC endpoint other than the public full node. +# NEXT_PUBLIC_SKUR_GRPC_URL=https://fullnode.testnet.sui.io:443 + +# The indexer. Optional: every screen works without it, with fewer round trips saved. +# NEXT_PUBLIC_SKUR_API=http://localhost:8787 diff --git a/app/next.config.ts b/app/next.config.ts new file mode 100644 index 0000000..500df45 --- /dev/null +++ b/app/next.config.ts @@ -0,0 +1,11 @@ +import type { NextConfig } from 'next'; + +const config: NextConfig = { + reactStrictMode: true, + // The SDK is consumed as built JavaScript, but keeping it transpiled here means a change in + // sdk/src shows up on the next dev reload instead of needing a rebuild first. + transpilePackages: ['@skur/sdk'], + typedRoutes: true, +}; + +export default config; diff --git a/app/package.json b/app/package.json new file mode 100644 index 0000000..e762188 --- /dev/null +++ b/app/package.json @@ -0,0 +1,28 @@ +{ + "name": "@skur/app", + "private": true, + "version": "0.1.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "typecheck": "tsc --noEmit", + "sync-deployments": "node scripts-sync-deployments.mjs" + }, + "dependencies": { + "@mysten/dapp-kit-core": "^1.6.36", + "@mysten/dapp-kit-react": "^2.1.38", + "@mysten/sui": "^2.34.0", + "@skur/sdk": "file:../sdk", + "@tanstack/react-query": "^5.102.8", + "next": "^16.0.0", + "react": "^19.2.8", + "react-dom": "^19.2.8" + }, + "devDependencies": { + "@types/node": "^24.13.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.7", + "typescript": "~6.0.2" + } +} \ No newline at end of file diff --git a/app/scripts-sync-deployments.mjs b/app/scripts-sync-deployments.mjs new file mode 100644 index 0000000..ce90725 --- /dev/null +++ b/app/scripts-sync-deployments.mjs @@ -0,0 +1,22 @@ +// Copy sui/deployments/*.json into the app, so the published addresses are configured in exactly +// one place and the app does not import across the workspace boundary. +import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'; + +const from = new URL('../sui/deployments/', import.meta.url); +const to = new URL('./src/config/deployments.json', import.meta.url); + +const out = {}; +try { + for (const file of await readdir(from)) { + if (!file.endsWith('.json')) continue; + const body = JSON.parse(await readFile(new URL(file, from), 'utf8')); + out[body.network ?? file.replace('.json', '')] = body; + } +} catch { + console.log('no deployments yet; leaving the committed defaults in place'); + process.exit(0); +} + +await mkdir(new URL('./src/config/', import.meta.url), { recursive: true }); +await writeFile(to, `${JSON.stringify(out, null, 2)}\n`); +console.log(`wrote ${Object.keys(out).join(', ') || 'nothing'}`); diff --git a/app/src/app/HomeApp.tsx b/app/src/app/HomeApp.tsx new file mode 100644 index 0000000..9b5e755 --- /dev/null +++ b/app/src/app/HomeApp.tsx @@ -0,0 +1,143 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import Link from 'next/link'; +import { useState } from 'react'; +import { MODE_LABELS, describeRoles } from '@skur/sdk'; +import { API_URL, CONFIGURED, KNOWN_VAULTS, NETWORK } from '@/config'; +import { useMyVaults, useVaultTx } from '@/hooks/useVault'; +import { CreateVault } from '@/components/CreateVault'; +import { Shell } from '@/components/Shell'; +import { Addr, Notice } from '@/components/ui'; + +export default function HomeApp() { + const account = useCurrentAccount(); + const [mode, setMode] = useState<'open' | 'create'>('open'); + const [manual, setManual] = useState(''); + const tx = useVaultTx(undefined); + const mine = useMyVaults(account?.address, API_URL); + + return ( + +
      +

      A valid signature is not a safe payment

      +

      + Skur decides how much authorization a payment needs, and whether it may settle right now, + from the amount, the destination, the recent outflow and the vault's own security + posture. The rules are enforced in Move, in a shared object anyone can read. +

      +
      + + + + {mode === 'create' ? ( + + ) : ( +
      +
      +

      Your vaults

      + {!account ? ( +

      + Connect a wallet to see the vaults you hold a role in. +

      + ) : !API_URL ? ( +

      + Finding your vaults by address needs the indexer. Set{' '} + NEXT_PUBLIC_SKUR_API, or open a vault by its id. +

      + ) : mine.isLoading ? ( +
      Looking…
      + ) : mine.error ? ( +

      + The indexer is not reachable. You can still open a vault by its id. +

      + ) : mine.data && mine.data.length > 0 ? ( +
      + {mine.data.map((v) => ( + +
      + {v.name} + + {MODE_LABELS[v.mode as 0 | 1 | 2]} +
      +

      + {describeRoles(v.roles).join(' · ') || 'no role'} +

      + + ))} +
      + ) : ( +
      No vaults found for this address.
      + )} +
      + +
      +
      +

      Open by id

      +

      + A vault is a shared object. Anyone can read one; acting on it needs the key that + holds the role. +

      +
      + setManual(e.target.value.trim())} + spellCheck={false} + /> + + Open + +
      +
      + + {KNOWN_VAULTS.length > 0 ? ( +
      +

      On {NETWORK}

      +
      + {KNOWN_VAULTS.map((v) => ( +
      + + {v.name} + + + +
      + ))} +
      +
      + ) : null} + + {!CONFIGURED ? ( + + No package is published for {NETWORK} yet. Run{' '} + sui/scripts/publish.sh {NETWORK}. + + ) : null} +
      +
      + )} +
      + ); +} diff --git a/app/src/app/VaultApp.tsx b/app/src/app/VaultApp.tsx new file mode 100644 index 0000000..b8d116e --- /dev/null +++ b/app/src/app/VaultApp.tsx @@ -0,0 +1,91 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useState } from 'react'; +import { Role, hasRole } from '@skur/sdk'; +import { CONFIGURED } from '@/config'; +import { useVaultTx, useVaultView } from '@/hooks/useVault'; +import { CreateVault } from '@/components/CreateVault'; +import { Overview } from '@/components/Overview'; +import { People } from '@/components/People'; +import { PolicyPanel } from '@/components/PolicyPanel'; +import { Queue } from '@/components/Queue'; +import { Security } from '@/components/Security'; +import { Send } from '@/components/Send'; +import { Shell } from '@/components/Shell'; +import { Notice } from '@/components/ui'; + +type Tab = 'overview' | 'queue' | 'send' | 'policy' | 'people' | 'security'; + +export default function VaultApp({ vaultId }: { vaultId: string }) { + const [tab, setTab] = useState('overview'); + const account = useCurrentAccount(); + const query = useVaultView(vaultId); + const tx = useVaultTx(vaultId); + + const tabs: { id: Tab; label: string }[] = [ + { id: 'overview', label: 'Overview' }, + { id: 'queue', label: 'Queue' }, + { id: 'send', label: 'Pay' }, + { id: 'policy', label: 'Policy' }, + { id: 'people', label: 'People' }, + { id: 'security', label: 'Security' }, + ]; + + return ( + ({ + id: t.id, + label: t.label, + active: tab === t.id, + onClick: () => setTab(t.id), + }))} + > + {!CONFIGURED ? ( + + No package is configured for this network. Publish the Move package and set{' '} + NEXT_PUBLIC_SKUR_PACKAGE_ID. + + ) : query.isLoading ? ( +
      Reading the vault…
      + ) : query.error ? ( + + Could not read that vault. Check the id and the network. +

      + {query.error instanceof Error ? query.error.message : String(query.error)} +

      +
      + ) : query.data ? ( + <> +
      +

      {query.data.vault.name}

      + {account ? ( + m.address === account.address)?.roles ?? 0} /> + ) : null} + + {tx.pending ? working… : null} +
      + {tab === 'overview' ? : null} + {tab === 'queue' ? : null} + {tab === 'send' ? : null} + {tab === 'policy' ? : null} + {tab === 'people' ? : null} + {tab === 'security' ? : null} + + ) : null} +
      + ); +} + +function RoleBadge({ roles }: { roles: number }) { + if (roles === 0) return read only; + const names: string[] = []; + if (hasRole(roles, Role.OWNER)) names.push('owner'); + if (hasRole(roles, Role.APPROVER)) names.push('approver'); + if (hasRole(roles, Role.EXECUTOR)) names.push('executor'); + if (hasRole(roles, Role.GUARDIAN)) names.push('guardian'); + if (hasRole(roles, Role.PROPOSER)) names.push('proposer'); + return {names.join(' · ')}; +} + +export { CreateVault }; diff --git a/app/src/app/globals.css b/app/src/app/globals.css new file mode 100644 index 0000000..9319c15 --- /dev/null +++ b/app/src/app/globals.css @@ -0,0 +1,204 @@ +/* Design tokens. One accent, a neutral ramp, and a semantic set for the three risk tiers and the + three security modes — the interface should never invent a colour for a state the vault has. */ +:root { + --accent: #ffd000; + --accent-ink: #1a1500; + --bg: #ffffff; + --bg-sunk: #f6f7f8; + --bg-raised: #ffffff; + --line: #e4e6e9; + --line-strong: #cfd3d8; + --ink: #15181c; + --ink-soft: #5b6470; + --ink-faint: #8b949e; + --ok: #107a4d; + --warn: #9a6400; + --bad: #b3261e; + --tier-low: #107a4d; + --tier-high: #9a6400; + --tier-critical: #b3261e; + --radius: 10px; + --radius-lg: 14px; + --mono: ui-monospace, "SF Mono", "DM Mono", Menlo, monospace; + --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme='light']) { + --bg: #0e1013; + --bg-sunk: #15181c; + --bg-raised: #191d22; + --line: #262b31; + --line-strong: #363d45; + --ink: #eef1f4; + --ink-soft: #a3adb8; + --ink-faint: #70797f; + --ok: #4ade80; + --warn: #fbbf24; + --bad: #f87171; + --tier-low: #4ade80; + --tier-high: #fbbf24; + --tier-critical: #f87171; + } +} + +:root[data-theme='dark'] { + --bg: #0e1013; + --bg-sunk: #15181c; + --bg-raised: #191d22; + --line: #262b31; + --line-strong: #363d45; + --ink: #eef1f4; + --ink-soft: #a3adb8; + --ink-faint: #70797f; + --ok: #4ade80; + --warn: #fbbf24; + --bad: #f87171; + --tier-low: #4ade80; + --tier-high: #fbbf24; + --tier-critical: #f87171; +} + +* { box-sizing: border-box; } + +html, body { padding: 0; margin: 0; } + +body { + background: var(--bg); + color: var(--ink); + font-family: var(--sans); + font-size: 15px; + line-height: 1.55; + -webkit-font-smoothing: antialiased; +} + +a { color: inherit; } + +h1, h2, h3, h4 { margin: 0; line-height: 1.2; letter-spacing: -0.02em; font-weight: 650; } +h1 { font-size: 30px; } +h2 { font-size: 21px; } +h3 { font-size: 17px; } +h4 { font-size: 15px; } +p { margin: 0; } + +.mono { font-family: var(--mono); font-size: 13px; } +.soft { color: var(--ink-soft); } +.faint { color: var(--ink-faint); } +.small { font-size: 13px; } + +/* layout */ +.shell { max-width: 1120px; margin: 0 auto; padding: 0 20px 80px; } +.topbar { + position: sticky; top: 0; z-index: 20; + display: flex; align-items: center; gap: 16px; + padding: 14px 20px; margin-bottom: 28px; + background: color-mix(in srgb, var(--bg) 88%, transparent); + backdrop-filter: blur(10px); + border-bottom: 1px solid var(--line); +} +.topbar .grow { flex: 1; } +.brand { display: flex; align-items: center; gap: 9px; font-weight: 700; letter-spacing: -0.03em; } +.brand .mark { + width: 22px; height: 22px; border-radius: 6px; + background: var(--accent); color: var(--accent-ink); + display: grid; place-items: center; font-size: 13px; font-weight: 800; +} +.nav { display: flex; gap: 2px; flex-wrap: wrap; } +.nav a, .nav button { + padding: 7px 12px; border-radius: 8px; border: 0; background: transparent; + color: var(--ink-soft); font: inherit; font-size: 14px; cursor: pointer; text-decoration: none; +} +.nav a:hover, .nav button:hover { background: var(--bg-sunk); color: var(--ink); } +.nav a[aria-current='page'], .nav button[data-active='true'] { background: var(--bg-sunk); color: var(--ink); font-weight: 600; } + +.grid { display: grid; gap: 16px; } +.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } +.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } +@media (max-width: 860px) { + .cols-2, .cols-3, .cols-4 { grid-template-columns: minmax(0, 1fr); } + .shell { padding: 0 16px 60px; } + h1 { font-size: 25px; } +} + +.card { + background: var(--bg-raised); + border: 1px solid var(--line); + border-radius: var(--radius-lg); + padding: 18px; +} +.card.sunk { background: var(--bg-sunk); } +.card h3 { margin-bottom: 4px; } +.card + .card { margin-top: 16px; } + +.row { display: flex; align-items: center; gap: 10px; } +.row.wrap { flex-wrap: wrap; } +.row .grow { flex: 1; } +.stack { display: flex; flex-direction: column; gap: 12px; } +.stack.tight { gap: 6px; } + +.kv { display: flex; justify-content: space-between; gap: 16px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: 14px; } +.kv:last-child { border-bottom: 0; } +.kv dt { color: var(--ink-soft); } +.kv dd { margin: 0; font-weight: 550; text-align: right; } + +/* controls */ +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: 7px; + padding: 9px 15px; border-radius: 9px; border: 1px solid var(--line-strong); + background: var(--bg-raised); color: var(--ink); + font: inherit; font-size: 14px; font-weight: 550; cursor: pointer; +} +.btn:hover:not(:disabled) { border-color: var(--ink-faint); } +.btn:disabled { opacity: 0.45; cursor: not-allowed; } +.btn.primary { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 650; } +.btn.danger { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 40%, var(--line)); } +.btn.ghost { border-color: transparent; background: transparent; } +.btn.sm { padding: 6px 11px; font-size: 13px; } + +input, select, textarea { + width: 100%; padding: 9px 11px; border-radius: 9px; + border: 1px solid var(--line-strong); background: var(--bg); + color: var(--ink); font: inherit; font-size: 14px; +} +input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; } +label { display: block; font-size: 13px; color: var(--ink-soft); margin-bottom: 5px; } +.field + .field { margin-top: 12px; } + +/* state */ +.pill { + display: inline-flex; align-items: center; gap: 5px; + padding: 3px 9px; border-radius: 999px; font-size: 12px; font-weight: 600; + border: 1px solid var(--line-strong); color: var(--ink-soft); +} +.pill.low { color: var(--tier-low); border-color: color-mix(in srgb, var(--tier-low) 35%, var(--line)); } +.pill.high { color: var(--tier-high); border-color: color-mix(in srgb, var(--tier-high) 35%, var(--line)); } +.pill.critical { color: var(--tier-critical); border-color: color-mix(in srgb, var(--tier-critical) 35%, var(--line)); } +.pill.accent { color: var(--accent-ink); background: var(--accent); border-color: var(--accent); } + +.notice { + padding: 12px 14px; border-radius: var(--radius); + border: 1px solid var(--line-strong); background: var(--bg-sunk); font-size: 14px; +} +.notice.warn { border-color: color-mix(in srgb, var(--warn) 45%, var(--line)); } +.notice.bad { border-color: color-mix(in srgb, var(--bad) 45%, var(--line)); } +.notice.ok { border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); } + +.dot { width: 8px; height: 8px; border-radius: 999px; flex: 0 0 auto; } +.dot.ok { background: var(--ok); } +.dot.warn { background: var(--warn); } +.dot.bad { background: var(--bad); } + +.bar { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; } +.bar > span { display: block; height: 100%; background: var(--accent); } +.bar.warn > span { background: var(--warn); } +.bar.bad > span { background: var(--bad); } + +.reasons { margin: 8px 0 0; padding-left: 18px; font-size: 13px; color: var(--ink-soft); } +.reasons li + li { margin-top: 3px; } + +table { width: 100%; border-collapse: collapse; font-size: 14px; } +th { text-align: left; font-weight: 600; color: var(--ink-soft); font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; padding: 0 0 8px; } +td { padding: 10px 0; border-top: 1px solid var(--line); vertical-align: top; } + +.empty { padding: 36px 20px; text-align: center; color: var(--ink-soft); } diff --git a/app/src/app/layout.tsx b/app/src/app/layout.tsx new file mode 100644 index 0000000..edc840c --- /dev/null +++ b/app/src/app/layout.tsx @@ -0,0 +1,15 @@ +import type { Metadata } from 'next'; +import './globals.css'; + +export const metadata: Metadata = { + title: 'Skur', + description: 'A programmable authorization and treasury security layer for Sui organizations.', +}; + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ); +} diff --git a/app/src/app/page.tsx b/app/src/app/page.tsx new file mode 100644 index 0000000..02e0fd0 --- /dev/null +++ b/app/src/app/page.tsx @@ -0,0 +1,18 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import { Providers } from './providers'; + +// Wallet detection needs a browser, so nothing in the app tree is server-rendered. +const HomeApp = dynamic(() => import('./HomeApp'), { + ssr: false, + loading: () =>
      Loading…
      , +}); + +export default function Page() { + return ( + + + + ); +} diff --git a/app/src/app/providers.tsx b/app/src/app/providers.tsx new file mode 100644 index 0000000..f1f484f --- /dev/null +++ b/app/src/app/providers.tsx @@ -0,0 +1,34 @@ +'use client'; + +import { DAppKitProvider } from '@mysten/dapp-kit-react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { useState } from 'react'; +import { dAppKit } from '@/dapp-kit'; + +/** + * Client-only. Wallet detection needs a browser, so every page that renders this is loaded with + * `ssr: false`. + */ +export function Providers({ children }: { children: React.ReactNode }) { + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + // A vault is a shared object: a write by anyone changes it, so reads stay fresh for + // only a few seconds. `refetchOnWindowFocus` is off because it made the old build + // look like it was constantly reloading. + staleTime: 5_000, + refetchInterval: 15_000, + refetchOnWindowFocus: false, + retry: 1, + }, + }, + }), + ); + return ( + + {children} + + ); +} diff --git a/app/src/app/vault/[id]/page.tsx b/app/src/app/vault/[id]/page.tsx new file mode 100644 index 0000000..ae2360b --- /dev/null +++ b/app/src/app/vault/[id]/page.tsx @@ -0,0 +1,20 @@ +'use client'; + +import dynamic from 'next/dynamic'; +import { useParams } from 'next/navigation'; +import { Providers } from '@/app/providers'; + +const VaultApp = dynamic(() => import('@/app/VaultApp'), { + ssr: false, + loading: () =>
      Loading…
      , +}); + +export default function Page() { + const params = useParams<{ id: string }>(); + const id = Array.isArray(params.id) ? params.id[0] : params.id; + return ( + + + + ); +} diff --git a/app/src/components/CreateVault.tsx b/app/src/components/CreateVault.tsx new file mode 100644 index 0000000..5810f11 --- /dev/null +++ b/app/src/components/CreateVault.tsx @@ -0,0 +1,253 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useMemo, useState } from 'react'; +import { SUI_TYPE_ARG } from '@mysten/sui/utils'; +import { + Role, + TEMPLATES, + fmtDuration, + rolesValid, + templateById, + tx as build, + validateCounts, + validatePolicy, + type TemplateId, +} from '@skur/sdk'; +import { CONFIGURED, PACKAGE_ID } from '@/config'; +import type { TxState } from '@/hooks/useVault'; +import { Notice } from './ui'; + +type Seat = { address: string; roles: number }; + +/** + * Creating a vault. + * + * One transaction: the whole configuration goes into a single programmable transaction block, so + * there is never a moment when a vault exists without its policy, its signers and its assets. If + * any part is wrong the whole thing fails and nothing is created. + * + * The thresholds are checked against the roster before the wallet opens, because a vault whose + * threshold nobody can reach is a frozen vault and the contract refuses to create one. + */ +export function CreateVault({ tx }: { tx: TxState }) { + const account = useCurrentAccount(); + const me = account?.address; + const [templateId, setTemplateId] = useState('startup'); + const [name, setName] = useState('Treasury'); + const [seats, setSeats] = useState([]); + + const template = templateById(templateId); + const roster: Seat[] = useMemo( + () => [ + ...(me ? [{ address: me, roles: Role.OWNER | Role.APPROVER | Role.EXECUTOR }] : []), + ...seats.filter((s) => /^0x[0-9a-fA-F]{1,64}$/.test(s.address)), + ], + [me, seats], + ); + + const counts = useMemo(() => { + const has = (r: number) => roster.filter((s) => (s.roles & r) !== 0).length; + return { + owners: has(Role.OWNER), + approvers: has(Role.APPROVER), + executors: has(Role.EXECUTOR), + guardians: has(Role.GUARDIAN), + }; + }, [roster]); + + const policyErrors = validatePolicy(template.policy); + const countErrors = validateCounts( + template.policy, + counts.owners, + counts.approvers, + counts.executors, + counts.guardians, + ); + const badRoles = roster.filter((s) => !rolesValid(s.roles)); + const duplicates = roster.length !== new Set(roster.map((s) => s.address)).size; + + const ready = + Boolean(me) && + CONFIGURED && + name.trim().length > 0 && + policyErrors.length === 0 && + countErrors.length === 0 && + badRoles.length === 0 && + !duplicates; + + const create = () => + tx.run( + build.createVault(PACKAGE_ID, { + name: name.trim(), + policy: template.policy, + members: roster, + assets: [{ coinType: SUI_TYPE_ARG, limits: template.native }], + recipients: [], + }), + 'create', + ); + + return ( +
      +
      +

      Pick a starting policy

      +

      + Each one is a complete, valid policy. Start with the closest fit and tighten it afterwards + through governance. +

      +
      + {TEMPLATES.map((t) => ( + + ))} +
      +
      + +
      +
      +

      Name it

      +
      + setName(e.target.value)} maxLength={60} /> +
      +
      + +
      +

      Who holds what

      +

      + You are the first owner, approver and executor. Add the rest — and note that the + contract will not let one address be both a guardian and anything else. +

      + + {me ? ( +
      +
      + {me.slice(0, 10)}…{me.slice(-6)} + you + + Owner + Approver + Executor +
      +
      + ) : null} + +
      + {seats.map((s, i) => ( +
      + + setSeats((v) => v.map((x, j) => (j === i ? { ...x, address: e.target.value.trim() } : x))) + } + style={{ flex: 1, minWidth: 220 }} + spellCheck={false} + /> + + +
      + ))} +
      + + + +
      + {counts.owners} owner{counts.owners === 1 ? '' : 's'} + {counts.approvers} approver{counts.approvers === 1 ? '' : 's'} + {counts.executors} executor{counts.executors === 1 ? '' : 's'} + {counts.guardians} guardian{counts.guardians === 1 ? '' : 's'} +
      +
      + + {!CONFIGURED ? ( + + No package is configured for this network. Publish with{' '} + sui/scripts/publish.sh and set{' '} + NEXT_PUBLIC_SKUR_PACKAGE_ID. + + ) : null} + {!me ? Connect a wallet to create a vault. : null} + {duplicates ? An address appears twice. : null} + {badRoles.length > 0 ? ( + + A guardian cannot also hold a treasury role. The contract would refuse this roster. + + ) : null} + {countErrors.length > 0 ? ( + + This template needs a larger roster. +
        + {countErrors.map((e) => ( +
      • {e}
      • + ))} +
      +
      + ) : null} + {tx.error ? {tx.error} : null} + + +

      + One transaction creates the vault, sets the policy, installs the signers and approves SUI. + If any part is invalid, nothing is created. +

      +
      +
      + ); +} diff --git a/app/src/components/Overview.tsx b/app/src/components/Overview.tsx new file mode 100644 index 0000000..13e58a1 --- /dev/null +++ b/app/src/components/Overview.tsx @@ -0,0 +1,248 @@ +'use client'; + +import { + Mode, + Reason, + Status, + describeReasons, + fmtAmount, + fmtDuration, + type VaultView, +} from '@skur/sdk'; +import { EXPLORER } from '@/config'; +import { Addr, Amount, ModePill, Notice, coinDecimals, coinSymbol } from './ui'; + +/** + * What the vault is right now: its posture, what it holds, how much of each window is used, and + * the policy in one glance. Everything here is read from the chain. + */ +export function Overview({ view }: { view: VaultView }) { + const { vault, assets, proposals, members } = view; + const pending = proposals.filter((p) => p.status === Status.PENDING); + const p = vault.policy; + + return ( +
      + {vault.mode === Mode.LOCKDOWN ? ( + + This vault is in Lockdown. Nothing outgoing executes and no payment can + be opened. Deposits still work. Leaving Lockdown needs{' '} + {p.governanceThreshold} owner approval{p.governanceThreshold === 1 ? '' : 's'},{' '} + {p.guardianThreshold} guardian confirmation{p.guardianThreshold === 1 ? '' : 's'} and{' '} + {fmtDuration(p.policyChangeDelay)}. + {vault.postureReasons ? ( +
        + {describeReasons(vault.postureReasons).map((r) => ( +
      • {r}
      • + ))} +
      + ) : null} +
      + ) : null} + {vault.mode === Mode.ELEVATED ? ( + + Elevated. Every payment is escalated one tier and the per-transaction and + daily caps are halved, until owners and a guardian agree to lower the posture. + {vault.postureReasons ? ( +
        + {describeReasons(vault.postureReasons).map((r) => ( +
      • {r}
      • + ))} +
      + ) : null} +
      + ) : null} + +
      +
      +

      Posture

      +
      + +
      +
      +
      +

      Awaiting action

      +

      {pending.length}

      +
      +
      +

      Signers

      +

      {members.length}

      +

      + {vault.ownerCount} owner{vault.ownerCount === 1 ? '' : 's'} · {vault.guardianCount}{' '} + guardian{vault.guardianCount === 1 ? '' : 's'} +

      +
      +
      +

      Policy version

      +

      {vault.policyVersion.toString()}

      +
      +
      + +
      +

      Holdings

      +

      + Each asset has its own limits, its own day and its own loss envelope. There is no + portfolio-wide number, because computing one honestly would need a price oracle. +

      + {assets.length === 0 ? ( +

      + No assets configured yet. +

      + ) : ( +
      + + + + + + + + + + + + {assets.map((a) => { + const d = coinDecimals(a.coinType); + const sym = coinSymbol(a.coinType); + const daily = a.limits.dailyMax; + const spent = a.velocity?.daySpent ?? 0n; + const dayPct = daily === 0n ? 0 : Number((spent * 100n) / daily); + const basis = a.velocity?.envelopeBasis ?? a.balance; + const envLimit = + p.envelopeBps === 0 ? 0n : (basis * BigInt(p.envelopeBps)) / 10_000n; + const envSpent = a.velocity?.envelopeSpent ?? 0n; + const envPct = envLimit === 0n ? 0 : Number((envSpent * 100n) / envLimit); + return ( + + + + + + + + + ); + })} + +
      AssetBalanceRoutine up toPer paymentTodayEnvelope
      + {sym} + {!a.limits.approved ? ( + + not approved + + ) : null} + {fmtAmount(a.balance, d)}{fmtAmount(a.limits.lowMax, d)} + {a.limits.perTxMax === 0n ? 'no cap' : fmtAmount(a.limits.perTxMax, d)} + + {daily === 0n ? ( + no cap + ) : ( + <> +
      80 ? 'bad' : dayPct > 50 ? 'warn' : ''}`}> + +
      + + {fmtAmount(spent, d)} of {fmtAmount(daily, d)} + + + )} +
      + {envLimit === 0n ? ( + off + ) : ( + <> +
      80 ? 'bad' : envPct > 50 ? 'warn' : ''}`}> + +
      + + {fmtAmount(envSpent, d)} of {fmtAmount(envLimit, d)} + + + )} +
      + )} +
      + +
      +
      +

      Approvals

      +
      +
      +
      Routine payment
      +
      + {p.approvalsLow} approval{p.approvalsLow === 1 ? '' : 's'}, no wait +
      +
      +
      +
      High risk
      +
      + {p.approvalsHigh} approvals, {fmtDuration(p.delayHigh)} +
      +
      +
      +
      Critical
      +
      + {p.approvalsCritical} approvals + {p.guardianRequiredCritical ? ` + ${p.guardianThreshold} guardian` : ''},{' '} + {fmtDuration(p.delayCritical)} +
      +
      +
      +
      Governance
      +
      + {p.governanceThreshold} owner{p.governanceThreshold === 1 ? '' : 's'} +
      +
      +
      +
      +
      +

      Delays and limits

      +
      +
      +
      New recipient waits
      +
      {fmtDuration(p.recipientActivationDelay)}
      +
      +
      +
      Weakening the policy waits
      +
      {fmtDuration(p.policyChangeDelay)}
      +
      +
      +
      Escalates above
      +
      + {p.highExposureBps / 100}% held, critical at {p.criticalExposureBps / 100}% +
      +
      +
      +
      Refused above
      +
      + {p.hardBlockExposureBps === 0 + ? 'no hard block' + : `${p.hardBlockExposureBps / 100}% of an asset`} +
      +
      +
      +
      Loss envelope
      +
      + {p.envelopeBps === 0 + ? 'off' + : `${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}`} +
      +
      +
      +
      +
      + +
      +
      +
      +

      This vault

      + +
      + + Open on the explorer + +
      +
      +
      + ); +} diff --git a/app/src/components/People.tsx b/app/src/components/People.tsx new file mode 100644 index 0000000..ed2367c --- /dev/null +++ b/app/src/components/People.tsx @@ -0,0 +1,351 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useState } from 'react'; +import { + ROLE_LABELS, + Role, + Trust, + describeRoles, + fmtTimestamp, + hasRole, + rolesValid, + tx as build, + type VaultView, +} from '@skur/sdk'; +import { PACKAGE_ID } from '@/config'; +import type { TxState } from '@/hooks/useVault'; +import { Addr, Countdown, Empty, Notice, Roles, TrustPill } from './ui'; + +/** Signers and recipients: who can act, and who can be paid. */ +export function People({ view, tx }: { view: VaultView; tx: TxState }) { + const account = useCurrentAccount(); + const me = account?.address; + const roles = me ? (view.members.find((m) => m.address === me)?.roles ?? 0) : 0; + const isOwner = hasRole(roles, Role.OWNER); + + const [newMember, setNewMember] = useState(''); + const [newRoles, setNewRoles] = useState(Role.APPROVER); + const [newRecipient, setNewRecipient] = useState(''); + const [label, setLabel] = useState(''); + const [lost, setLost] = useState(''); + const [replacement, setReplacement] = useState(''); + + const rolesOk = rolesValid(newRoles); + + return ( +
      + {tx.error ? {tx.error} : null} + +
      +

      Signers

      +

      + A guardian holds no treasury role and no treasury member holds the guardian role. The + contract refuses any other arrangement. +

      + + + + + + + + + {view.members.map((m) => ( + + + + + + ))} + +
      AddressRoles +
      + + {m.address === me ? you : null} + + + + +
      + +
      +

      Add a signer

      +

      + Granting a role is treated as weakening the vault — a new key is a new way in — so it + waits out the policy-change delay and any guardian can veto it. +

      +
      +
      + + setNewMember(e.target.value.trim())} + spellCheck={false} + /> +
      +
      + +
      + {[Role.OWNER, Role.APPROVER, Role.EXECUTOR, Role.GUARDIAN, Role.PROPOSER].map((r) => ( + + ))} +
      +
      + +
      + {!rolesOk ? ( +

      + {newRoles === 0 + ? 'Pick at least one role.' + : 'A guardian cannot also hold a treasury role. The contract would refuse this.'} +

      + ) : ( +

      + {describeRoles(newRoles).join(', ') || '—'} +

      + )} +
      + +
      +

      Replace a lost key

      +

      + A guardian opens this. It waits {Math.round(view.vault.policy.recoveryDelay / 3_600_000)}{' '} + hours, any owner can cancel it, the roles move across unchanged, and the vault comes out + of it in Elevated. +

      +
      +
      + + setLost(e.target.value.trim())} /> +
      +
      + + setReplacement(e.target.value.trim())} + /> +
      + +
      +
      +
      + +
      +

      Recipients

      +

      + An address the vault has never paid is escalated every time. Registering one starts it at + the restrictive default and makes it serve an activation delay. +

      + {view.recipients.length === 0 ? ( + No recipients registered. Payments can still be made; they are just escalated. + ) : ( + + + + + + + + + + + + {view.recipients.map((r) => ( + + + + + + + + + ))} + +
      AddressLabelStandingPaidActivates +
      + + {r.label || '—'} + + {r.paidCount} + {r.activatesAt > Date.now() ? ( + + ) : ( + active + )} + + {r.trust !== Trust.BLOCKED ? ( + + ) : ( + + )} +
      + )} + +
      +

      Register a recipient

      +
      +
      + + setNewRecipient(e.target.value.trim())} + spellCheck={false} + /> +
      +
      + + setLabel(e.target.value)} + maxLength={60} + /> +
      + +
      +

      + Takes effect at once, because trust “new” with an activation delay is + stricter than unknown. Raising it further is a governance action with a timelock. +

      +
      + +

      + Last registered {view.recipients.length > 0 ? fmtTimestamp(Math.max(...view.recipients.map((r) => r.registeredAt))) : '—'} +

      +
      +
      + ); +} diff --git a/app/src/components/PolicyPanel.tsx b/app/src/components/PolicyPanel.tsx new file mode 100644 index 0000000..898cf95 --- /dev/null +++ b/app/src/components/PolicyPanel.tsx @@ -0,0 +1,265 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useMemo, useState } from 'react'; +import { + POLICY_GROUPS, + Role, + fmtDuration, + fromHours, + hasRole, + policyReductions, + runScenarios, + toHours, + tx as build, + validateCounts, + validatePolicy, + type Policy, + type VaultView, +} from '@skur/sdk'; +import { PACKAGE_ID } from '@/config'; +import type { TxState } from '@/hooks/useVault'; +import { Notice, coinDecimals, coinSymbol } from './ui'; + +/** + * The policy editor and the simulator. + * + * Editing is one screen with the consequences on it: what the change gives up, whether it is + * coherent at all, and what the attacks look like against the edited policy rather than the live + * one. Everything here runs the same algorithms as the Move modules, which is the only reason it + * is safe to show a number for a policy that is not deployed. + */ +export function PolicyPanel({ view, tx }: { view: VaultView; tx: TxState }) { + const account = useCurrentAccount(); + const roles = account ? (view.members.find((m) => m.address === account.address)?.roles ?? 0) : 0; + const [draft, setDraft] = useState(view.vault.policy); + + const errors = useMemo(() => validatePolicy(draft), [draft]); + const countErrors = useMemo( + () => + validateCounts( + draft, + view.vault.ownerCount, + view.vault.approverCount, + view.vault.executorCount, + view.vault.guardianCount, + ), + [draft, view.vault], + ); + const reductions = useMemo(() => policyReductions(view.vault.policy, draft), [view.vault.policy, draft]); + const changed = JSON.stringify(draft) !== JSON.stringify(view.vault.policy); + const valid = errors.length === 0 && countErrors.length === 0; + + const set = (key: keyof Policy, value: number | boolean) => + setDraft((d) => ({ ...d, [key]: value }) as Policy); + + const biggest = view.assets.reduce( + (best, a) => (a.balance > (best?.balance ?? -1n) ? a : best), + view.assets[0], + ); + + const scenarios = useMemo(() => { + if (!biggest) return []; + return runScenarios({ + policy: draft, + limits: biggest.limits, + balance: biggest.balance, + decimals: coinDecimals(biggest.coinType), + symbol: coinSymbol(biggest.coinType), + approverCount: view.vault.approverCount, + guardianCount: view.vault.guardianCount, + }); + }, [draft, biggest, view.vault]); + + return ( +
      + {tx.error ? {tx.error} : null} + +
      +
      + {POLICY_GROUPS.map((group) => ( +
      +

      {group.title}

      +

      {group.sub}

      +
      + {group.fields.map((f) => { + const raw = draft[f.key]; + if (f.unit === 'bool') { + return ( +
      + set(f.key, e.target.checked)} + /> + +
      + ); + } + const value = + f.unit === 'hours' + ? toHours(Number(raw)) + : f.unit === 'bps' + ? Number(raw) / 100 + : Number(raw); + return ( +
      + + { + const n = Number(e.target.value); + if (Number.isNaN(n) || n < 0) return; + set( + f.key, + f.unit === 'hours' + ? fromHours(n) + : f.unit === 'bps' + ? Math.round(n * 100) + : Math.round(n), + ); + }} + /> +
      + ); + })} +
      +
      + ))} +
      + +
      +
      +

      What this change does

      + {!changed ? ( +

      + Nothing yet. Edit a field to see what it gives up. +

      + ) : ( +
      + {errors.length > 0 || countErrors.length > 0 ? ( + + The vault would not accept this policy. +
        + {[...errors, ...countErrors].map((e) => ( +
      • {e}
      • + ))} +
      +
      + ) : reductions.length === 0 ? ( + + This change only tightens the vault, so it takes effect as soon as{' '} + {view.vault.policy.governanceThreshold} owner + {view.vault.policy.governanceThreshold === 1 ? '' : 's'} approve it. + + ) : ( + + This gives up {reductions.length} control{reductions.length === 1 ? '' : 's'}. +
        + {reductions.map((r) => ( +
      • {r}
      • + ))} +
      +

      + It will wait {fmtDuration(view.vault.policy.policyChangeDelay)} and any + guardian can veto it. It cannot be opened at all while the vault is in + Lockdown. +

      +
      + )} +
      + )} + +
      + + +
      +
      + +
      +

      The attacks, against this policy

      +

      + Run with the edited policy and this vault's largest holding. The verdicts are the + vault's own rules, not a score. +

      + {scenarios.length === 0 ? ( +
      Fund an asset to run the scenarios.
      + ) : ( +
      + {scenarios.map((s) => ( +
      +
      + {s.title} + + +
      +

      + {s.narrative} +

      +
        + {s.detail.map((d) => ( +
      • {d}
      • + ))} +
      +
      + ))} +
      + )} +
      +
      +
      +
      + ); +} + +function Verdict({ verdict }: { verdict: string }) { + const cls = + verdict === 'blocked' || verdict === 'impossible' + ? 'low' + : verdict === 'delayed' || verdict === 'escalated' + ? 'high' + : 'critical'; + const label = + verdict === 'blocked' + ? 'stopped' + : verdict === 'impossible' + ? 'impossible' + : verdict === 'delayed' + ? 'delayed' + : verdict === 'escalated' + ? 'escalated' + : 'would succeed'; + return {label}; +} diff --git a/app/src/components/Queue.tsx b/app/src/components/Queue.tsx new file mode 100644 index 0000000..2064aaa --- /dev/null +++ b/app/src/components/Queue.tsx @@ -0,0 +1,343 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { + KIND_LABELS, + Kind, + Role, + Status, + Tier, + describeReasons, + fmtDuration, + fmtTimestamp, + hasRole, + policyReductions, + tx as build, + type Proposal, + type VaultView, +} from '@skur/sdk'; +import { PACKAGE_ID } from '@/config'; +import type { TxState } from '@/hooks/useVault'; +import { Addr, Amount, Countdown, Empty, Notice, StatusPill, TierPill } from './ui'; + +/** + * The queue, and the actions on it. + * + * Every button is gated on the role the contract requires, so a signer is never offered an action + * the vault would refuse. The requirement shown is the one pinned on the proposal; at execution + * the vault re-derives it and applies whichever is stricter, which is why a payment can need more + * than this says but never less. + */ +export function Queue({ view, tx }: { view: VaultView; tx: TxState }) { + const account = useCurrentAccount(); + const me = account?.address; + const roles = me ? (view.members.find((m) => m.address === me)?.roles ?? 0) : 0; + const pending = view.proposals.filter((p) => p.status === Status.PENDING); + const settled = view.proposals.filter((p) => p.status !== Status.PENDING); + + return ( +
      + {tx.error ? {tx.error} : null} +
      +

      Awaiting action

      +

      + {pending.length === 0 + ? 'Nothing is waiting.' + : `${pending.length} proposal${pending.length === 1 ? '' : 's'} open.`} +

      + {pending.length === 0 ? ( + The queue is empty. + ) : ( +
      + {pending.map((p) => ( + + ))} +
      + )} +
      + +
      +

      History

      + {settled.length === 0 ? ( + Nothing has settled yet. + ) : ( + + + + + + + + + + + + + {settled.map((p) => ( + + + + + + + + + ))} + +
      #WhatAmountToOutcomeWhen
      {p.id.toString()}{KIND_LABELS[p.kind]} + {p.kind === Kind.TRANSFER && p.asset ? ( + + ) : ( + — + )} + + {p.kind === Kind.TRANSFER ? : —} + + + {fmtTimestamp(p.createdAt)}
      + )} +
      +
      + ); +} + +function ProposalCard({ + p, + view, + roles, + me, + tx, +}: { + p: Proposal; + view: VaultView; + roles: number; + me: string | undefined; + tx: TxState; +}) { + const id = p.id; + const vaultId = view.vault.id; + const now = Date.now(); + const liveApprovals = p.approvals.filter((a) => + hasRole(view.members.find((m) => m.address === a)?.roles ?? 0, Role.APPROVER), + ).length; + const liveConfirmations = p.confirmations.filter((a) => + hasRole(view.members.find((m) => m.address === a)?.roles ?? 0, Role.GUARDIAN), + ).length; + + const isTransfer = p.kind === Kind.TRANSFER; + const voteRole = isTransfer ? Role.APPROVER : Role.OWNER; + const alreadyApproved = me ? p.approvals.includes(me) : false; + const alreadyConfirmed = me ? p.confirmations.includes(me) : false; + + const approvalsMet = liveApprovals >= p.reqApprovals; + const guardiansMet = liveConfirmations >= p.reqGuardians; + const timeMet = now >= p.executableAt; + const canExecute = approvalsMet && guardiansMet && timeMet; + + // A guardian can veto exactly what the contract lets them veto, and nothing else. + const vetoable = + p.reductionMask !== 0 || + (isTransfer && p.tier === Tier.CRITICAL) || + p.kind === Kind.RECOVERY || + p.kind === Kind.MODE_RELAX; + + const executeTx = () => { + if (isTransfer && p.asset) + return build.executeTransfer(PACKAGE_ID, { vaultId, coinType: p.asset, proposalId: id }); + if (p.kind === Kind.POLICY_UPDATE) return build.executePolicy(PACKAGE_ID, vaultId, id); + if (p.kind === Kind.MEMBER_SET) return build.executeMember(PACKAGE_ID, vaultId, id); + if (p.kind === Kind.RECIPIENT_TRUST) + return build.executeRecipientTrust(PACKAGE_ID, vaultId, id); + if (p.kind === Kind.MODE_RELAX) return build.executeModeRelax(PACKAGE_ID, vaultId, id); + if (p.kind === Kind.RECOVERY) return build.executeRecovery(PACKAGE_ID, vaultId, id); + if (p.kind === Kind.ASSET_LIMITS && p.asset) + return build.executeAssetLimits(PACKAGE_ID, { vaultId, coinType: p.asset, proposalId: id }); + return null; + }; + + // Executing a payment takes the executor role; settling a governance change takes any member, + // because its authorization is the owner approvals already recorded on it. + const mayExecute = isTransfer ? hasRole(roles, Role.EXECUTOR) : roles !== 0; + const reasons = describeReasons(p.reasons); + const reductions = p.newPolicy ? policyReductions(view.vault.policy, p.newPolicy) : []; + + return ( +
      +
      + #{id.toString()} + {KIND_LABELS[p.kind]} + {isTransfer ? : null} + {p.reductionMask !== 0 ? weakens the vault : null} + + expires {fmtTimestamp(p.expiresAt)} +
      + + {isTransfer && p.asset ? ( +
      +

      + +

      + to + + {p.exposureBps > 0 ? ( + {(p.exposureBps / 100).toFixed(2)}% of holdings + ) : null} +
      + ) : null} + {p.memo ?

      {p.memo}

      : null} + + {p.kind === Kind.MEMBER_SET ? ( +

      + {p.memberRoles === 0 ? 'Remove ' : 'Set roles for '} + + {p.memberRoles !== 0 ? ` to ${p.memberRoles}` : ''} +

      + ) : null} + {p.kind === Kind.RECOVERY ? ( +

      + Replace with , same roles. Any + owner can cancel this before it executes. +

      + ) : null} + + {reasons.length > 0 ? ( + <> +

      + Scored this way because: +

      +
        + {reasons.map((r) => ( +
      • {r}
      • + ))} +
      + + ) : null} + {reductions.length > 0 ? ( + <> +

      + This change gives up: +

      +
        + {reductions.map((r) => ( +
      • {r}
      • + ))} +
      + + ) : null} + +
      + + + {liveApprovals}/{p.reqApprovals} + {' '} + approvals + {liveApprovals < p.approvals.length ? ( + ({p.approvals.length - liveApprovals} no longer count) + ) : null} + + {p.reqGuardians > 0 ? ( + + + {liveConfirmations}/{p.reqGuardians} + {' '} + guardian + + ) : null} + + executable + + +
      + +
      + + + {p.reqGuardians > 0 || vetoable ? ( + + ) : null} + + {vetoable ? ( + + ) : null} + + + + + + + {now >= p.expiresAt ? ( + + ) : null} +
      + + {p.reductionMask !== 0 ? ( +

      + A weakening waits {fmtDuration(view.vault.policy.policyChangeDelay)} and any guardian can + stop it until then. +

      + ) : null} +
      + ); +} diff --git a/app/src/components/Security.tsx b/app/src/components/Security.tsx new file mode 100644 index 0000000..7d7d71f --- /dev/null +++ b/app/src/components/Security.tsx @@ -0,0 +1,228 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useMemo, useState } from 'react'; +import { + Mode, + Role, + Trust, + computeMaxLoss, + fmtAmount, + fmtDuration, + hasRole, + postureItems, + tx as build, + type VaultView, +} from '@skur/sdk'; +import { PACKAGE_ID } from '@/config'; +import type { TxState } from '@/hooks/useVault'; +import { Notice, coinDecimals, coinSymbol } from './ui'; + +/** + * The security screen: what holds, what the worst case looks like, and the two controls a human + * reaches for in an incident. + */ +export function Security({ view, tx }: { view: VaultView; tx: TxState }) { + const account = useCurrentAccount(); + const roles = account ? (view.members.find((m) => m.address === account.address)?.roles ?? 0) : 0; + const posture = useMemo( + () => + postureItems({ + policy: view.vault.policy, + guardians: view.vault.guardianCount, + assets: view.assets.map((a) => ({ symbol: coinSymbol(a.coinType), limits: a.limits })), + }), + [view], + ); + + const canFreeze = hasRole(roles, Role.GUARDIAN) || hasRole(roles, Role.OWNER); + const [blockAddr, setBlockAddr] = useState(''); + + return ( +
      + {tx.error ? {tx.error} : null} + +
      +
      +

      What holds

      +

      + Confirmed controls and obvious gaps. This is not a score and does not claim to measure + absolute security. +

      +
      + {posture.map((item) => ( +
      + + {item.text} +
      + ))} +
      +
      + +
      +

      In an incident

      +

      + Raising the posture is immediate and unilateral. Lowering it never is. +

      +
      + +

      + Escalates every payment one tier and halves the per-payment and daily caps. +

      + + +

      + Stops all outgoing execution at once. Deposits keep working. Leaving needs{' '} + {view.vault.policy.governanceThreshold} owner + {view.vault.policy.governanceThreshold === 1 ? '' : 's'},{' '} + {view.vault.policy.guardianThreshold} guardian + {view.vault.policy.guardianThreshold === 1 ? '' : 's'} and{' '} + {fmtDuration(view.vault.policy.policyChangeDelay)}. +

      + + {view.vault.mode !== Mode.NORMAL ? ( + + ) : null} + +
      + +
      + setBlockAddr(e.target.value.trim())} + spellCheck={false} + /> + +
      +

      + The one unilateral power in the system, and it can only ever stop money. +

      +
      +
      +
      +
      + +
      +

      Maximum possible loss

      +

      + Per asset, assuming every signer a tier needs is compromised and cooperating, and that no + guardian acts. It is an upper bound under those assumptions, never a guarantee. +

      + {view.assets.length === 0 ? ( +
      No assets configured.
      + ) : ( + + + + + + + + + + + + + {view.assets.map((a) => { + const r = computeMaxLoss(view.vault.policy, a.limits, a.balance, view.vault.mode); + const d = coinDecimals(a.coinType); + return ( + + + + + + + + + ); + })} + +
      AssetWith no delayBounded byWithin a dayBounded byLargest payments wait
      + {coinSymbol(a.coinType)} + {fmtAmount(r.immediate, d)}{r.immediateBinding}{fmtAmount(r.day, d)}{r.dayBinding}{fmtDuration(r.criticalDelay)}
      + )} +
      + + The assumptions behind these numbers + +
        + {computeMaxLoss( + view.vault.policy, + view.assets[0]?.limits ?? { approved: false, lowMax: 0n, highMax: 0n, perTxMax: 0n, dailyMax: 0n }, + view.assets[0]?.balance ?? 0n, + view.vault.mode, + ).assumptions.map((a) => ( +
      • {a}
      • + ))} +
      • + A 24-hour bucket anchors on its first payment, so up to two days' allowance can + leave across a boundary. The envelope and the per-payment cap bound that. +
      • +
      +
      +
      +
      + ); +} diff --git a/app/src/components/Send.tsx b/app/src/components/Send.tsx new file mode 100644 index 0000000..4bbafb1 --- /dev/null +++ b/app/src/components/Send.tsx @@ -0,0 +1,341 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { useMemo, useState } from 'react'; +import { + Role, + Trust, + canPropose, + describeReasons, + fmtAmount, + fmtDuration, + parseAmount, + tx as build, + type VaultView, +} from '@skur/sdk'; +import { API_URL, PACKAGE_ID } from '@/config'; +import { useTransferPreview, type TxState } from '@/hooks/useVault'; +import { Addr, Amount, Countdown, Notice, TierPill, TrustPill, coinDecimals, coinSymbol } from './ui'; + +/** + * Opening a payment. + * + * The review under the form is the vault's own classification, simulated live. The interface does + * not compute it, so it cannot promise something the vault would refuse — which is the whole point + * of `preview_transfer` being the same code `execute_transfer` runs. + */ +export function Send({ view, tx }: { view: VaultView; tx: TxState }) { + const account = useCurrentAccount(); + const me = account?.address; + const roles = me ? (view.members.find((m) => m.address === me)?.roles ?? 0) : 0; + const approved = view.assets.filter((a) => a.limits.approved); + const [coinType, setCoinType] = useState(approved[0]?.coinType ?? ''); + const [recipient, setRecipient] = useState(''); + const [amountText, setAmountText] = useState(''); + const [memo, setMemo] = useState(''); + + const asset = approved.find((a) => a.coinType === coinType) ?? approved[0]; + const decimals = coinType ? coinDecimals(coinType) : 9; + const amount = useMemo(() => parseAmount(amountText, decimals) ?? 0n, [amountText, decimals]); + const recipientValid = /^0x[0-9a-fA-F]{1,64}$/.test(recipient); + + const known = view.recipients.find((r) => r.address === recipient); + const trust = known?.trust ?? Trust.UNKNOWN; + const activatesAt = known?.activatesAt ?? 0; + + const preview = useTransferPreview({ + vaultId: view.vault.id, + coinType, + amount, + recipient, + sender: me, + enabled: Boolean(coinType) && recipientValid && amount > 0n, + }); + + // Local checks that mirror what `propose_transfer` would refuse, so the form says why before a + // wallet opens rather than after a transaction fails. + const problems: string[] = []; + if (asset && amount > 0n) { + if (trust === Trust.BLOCKED) problems.push('This recipient is blocked by the vault.'); + if (asset.limits.perTxMax !== 0n && amount > asset.limits.perTxMax) + problems.push( + `Above the per-payment cap of ${fmtAmount(asset.limits.perTxMax, decimals, coinSymbol(coinType))}.`, + ); + const spent = asset.velocity?.daySpent ?? 0n; + if (asset.limits.dailyMax !== 0n && spent + amount > asset.limits.dailyMax) + problems.push( + `Above what is left of today's allowance (${fmtAmount(asset.limits.dailyMax - spent, decimals, coinSymbol(coinType))}).`, + ); + const hb = view.vault.policy.hardBlockExposureBps; + if (hb !== 0 && asset.balance > 0n && (amount * 10_000n) / asset.balance >= BigInt(hb)) + problems.push(`At or above the hard block of ${hb / 100}% of this asset. No approval clears it.`); + if (amount > asset.balance) + problems.push(`The vault holds ${fmtAmount(asset.balance, decimals, coinSymbol(coinType))}.`); + } + + const mayPropose = canPropose(roles); + const ready = mayPropose && recipientValid && amount > 0n && problems.length === 0 && Boolean(coinType); + + const submit = () => { + tx.run( + build.proposeTransfer(PACKAGE_ID, { + vaultId: view.vault.id, + coinType, + amount, + recipient, + memo, + }), + 'propose', + ).then((digest) => { + if (digest) { + setAmountText(''); + setMemo(''); + } + }); + }; + + if (approved.length === 0) { + return ( + + No asset is approved for this vault yet. An owner has to approve one through governance + before anything can be paid. + + ); + } + + return ( +
      +
      +

      Open a payment

      +

      + Opening a payment is not approving it. The vault scores it first and then says what it + needs. +

      + +
      +
      + + +
      + +
      + + setRecipient(e.target.value.trim())} + spellCheck={false} + /> + {recipient && !recipientValid ? ( +

      + That is not a Sui address. +

      + ) : null} + {recipientValid ? ( +
      + + {known?.label ? {known.label} : null} + {known && known.paidCount > 0 ? ( + + paid {known.paidCount} time{known.paidCount === 1 ? '' : 's'} before + + ) : ( + never paid by this vault + )} + {activatesAt > Date.now() ? ( + + activates + + ) : null} +
      + ) : null} +
      + +
      + + setAmountText(e.target.value)} + inputMode="decimal" + /> + {asset ? ( +

      + Routine up to {fmtAmount(asset.limits.lowMax, decimals)} · high risk up to{' '} + {fmtAmount(asset.limits.highMax, decimals)} · above that, critical +

      + ) : null} +
      + +
      + + setMemo(e.target.value)} + maxLength={120} + /> +
      +
      + + {!mayPropose ? ( +
      + + The connected key cannot open payments in this vault. That takes an owner, approver, + executor or proposer role. + +
      + ) : null} + + {problems.length > 0 ? ( +
      + + The vault would refuse this. +
        + {problems.map((p) => ( +
      • {p}
      • + ))} +
      +
      +
      + ) : null} + {tx.error ? ( +
      + {tx.error} +
      + ) : null} + + +
      + +
      +

      What the vault will demand

      +

      + Read from the vault itself, not computed here. If this says three approvals and a day, + that is what execution will require. +

      + + {!recipientValid || amount === 0n ? ( +
      Fill in a recipient and an amount.
      + ) : preview.isLoading ? ( +
      Asking the vault…
      + ) : preview.error ? ( +
      + + Could not reach the vault for a preview. The checks on the left still apply, and + execution is governed by the chain either way. + +
      + ) : preview.data ? ( + + ) : null} +
      +
      + ); +} + +function PreviewBody({ + data, + amount, + coinType, + balance, + activatesAt, +}: { + data: { tier: number; reasons: number; exposureBps: number; reqApprovals: number; reqGuardians: number; delay: number }; + amount: bigint; + coinType: string; + balance: bigint; + activatesAt: number; +}) { + const decimals = coinDecimals(coinType); + const reasons = describeReasons(data.reasons); + const executableAt = Math.max(Date.now() + data.delay, activatesAt); + return ( +
      +
      + + + {(data.exposureBps / 100).toFixed(2)}% of this asset + +
      + +
      +
      +
      Leaves the vault
      +
      + +
      +
      +
      +
      Remains after
      +
      {fmtAmount(balance > amount ? balance - amount : 0n, decimals, coinSymbol(coinType))}
      +
      +
      +
      Approvals needed
      +
      {data.reqApprovals}
      +
      +
      +
      Guardian confirmations
      +
      {data.reqGuardians === 0 ? 'none' : data.reqGuardians}
      +
      +
      +
      Waits
      +
      {data.delay === 0 ? 'no wait' : fmtDuration(data.delay)}
      +
      +
      +
      Earliest execution
      +
      + +
      +
      +
      + + {reasons.length > 0 ? ( + <> +

      + Scored this way because: +

      +
        + {reasons.map((r) => ( +
      • {r}
      • + ))} +
      + + ) : ( +

      + Nothing about this payment is unusual, so it stays at the routine tier. +

      + )} + + {activatesAt > Date.now() + data.delay ? ( +

      + The recipient's activation delay, not the tier, is what governs when this can + execute. +

      + ) : null} +
      + ); +} diff --git a/app/src/components/Shell.tsx b/app/src/components/Shell.tsx new file mode 100644 index 0000000..13a2c80 --- /dev/null +++ b/app/src/components/Shell.tsx @@ -0,0 +1,52 @@ +'use client'; + +import { ConnectButton } from '@mysten/dapp-kit-react/ui'; +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import Link from 'next/link'; +import { NETWORK } from '@/config'; +import { ThemeToggle } from './ui'; + +export function Shell({ + children, + tabs, +}: { + children: React.ReactNode; + tabs?: { id: string; label: string; active: boolean; onClick: () => void }[]; +}) { + const account = useCurrentAccount(); + return ( + <> +
      + + S + Skur + + {NETWORK} + {tabs ? ( + + ) : null} + + + +
      +
      + {!account ? ( +
      +

      Connect a wallet to act

      +

      + Reading a vault needs no wallet — the policy, the queue and the history are public. + Approving, executing or opening a payment needs the key that holds the role. +

      +
      + ) : null} + {children} +
      + + ); +} diff --git a/app/src/components/ui.tsx b/app/src/components/ui.tsx new file mode 100644 index 0000000..6d1d814 --- /dev/null +++ b/app/src/components/ui.tsx @@ -0,0 +1,161 @@ +'use client'; + +import { useEffect, useState } from 'react'; +import { + MODE_LABELS, + Mode, + STATUS_LABELS, + Status, + TIER_LABELS, + Tier, + TRUST_LABELS, + Trust, + describeRoles, + fmtAmount, + short, +} from '@skur/sdk'; +import { EXPLORER } from '@/config'; + +export function TierPill({ tier }: { tier: Tier }) { + const cls = tier === Tier.CRITICAL ? 'critical' : tier === Tier.HIGH ? 'high' : 'low'; + return {TIER_LABELS[tier]}; +} + +export function ModePill({ mode }: { mode: Mode }) { + const cls = mode === Mode.LOCKDOWN ? 'critical' : mode === Mode.ELEVATED ? 'high' : 'low'; + return {MODE_LABELS[mode]}; +} + +export function StatusPill({ status }: { status: Status }) { + const cls = + status === Status.EXECUTED + ? 'low' + : status === Status.PENDING + ? '' + : status === Status.BLOCKED || status === Status.VETOED + ? 'critical' + : 'high'; + return {STATUS_LABELS[status]}; +} + +export function TrustPill({ trust }: { trust: Trust }) { + const cls = + trust === Trust.BLOCKED || trust === Trust.RESTRICTED + ? 'critical' + : trust === Trust.TRUSTED || trust === Trust.VERIFIED + ? 'low' + : 'high'; + return {TRUST_LABELS[trust]}; +} + +export function Roles({ bits }: { bits: number }) { + const names = describeRoles(bits); + return ( + + {names.length === 0 ? none : null} + {names.map((n) => ( + + {n} + + ))} + + ); +} + +export function Addr({ value, label }: { value: string; label?: string }) { + return ( + + {label ? `${label} · ` : ''} + {short(value, 6)} + + ); +} + +/** A coin type is long and mostly noise; the struct name is what a person recognises. */ +export function coinSymbol(coinType: string): string { + const name = coinType.split('::').pop() ?? coinType; + return name.toUpperCase(); +} + +/** Decimals are a property of the coin's metadata; these are the ones we can know without a read. */ +const KNOWN_DECIMALS: Record = { SUI: 9, USDC: 6, USDT: 6, USDSUI: 6 }; + +export function coinDecimals(coinType: string): number { + return KNOWN_DECIMALS[coinSymbol(coinType)] ?? 9; +} + +export function Amount({ value, coinType }: { value: bigint; coinType: string }) { + return {fmtAmount(value, coinDecimals(coinType), coinSymbol(coinType))}; +} + +export function Notice({ + kind = 'warn', + children, +}: { + kind?: 'warn' | 'bad' | 'ok' | 'plain'; + children: React.ReactNode; +}) { + return
      {children}
      ; +} + +export function Empty({ children }: { children: React.ReactNode }) { + return
      {children}
      ; +} + +/** Light, dark or whatever the system says, remembered per browser. */ +export function ThemeToggle() { + const [theme, setTheme] = useState<'system' | 'light' | 'dark'>('system'); + + useEffect(() => { + try { + const saved = localStorage.getItem('skur.theme'); + if (saved === 'light' || saved === 'dark' || saved === 'system') setTheme(saved); + } catch { + // Private windows and blocked site data throw here. The default is fine. + } + }, []); + + useEffect(() => { + const root = document.documentElement; + if (theme === 'system') root.removeAttribute('data-theme'); + else root.setAttribute('data-theme', theme); + try { + localStorage.setItem('skur.theme', theme); + } catch { + // Not being able to remember the choice is not a reason to fail to apply it. + } + }, [theme]); + + const next = theme === 'system' ? 'light' : theme === 'light' ? 'dark' : 'system'; + const glyph = theme === 'light' ? '☀' : theme === 'dark' ? '☾' : '◐'; + return ( + + ); +} + +/** A relative time that updates, so "executable in 4m" does not sit there being wrong. */ +export function Countdown({ to }: { to: number }) { + const [now, setNow] = useState(() => Date.now()); + useEffect(() => { + const id = setInterval(() => setNow(Date.now()), 1_000); + return () => clearInterval(id); + }, []); + const left = to - now; + if (left <= 0) return now; + const s = Math.floor(left / 1000); + const d = Math.floor(s / 86400); + const h = Math.floor((s % 86400) / 3600); + const m = Math.floor((s % 3600) / 60); + const sec = s % 60; + const text = d > 0 ? `${d}d ${h}h` : h > 0 ? `${h}h ${m}m` : `${m}m ${sec}s`; + return in {text}; +} diff --git a/app/src/config/deployments.json b/app/src/config/deployments.json new file mode 100644 index 0000000..d7d8dda --- /dev/null +++ b/app/src/config/deployments.json @@ -0,0 +1,17 @@ +{ + "testnet": { + "network": "testnet", + "packageId": "0x0", + "vaults": [] + }, + "devnet": { + "network": "devnet", + "packageId": "0x0", + "vaults": [] + }, + "localnet": { + "network": "localnet", + "packageId": "0x0", + "vaults": [] + } +} diff --git a/app/src/config/index.ts b/app/src/config/index.ts new file mode 100644 index 0000000..785875d --- /dev/null +++ b/app/src/config/index.ts @@ -0,0 +1,25 @@ +import type { Network } from '@skur/sdk'; +import deployments from './deployments.json'; + +/** + * Where the package lives. Published addresses come from `sui/deployments/.json`, copied + * in by `npm run sync-deployments`, and an environment variable overrides them so a developer can + * point at their own publish without editing a committed file. + */ +export const NETWORK = (process.env.NEXT_PUBLIC_SKUR_NETWORK ?? 'testnet') as Network; + +type Deployment = { network: string; packageId: string; vaults: { id: string; name: string }[] }; + +const committed = (deployments as Record)[NETWORK]; + +export const PACKAGE_ID = process.env.NEXT_PUBLIC_SKUR_PACKAGE_ID ?? committed?.packageId ?? '0x0'; + +export const KNOWN_VAULTS = committed?.vaults ?? []; + +/** The indexer. Optional: every screen works without it, just with fewer round trips saved. */ +export const API_URL = process.env.NEXT_PUBLIC_SKUR_API ?? ''; + +export const EXPLORER = (kind: 'object' | 'tx', id: string) => + `https://suiscan.xyz/${NETWORK}/${kind === 'object' ? 'object' : 'tx'}/${id}`; + +export const CONFIGURED = PACKAGE_ID !== '0x0'; diff --git a/app/src/dapp-kit.ts b/app/src/dapp-kit.ts new file mode 100644 index 0000000..b75d019 --- /dev/null +++ b/app/src/dapp-kit.ts @@ -0,0 +1,28 @@ +import { createDAppKit } from '@mysten/dapp-kit-react'; +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { GRPC_ENDPOINTS } from '@skur/sdk'; +import { NETWORK } from './config'; + +/** + * One dApp Kit instance for the app. + * + * The client is `SuiGrpcClient`. This is the reason the app is on `@mysten/dapp-kit-react` 2.x and + * not `@mysten/dapp-kit` 1.x: the older package only speaks JSON-RPC, which Sui is in the middle + * of decommissioning. + */ +export const dAppKit = createDAppKit({ + networks: ['mainnet', 'testnet', 'devnet', 'localnet'] as const, + defaultNetwork: NETWORK, + createClient: (network) => + new SuiGrpcClient({ + network, + baseUrl: process.env.NEXT_PUBLIC_SKUR_GRPC_URL ?? GRPC_ENDPOINTS[network], + }), + autoConnect: true, +}); + +declare module '@mysten/dapp-kit-react' { + interface Register { + dAppKit: typeof dAppKit; + } +} diff --git a/app/src/hooks/useVault.ts b/app/src/hooks/useVault.ts new file mode 100644 index 0000000..58c4f54 --- /dev/null +++ b/app/src/hooks/useVault.ts @@ -0,0 +1,138 @@ +'use client'; + +import { useCurrentClient, useDAppKit } from '@mysten/dapp-kit-react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useCallback, useState } from 'react'; +import type { Transaction } from '@mysten/sui/transactions'; +import { + describeFailure, + fetchVaultView, + previewTransfer, + type TransferPreview, + type VaultView, +} from '@skur/sdk'; +import { NETWORK, PACKAGE_ID } from '@/config'; + +/** Everything one vault screen needs, in as few round trips as the transport allows. */ +export function useVaultView(vaultId: string | undefined) { + const client = useCurrentClient(); + return useQuery({ + queryKey: ['vault', NETWORK, vaultId], + enabled: Boolean(vaultId), + queryFn: () => fetchVaultView(client, vaultId!), + }); +} + +/** + * What the vault itself says this payment would need. + * + * This simulates the vault's own `preview_transfer` rather than running the TypeScript engine, so + * the number on the confirmation screen is the number the chain will demand. The engine is used + * only for a policy that is not deployed yet. + */ +export function useTransferPreview(input: { + vaultId: string; + coinType: string; + amount: bigint; + recipient: string; + sender: string | undefined; + enabled: boolean; +}) { + const client = useCurrentClient(); + return useQuery({ + queryKey: [ + 'preview', + NETWORK, + input.vaultId, + input.coinType, + input.amount.toString(), + input.recipient, + ], + enabled: input.enabled && Boolean(input.sender) && input.amount > 0n, + staleTime: 10_000, + refetchInterval: false, + queryFn: () => + previewTransfer(client, { + packageId: PACKAGE_ID, + vaultId: input.vaultId, + coinType: input.coinType, + amount: input.amount, + recipient: input.recipient, + sender: input.sender!, + }), + }); +} + +export type TxState = { + run: (tx: Transaction, label: string) => Promise; + pending: string | null; + error: string | null; + lastDigest: string | null; + clear: () => void; +}; + +/** + * Sign, execute, wait, invalidate. + * + * A resolved promise means the network executed the transaction, which is not the same as the + * transaction having succeeded — a Move abort comes back as `FailedTransaction`. The abort code is + * translated into the sentence the contract means by it. + */ +export function useVaultTx(vaultId: string | undefined): TxState { + const dAppKit = useDAppKit(); + const client = useCurrentClient(); + const queryClient = useQueryClient(); + const [pending, setPending] = useState(null); + const [error, setError] = useState(null); + const [lastDigest, setLastDigest] = useState(null); + + const mutation = useMutation({ + mutationFn: async ({ tx }: { tx: Transaction; label: string }) => { + const result = await dAppKit.signAndExecuteTransaction({ transaction: tx }); + if (result.FailedTransaction) { + throw new Error( + describeFailure(result.FailedTransaction.status.error?.message ?? 'the vault refused it'), + ); + } + const digest = result.Transaction.digest; + await client.core.waitForTransaction({ digest }); + return digest; + }, + }); + + const run = useCallback( + async (tx: Transaction, label: string) => { + setError(null); + setPending(label); + try { + const digest = await mutation.mutateAsync({ tx, label }); + setLastDigest(digest); + await queryClient.invalidateQueries({ queryKey: ['vault', NETWORK, vaultId] }); + await queryClient.invalidateQueries({ queryKey: ['preview', NETWORK, vaultId] }); + return digest; + } catch (e) { + setError(describeFailure(e)); + return null; + } finally { + setPending(null); + } + }, + [mutation, queryClient, vaultId], + ); + + return { run, pending, error, lastDigest, clear: () => setError(null) }; +} + +/** Vaults the connected address is a member of, via the indexer when one is configured. */ +export function useMyVaults(address: string | undefined, apiUrl: string) { + return useQuery<{ vault_id: string; name: string; roles: number; mode: number }[]>({ + queryKey: ['my-vaults', NETWORK, address], + enabled: Boolean(address && apiUrl), + queryFn: async () => { + const res = await fetch(`${apiUrl}/members/${address}/vaults`); + if (!res.ok) throw new Error(`the indexer returned ${res.status}`); + const body = (await res.json()) as { vaults: { vault_id: string; name: string; roles: number; mode: number }[] }; + return body.vaults; + }, + }); +} diff --git a/app/tsconfig.json b/app/tsconfig.json new file mode 100644 index 0000000..6493f27 --- /dev/null +++ b/app/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["dom", "dom.iterable", "ES2023"], + "allowJs": false, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { "@/*": ["./src/*"] } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/docs/MIGRATION_EVM_TO_SUI.md b/docs/MIGRATION_EVM_TO_SUI.md new file mode 100644 index 0000000..dc84d9a --- /dev/null +++ b/docs/MIGRATION_EVM_TO_SUI.md @@ -0,0 +1,93 @@ +# Moving from EVM to Sui + +What came across, what changed shape because Sui is not an EVM chain, and what the old build is +still here for. + +## Why move at all + +The EVM build worked and was deployed to the Ark Constellation devnet. The reason to move is not +that the code was wrong; it is that the controls Skur exists to provide — approvals that scale with +risk, cumulative outflow accounting, a circuit breaker, a guardian plane — have no onchain +competitor on Sui, while on an EVM chain they sit next to a mature module ecosystem around Safe. +Sui is where this is infrastructure rather than a feature. + +Four things about Sui also make the design better rather than merely portable: + +- **A vault is one shared object.** The policy, the roster, the recipients and the proposals are + fields on it, so "what are the rules right now" is a single read. On the EVM they were storage + slots across a proxy, and the interface had to reconstruct them. +- **Programmable transaction blocks** let creation be atomic without a factory. `begin` hands back + a value with no abilities, so the same transaction must configure the assets and call `finish`. + There is no half-configured vault, and no EIP-1167 clone to deploy and verify. +- **`sui::clock`** gives millisecond time in the transaction. Timelocks are durations, not block + arithmetic. +- **Typed coins.** The treasury is keyed by `TypeName`, so one vault holds any coin type with its + own limits, day and envelope — no token allowlist to maintain, and no `SafeERC20` dance around + tokens that lie about their return values. + +## What carried over unchanged + +The security model. Every control in the EVM build is in the Move build, with the same semantics: + +- the four treasury roles and the exclusive guardian role; +- the three tiers, the six trust levels, the three security modes, the reason bitmask; +- all seventeen policy fields and every validation rule, including the awkward ones — the + proposal lifetime that must clear the longest delay by an hour, the hard block that cannot sit + below the critical exposure threshold; +- the loosening comparison, including the cases where a number going down is a weakening; +- anchored 24-hour buckets and the loss envelope; +- recipient activation delay, pinned-then-tighten-only requirements, live approval recount; +- guardian veto, guardian recovery with an owner cancel; +- the seven policy templates and the attack simulator. + +The TypeScript engines came across as the same algorithms: `risk`, `policy`, `templates`, +`maxLoss`, `posture`, `simulator`, `format`. They now live in [`sdk/src/engine/`](../sdk/src/engine/) +as one copy shared by every interface, instead of in `web/src/lib` with the mobile app reaching +into it through a path alias. + +## What changed shape + +| EVM | Sui | Why | +|---|---|---| +| `SkurFactory` + EIP-1167 clones | `vault::begin` → `setup_*` → `finish` in one PTB | A shared object does not need a proxy, and a hot potato makes the configuration atomic | +| `address` asset identifiers with an allowlist | `TypeName` keys into a `Bag` of `Balance` | The type system is the allowlist | +| `mapping` + arrays for members, recipients, proposals | `Table` and dynamic fields | Reads are per entry rather than per array scan, which is why the SDK lists names and fetches values | +| Durations in seconds | Durations in milliseconds | `sui::clock` reports milliseconds; converting at every comparison is how you get an off-by-1000 | +| `revert` on a tripped breaker, with the mode write lost | `execute_transfer` returns without aborting, so the Lockdown write commits | A latch that reverts with the transaction is not a latch. This is the one behavioural change, and it is a fix | +| `nonReentrant` | Nothing | Move has no dynamic dispatch into a caller; reentrancy is absent by construction | +| `SafeERC20` | `balance::split` | A `Balance` cannot lie about a transfer | +| Events read with `eth_getLogs`, in 9,000-block windows | `listEvents` over gRPC with ledger cursors | No block-range limit to work around; a cursor resumes exactly | +| wagmi + viem, Vite | `@mysten/dapp-kit-react` 2.x, Next.js | `@mysten/dapp-kit` 1.x is deprecated for being JSON-RPC only | +| Nothing | A `PROPOSER` role | The agent case: software that can request a payment and provably cannot take one | +| Nothing | A Node/PostgreSQL indexer and notification service | The EVM interface read the chain directly for everything, which is honest but slow past a few hundred proposals | + +### The one semantic change worth arguing about + +On the EVM, a transfer that would cross the loss envelope reverted. Reverting undid the state +change that put the vault into Lockdown, so the breaker tripped and the vault stayed open — an +attacker could keep trying, and every attempt cost them only gas. + +In Move the function returns instead of aborting: the proposal is marked `BLOCKED`, the vault is set +to Lockdown, a `BreakerTripped` event is emitted, and the transaction **succeeds** so all of that +persists. The money does not move. This is tested by +`crossing_the_loss_envelope_freezes_the_vault_instead_of_paying`, which asserts all three: the +status, the unchanged balance, and the Lockdown. + +## What the old build is still here for + +[`contracts/`](../contracts/), [`web/`](../web/) and [`mobile/`](../mobile/) are the EVM build. They +are kept because: + +- the deployed devnet vault and its verified sources are the only live thing to point an evaluator + at until the Sui package is published and audited; +- `web/src/lib` is the reference the Move modules were ported against, and the EVM test suite is a + second opinion on the engines; +- two pull requests against them are still open. + +They are not the direction. New work goes into [`sui/`](../sui/), [`sdk/`](../sdk/), +[`app/`](../app/) and [`server/`](../server/). The root `package.json` keeps the old scripts under +`legacy:` so nothing silently runs the wrong suite. + +When the Sui package is audited and deployed, the EVM build should be removed rather than +maintained in parallel. Two implementations of a security model is one more than anyone can keep +honest. diff --git a/docs/SUI_SECURITY_MODEL.md b/docs/SUI_SECURITY_MODEL.md new file mode 100644 index 0000000..ed1c383 --- /dev/null +++ b/docs/SUI_SECURITY_MODEL.md @@ -0,0 +1,127 @@ +# Skur security model (Sui / Move) + +What each control is, where it is enforced, and which test proves it. + +The claim is bounded and worth stating before anything else: **Skur adds independent, programmable +controls that can limit or delay damage even when authorized credentials are misused.** It does not +make signer compromise harmless. Anyone who reads this document and concludes otherwise has read it +wrong. + +Module paths are under [`sui/sources/`](../sui/sources/); tests under [`sui/tests/`](../sui/tests/). + +## Two control planes + +| Plane | Role bits | Can | Cannot | +|---|---|---|---| +| Treasury | `OWNER(1)`, `APPROVER(2)`, `EXECUTOR(4)`, `PROPOSER(16)` | open a payment (any treasury role), approve one (approver), execute one (executor), run governance (owner) | veto, confirm, hold the guardian role | +| Guardian | `GUARDIAN(8)` | raise the mode including straight to Lockdown, veto, confirm critical payments, restrict or block a recipient alone, open a recovery | hold any treasury bit, open a payment, approve one, execute one, run governance | + +The exclusivity is `types::roles_valid`, and every path that writes a role goes through it: +`begin`, `execute_member` and `execute_recovery` all call `apply_roles`, which asserts it again. +There is no path that installs a role without it. + +`PROPOSER` is the automation role. It satisfies `can_propose` and nothing else — not approval, not +confirmation, not execution, not governance. + +## The lifecycle, as implemented + +1. **`propose_transfer`** refuses a blocked recipient, an unapproved asset, a zero amount, an + amount over the per-transaction cap, an amount over what is left of the day, and anything at or + above the hard block. Then it classifies the payment through `risk::classify` and pins the tier, + the reasons, the exposure, the required approvals, the required guardian confirmations, + `executable_at` (the tier's delay, or the recipient's activation time, whichever is later) and + `expires_at`. +2. **`approve`** takes the approver role for a payment and the owner role for governance, and + records the approval against the address. **`confirm`** takes the guardian role. +3. **`execute_transfer`** re-evaluates everything against live state — see below — and only then + writes the status, charges the windows, and moves the coin. + +Governance kinds share the same path through `open_governance` and `authorize_governance`, so there +is one place where a proposal becomes effective and one place to audit. + +## What execution re-checks + +This is the function to read: `execute_transfer` in [`vault.move`](../sui/sources/vault.move). + +| Re-checked | Why it cannot be checked only at proposal | +|---|---| +| The asset is still approved | Governance can revoke an asset while a payment is in flight | +| Balance covers the amount | The vault may have paid something else since | +| Recipient is not blocked, and has activated | A guardian can block an address after it was approved | +| Per-transaction and daily caps, under the current mode | The mode may have risen to Elevated, halving both | +| The hard block, against the live balance | A smaller balance makes the same amount a larger share | +| The tier, reclassified | Every input above may have moved | +| Approvals and confirmations, recounted against live roles | A signer may have been removed since approving | +| The timelock, against the live delay as well as the pinned one | The policy may have tightened | +| The loss envelope | Checked last, and charged in the same step as the payment | + +Requirements are **pinned, then tighten-only**: the stricter of the pinned and the live requirement +applies. Tightening the policy affects payments already in flight; loosening it cannot rescue one. + +## Invariants, and the test that proves each + +| # | Invariant | Enforced by | Proven by | +|---|---|---|---| +| 1 | Nothing executes before every active condition is met | the ordered assertions in `execute_transfer` | `a_new_recipient_cannot_skip_activation`, `one_signer_cannot_clear_a_high_tier_payment` | +| 2 | A guardian cannot move treasury assets through guardian authority | `types::roles_valid`, role gates on propose/approve/execute | `a_guardian_cannot_open_a_payment`, `a_guardian_cannot_hold_a_treasury_role` | +| 3 | Lockdown stops outgoing execution and new payments | `assert_not_lockdown` in `propose_transfer` and `execute_transfer` | `lockdown_stops_new_payments_from_being_opened` | +| 4 | A security-reducing change never takes effect immediately | `policy::reductions`, `limit_reductions`, `trust_reduces`, and the delay in `open_governance` | `loosening_the_policy_has_to_wait`, `loosening_the_policy_succeeds_once_the_delay_has_run`, `a_guardian_can_veto_a_weakening`, `tightening_the_policy_takes_effect_as_soon_as_owners_agree` | +| 5 | Cumulative outflow cannot be bypassed by splitting | the day bucket and the envelope in `execute_transfer` | `splitting_a_drain_does_not_beat_the_daily_cap`, `velocity_pressure_escalates_mid_drain` | +| 6 | A proposal cannot execute twice | status written before the coin moves, `settle` decrements once | `a_payment_cannot_execute_twice` | +| 7 | A removed signer's approval stops counting | `count_with_role` against the live roster at execution | `a_removed_signers_approval_stops_counting` | +| 8 | An approval cannot be duplicated or replayed | one entry per address in a `VecSet`, checked before insert | `an_approval_cannot_be_replayed` | +| 9 | A new recipient cannot skip its activation delay | `executable_at = max(delay, activates_at)`, re-asserted at execution | `a_new_recipient_cannot_skip_activation` | +| 10 | Recovery cannot quietly weaken the vault | `execute_recovery` copies the roles it finds now, leaves the policy untouched, and raises the mode | `recovery_moves_the_roles_and_leaves_the_vault_elevated`, `recovery_cannot_skip_its_delay`, `any_owner_can_cancel_a_recovery` | +| 11 | Balance accounting reconciles | one `Balance` per type in a `Bag`; `balance::split` is the only outgoing path | `a_routine_payment_needs_one_approval_and_no_wait`, `the_daily_bucket_reopens_after_a_day` | +| 12 | The roster always satisfies the policy | `assert_counts_valid` after `finish`, `execute_member` and `execute_recovery` | `counts_must_satisfy_the_policy`, and the roster assertions in the recovery tests | +| 13 | The breaker's latch survives the attempt | `execute_transfer` returns without aborting, so the Lockdown write commits | `crossing_the_loss_envelope_freezes_the_vault_instead_of_paying` | +| 14 | Leaving a raised posture is never unilateral | `propose_mode_relax` needs owners, guardians and the policy-change delay | `leaving_lockdown_takes_owners_a_guardian_and_time`, `owners_alone_cannot_lift_a_freeze` | +| 15 | An automation key cannot authorize itself | `PROPOSER` satisfies only `can_propose` | `an_agent_cannot_approve_its_own_proposal`, `an_agent_cannot_execute`, `a_proposer_can_only_propose` | + +Reentrancy is absent by construction rather than defended against: Move has no dynamic dispatch +into a caller, and the only outgoing value movement is `transfer::public_transfer` of a coin split +after the status has been written. + +## Threats, mapped to what the contract does + +| Threat | What happens | +|---|---| +| One signer compromised | Cannot reach any tier's threshold alone unless `approvals_low` is 1 — and even then the payment is bounded by the routine maximum, the per-transaction cap, the day's remaining allowance and the envelope | +| Enough signers compromised | The high and critical delays are a guardian's veto window; a critical payment needs a guardian; the envelope latches the vault on the first attempt that would cross it | +| An owner quorum weakens the policy | The change waits out `policy_change_delay`, any guardian can veto it, and it cannot be opened at all in Lockdown | +| A drain split into many payments | The day bucket and the envelope count cumulatively; crossing half the day's allowance escalates every further payment | +| A new malicious recipient | Escalated every time while unknown, forced to wait out activation once registered, and vetoable | +| A guardian key compromised | There is no withdrawal path. A recovery waits `recovery_delay` and any owner cancels it. A guardian can freeze, veto and block | +| An automation key compromised | A queue of proposals nobody approved | +| The interface compromised | Every requirement is computed on chain. `preview_transfer` is the same code `execute_transfer` runs, so a preview cannot promise what the vault would refuse, and any interface can reproduce the reads | +| A lost signer | Guardians open a recovery, owners can cancel it, the roles move unchanged, the vault comes out Elevated | +| An emergency | Any owner or guardian enters Lockdown instantly | + +## Known limitations + +State these to anyone evaluating the system. They are design positions, not oversights. + +- **No independent audit yet.** Do not put real value behind Skur until one is complete. +- **Anchored windows, not sliding ones.** A day bucket anchors on its first charge, so up to two + days' allowance can leave across a boundary. The envelope and the per-transaction cap bound it, + and the maximum-loss view says so explicitly rather than quietly assuming the best case. +- **Exposure is per asset.** A vault holding several coin types has several independent exposure + calculations and no portfolio-wide number. Producing one would need an oracle, and a wrong + portfolio number is worse than an honest per-asset one. +- **The breaker latches; it does not refund.** Everything that executed before the trip stays paid. + What it buys is that the trip happens *instead of* the payment that would have crossed the line, + not after it. +- **The envelope basis is the balance when the window opened.** That is deliberate — measuring + against the live balance would let a drain shrink its own denominator — but it means a large + deposit mid-window does not raise the window's allowance until the window rolls. +- **Single-guardian vaults.** With `guardian_threshold = 1`, one guardian key both freezes and (with + owners) unfreezes. The protocol, fund and larger templates ship with two. +- **A shared object serializes.** Every write to a vault goes through consensus on that object, so + one vault has a throughput ceiling. For a payments treasury doing thousands of payments an hour + that is a real constraint, and the answer is several vaults rather than pretending otherwise. +- **No arbitrary contract calls in V1.** Only coin transfers exist. "Unlimited approval" and + "malicious contract interaction" are excluded by construction rather than analysed — which is + also why decoding arbitrary calls is on the roadmap rather than claimed as done. +- **`register_recipient` does not auto-promote.** Paying an unknown address does not make it known; + only governance changes trust. A payment to a never-registered address is escalated every time, + forever, which is intended and occasionally surprising. diff --git a/package.json b/package.json index 50c2b19..d25b730 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,20 @@ "name": "skur", "private": true, "version": "0.1.0", - "description": "Programmable treasury security for onchain businesses.", + "description": "A programmable authorization and treasury security layer for Sui organizations.", "scripts": { - "contracts:build": "cd contracts && forge build", - "contracts:test": "cd contracts && forge test", - "contracts:slither": "cd contracts && slither . --filter-paths \"lib/|test/|script/\" --exclude-informational --exclude-optimization", - "abi": "python3 scripts/export-abi.py", - "web:dev": "cd web && npm run dev", - "web:build": "cd web && npm run build", - "web:test": "cd web && npm test", - "mobile:start": "cd mobile && npx expo start", - "mobile:typecheck": "cd mobile && npx tsc --noEmit", - "test": "npm run contracts:test && npm run web:test && npm run mobile:typecheck" + "move:build": "cd sui && sui move build", + "move:test": "cd sui && sui move test", + "move:publish": "cd sui && scripts/publish.sh", + "sdk:build": "cd sdk && npm run build", + "sdk:test": "cd sdk && npm test", + "server:migrate": "cd server && npm run migrate", + "server:dev": "cd server && npm run dev", + "app:dev": "cd app && npm run dev", + "app:build": "cd app && npm run build", + "test": "npm run move:test && npm run sdk:test", + "typecheck": "cd sdk && npm run typecheck && cd ../server && npm run typecheck && cd ../app && npm run typecheck", + "legacy:contracts:test": "cd contracts && forge test", + "legacy:web:test": "cd web && npm test" } -} +} \ No newline at end of file diff --git a/server/src/notify.ts b/server/src/notify.ts index 1be72f1..de2b070 100644 --- a/server/src/notify.ts +++ b/server/src/notify.ts @@ -1,238 +1,8 @@ import { createHmac } from 'node:crypto'; import type { PoolClient } from 'pg'; -import { - KIND_LABELS, - MODE_LABELS, - Kind, - Mode, - Role, - STATUS_LABELS, - Status, - TIER_LABELS, - Tier, - Trust, - describeReasons, - fmtDuration, - short, - type DecodedEvent, -} from '@skur/sdk'; +import { fmtDuration, type DecodedEvent } from '@skur/sdk'; import { pool } from './db.ts'; - -/** - * Who needs to be told, and why. - * - * The rule is the point of the whole service: an approver should hear about the queue, an - * executor about what is ready, and a guardian about the things only a guardian can stop. Sending - * everything to everyone is the same as sending nothing, because nobody reads the eleventh alert. - * - * `roles` is a bitmask of who the message is for; zero means every member of the vault. - */ -type Rule = { - rule: string; - title: string; - body: string; - severity: 'info' | 'action' | 'alert'; - roles: number; -}; - -const fmtAmount = (v: bigint) => v.toLocaleString('en-US'); - -export function rulesFor({ event }: DecodedEvent): Rule[] { - switch (event.name) { - case 'ProposalOpened': { - const out: Rule[] = []; - const who = event.kind === Kind.TRANSFER ? Role.APPROVER : Role.OWNER; - const label = KIND_LABELS[event.kind] ?? 'Proposal'; - - if (event.kind === Kind.TRANSFER) { - const reasons = describeReasons(event.reasons); - out.push({ - rule: 'transfer.opened', - title: `${TIER_LABELS[event.tier]} payment awaiting approval`, - body: [ - `${fmtAmount(event.amount)} to ${short(event.recipient)}${event.memo ? ` — ${event.memo}` : ''}.`, - `Needs ${event.reqApprovals} approval${event.reqApprovals === 1 ? '' : 's'}${ - event.reqGuardians ? ` and ${event.reqGuardians} guardian confirmation${event.reqGuardians === 1 ? '' : 's'}` : '' - }.`, - reasons.length ? `Scored ${TIER_LABELS[event.tier]} because: ${reasons.join('; ')}.` : '', - ] - .filter(Boolean) - .join(' '), - severity: 'action', - roles: who, - }); - if (event.tier === Tier.CRITICAL) { - out.push({ - rule: 'transfer.critical', - title: 'A critical payment is open and can be vetoed', - body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, at ${(event.exposureBps / 100).toFixed(1)}% of holdings. You can veto it until it executes.`, - severity: 'alert', - roles: Role.GUARDIAN, - }); - } - } else { - out.push({ - rule: 'governance.opened', - title: `${label} awaiting owner approval`, - body: `Opened by ${short(event.proposer)}.`, - severity: 'action', - roles: who, - }); - } - - // The one notification that matters most: somebody is trying to make the vault weaker. - if (event.reductionMask !== 0) { - out.push({ - rule: 'governance.weakening', - title: `${label} would weaken this vault`, - body: `It cannot take effect before ${new Date(event.executableAt).toUTCString()}, and any guardian can veto it until then.`, - severity: 'alert', - roles: Role.GUARDIAN | Role.OWNER, - }); - } - if (event.kind === Kind.RECOVERY) { - out.push({ - rule: 'recovery.opened', - title: 'A signer recovery has been proposed', - body: `Proposed by ${short(event.proposer)}. Any owner can cancel it before it executes.`, - severity: 'alert', - roles: Role.OWNER, - }); - } - return out; - } - - case 'Approved': - // Only the approval that completes the set is worth an interruption. - if (event.approvals < event.reqApprovals) return []; - return [ - { - rule: 'proposal.ready', - title: 'A payment has all its approvals', - body: `Proposal #${event.proposal} is fully approved. It executes once its waiting period has elapsed.`, - severity: 'action', - roles: Role.EXECUTOR, - }, - ]; - - case 'BreakerTripped': - return [ - { - rule: 'breaker.tripped', - title: 'The circuit breaker stopped a payment and froze the vault', - body: `${fmtAmount(event.amount)} would have taken the window past its loss envelope of ${fmtAmount(event.envelopeLimit)} against a basis of ${fmtAmount(event.envelopeBasis)}. The money did not move. The vault is now in Lockdown and needs owners, a guardian and time to reopen.`, - severity: 'alert', - roles: 0, - }, - ]; - - case 'ModeChanged': - if (event.to === Mode.NORMAL) { - return [ - { - rule: 'mode.normal', - title: 'The vault is back to normal', - body: `Lowered from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, - severity: 'info', - roles: 0, - }, - ]; - } - return [ - { - rule: 'mode.raised', - title: `The vault is now in ${MODE_LABELS[event.to]}`, - body: [ - `Raised from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, - event.to === Mode.LOCKDOWN - ? 'Nothing outgoing executes until owners and a guardian agree to reopen it.' - : 'Caps are halved and every payment is escalated one tier.', - describeReasons(event.reasons).join('; '), - ] - .filter(Boolean) - .join(' '), - severity: 'alert', - roles: 0, - }, - ]; - - case 'Settled': - if (event.status === Status.VETOED) { - return [ - { - rule: 'proposal.vetoed', - title: 'A guardian vetoed a proposal', - body: `Proposal #${event.proposal} was vetoed by ${short(event.actor)}. The vault moved to Elevated.`, - severity: 'alert', - roles: 0, - }, - ]; - } - if (event.status === Status.EXPIRED) { - return [ - { - rule: 'proposal.expired', - title: 'A proposal expired before it executed', - body: `Proposal #${event.proposal} (${KIND_LABELS[event.kind]}) ran out of time. Its approvals no longer count for anything.`, - severity: 'info', - roles: Role.APPROVER | Role.OWNER, - }, - ]; - } - return []; - - case 'Executed': - if (event.kind !== Kind.TRANSFER) return []; - return [ - { - rule: 'transfer.executed', - title: 'A payment went out', - body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, executed by ${short(event.executor)}. ${fmtAmount(event.balanceAfter)} remains.`, - severity: 'info', - roles: 0, - }, - ]; - - case 'RecipientTrustChanged': - if (event.to !== Trust.BLOCKED && event.to !== Trust.RESTRICTED) return []; - return [ - { - rule: 'recipient.restricted', - title: `A recipient was ${event.to === Trust.BLOCKED ? 'blocked' : 'restricted'}`, - body: `${short(event.recipient)} was set by ${short(event.actor)}. Payments to it are ${event.to === Trust.BLOCKED ? 'refused' : 'treated as critical'} from now on.`, - severity: 'alert', - roles: 0, - }, - ]; - - case 'Recovered': - return [ - { - rule: 'recovery.executed', - title: 'A signer was replaced', - body: `${short(event.lost)} was replaced by ${short(event.replacement)} with the same roles. The policy was not changed, and the vault is now Elevated.`, - severity: 'alert', - roles: 0, - }, - ]; - - case 'PolicyChanged': - return [ - { - rule: 'policy.changed', - title: `The policy is now at version ${event.version}`, - body: event.reductionMask === 0 - ? 'The change only tightened the vault.' - : 'The change gave up one or more controls. It served its delay and was not vetoed.', - severity: event.reductionMask === 0 ? 'info' : 'alert', - roles: 0, - }, - ]; - - default: - return []; - } -} +import { rulesFor } from './rules.ts'; /** * Queue notifications for an event. The unique constraint on @@ -357,4 +127,4 @@ export function describeWait(executableAt: number, now = Date.now()): string { return `executable in ${fmtDuration(left)}`; } -export { STATUS_LABELS }; + diff --git a/server/src/rules.ts b/server/src/rules.ts new file mode 100644 index 0000000..da69591 --- /dev/null +++ b/server/src/rules.ts @@ -0,0 +1,231 @@ +import { + KIND_LABELS, + MODE_LABELS, + Kind, + Mode, + Role, + Status, + TIER_LABELS, + Tier, + Trust, + describeReasons, + short, + type DecodedEvent, +} from '@skur/sdk'; + +/** + * Who needs to be told, and why. + * + * The rule is the point of the whole service: an approver should hear about the queue, an + * executor about what is ready, and a guardian about the things only a guardian can stop. Sending + * everything to everyone is the same as sending nothing, because nobody reads the eleventh alert. + * + * `roles` is a bitmask of who the message is for; zero means every member of the vault. + */ +type Rule = { + rule: string; + title: string; + body: string; + severity: 'info' | 'action' | 'alert'; + roles: number; +}; + +const fmtAmount = (v: bigint) => v.toLocaleString('en-US'); + +export function rulesFor({ event }: DecodedEvent): Rule[] { + switch (event.name) { + case 'ProposalOpened': { + const out: Rule[] = []; + const who = event.kind === Kind.TRANSFER ? Role.APPROVER : Role.OWNER; + const label = KIND_LABELS[event.kind] ?? 'Proposal'; + + if (event.kind === Kind.TRANSFER) { + const reasons = describeReasons(event.reasons); + out.push({ + rule: 'transfer.opened', + title: `${TIER_LABELS[event.tier]} payment awaiting approval`, + body: [ + `${fmtAmount(event.amount)} to ${short(event.recipient)}${event.memo ? ` — ${event.memo}` : ''}.`, + `Needs ${event.reqApprovals} approval${event.reqApprovals === 1 ? '' : 's'}${ + event.reqGuardians ? ` and ${event.reqGuardians} guardian confirmation${event.reqGuardians === 1 ? '' : 's'}` : '' + }.`, + reasons.length ? `Scored ${TIER_LABELS[event.tier]} because: ${reasons.join('; ')}.` : '', + ] + .filter(Boolean) + .join(' '), + severity: 'action', + roles: who, + }); + if (event.tier === Tier.CRITICAL) { + out.push({ + rule: 'transfer.critical', + title: 'A critical payment is open and can be vetoed', + body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, at ${(event.exposureBps / 100).toFixed(1)}% of holdings. You can veto it until it executes.`, + severity: 'alert', + roles: Role.GUARDIAN, + }); + } + } else { + out.push({ + rule: 'governance.opened', + title: `${label} awaiting owner approval`, + body: `Opened by ${short(event.proposer)}.`, + severity: 'action', + roles: who, + }); + } + + // The one notification that matters most: somebody is trying to make the vault weaker. + if (event.reductionMask !== 0) { + out.push({ + rule: 'governance.weakening', + title: `${label} would weaken this vault`, + body: `It cannot take effect before ${new Date(event.executableAt).toUTCString()}, and any guardian can veto it until then.`, + severity: 'alert', + roles: Role.GUARDIAN | Role.OWNER, + }); + } + if (event.kind === Kind.RECOVERY) { + out.push({ + rule: 'recovery.opened', + title: 'A signer recovery has been proposed', + body: `Proposed by ${short(event.proposer)}. Any owner can cancel it before it executes.`, + severity: 'alert', + roles: Role.OWNER, + }); + } + return out; + } + + case 'Approved': + // Only the approval that completes the set is worth an interruption. + if (event.approvals < event.reqApprovals) return []; + return [ + { + rule: 'proposal.ready', + title: 'A payment has all its approvals', + body: `Proposal #${event.proposal} is fully approved. It executes once its waiting period has elapsed.`, + severity: 'action', + roles: Role.EXECUTOR, + }, + ]; + + case 'BreakerTripped': + return [ + { + rule: 'breaker.tripped', + title: 'The circuit breaker stopped a payment and froze the vault', + body: `${fmtAmount(event.amount)} would have taken the window past its loss envelope of ${fmtAmount(event.envelopeLimit)} against a basis of ${fmtAmount(event.envelopeBasis)}. The money did not move. The vault is now in Lockdown and needs owners, a guardian and time to reopen.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'ModeChanged': + if (event.to === Mode.NORMAL) { + return [ + { + rule: 'mode.normal', + title: 'The vault is back to normal', + body: `Lowered from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, + severity: 'info', + roles: 0, + }, + ]; + } + return [ + { + rule: 'mode.raised', + title: `The vault is now in ${MODE_LABELS[event.to]}`, + body: [ + `Raised from ${MODE_LABELS[event.from]} by ${short(event.actor)}.`, + event.to === Mode.LOCKDOWN + ? 'Nothing outgoing executes until owners and a guardian agree to reopen it.' + : 'Caps are halved and every payment is escalated one tier.', + describeReasons(event.reasons).join('; '), + ] + .filter(Boolean) + .join(' '), + severity: 'alert', + roles: 0, + }, + ]; + + case 'Settled': + if (event.status === Status.VETOED) { + return [ + { + rule: 'proposal.vetoed', + title: 'A guardian vetoed a proposal', + body: `Proposal #${event.proposal} was vetoed by ${short(event.actor)}. The vault moved to Elevated.`, + severity: 'alert', + roles: 0, + }, + ]; + } + if (event.status === Status.EXPIRED) { + return [ + { + rule: 'proposal.expired', + title: 'A proposal expired before it executed', + body: `Proposal #${event.proposal} (${KIND_LABELS[event.kind]}) ran out of time. Its approvals no longer count for anything.`, + severity: 'info', + roles: Role.APPROVER | Role.OWNER, + }, + ]; + } + return []; + + case 'Executed': + if (event.kind !== Kind.TRANSFER) return []; + return [ + { + rule: 'transfer.executed', + title: 'A payment went out', + body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, executed by ${short(event.executor)}. ${fmtAmount(event.balanceAfter)} remains.`, + severity: 'info', + roles: 0, + }, + ]; + + case 'RecipientTrustChanged': + if (event.to !== Trust.BLOCKED && event.to !== Trust.RESTRICTED) return []; + return [ + { + rule: 'recipient.restricted', + title: `A recipient was ${event.to === Trust.BLOCKED ? 'blocked' : 'restricted'}`, + body: `${short(event.recipient)} was set by ${short(event.actor)}. Payments to it are ${event.to === Trust.BLOCKED ? 'refused' : 'treated as critical'} from now on.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'Recovered': + return [ + { + rule: 'recovery.executed', + title: 'A signer was replaced', + body: `${short(event.lost)} was replaced by ${short(event.replacement)} with the same roles. The policy was not changed, and the vault is now Elevated.`, + severity: 'alert', + roles: 0, + }, + ]; + + case 'PolicyChanged': + return [ + { + rule: 'policy.changed', + title: `The policy is now at version ${event.version}`, + body: event.reductionMask === 0 + ? 'The change only tightened the vault.' + : 'The change gave up one or more controls. It served its delay and was not vetoed.', + severity: event.reductionMask === 0 ? 'info' : 'alert', + roles: 0, + }, + ]; + + default: + return []; + } +} + diff --git a/server/test/notify.test.ts b/server/test/notify.test.ts new file mode 100644 index 0000000..2422680 --- /dev/null +++ b/server/test/notify.test.ts @@ -0,0 +1,201 @@ +import { describe, expect, it } from 'vitest'; +import { Kind, Mode, Role, Status, Tier, Trust, type DecodedEvent } from '@skur/sdk'; +import { rulesFor } from '../src/rules.ts'; + +/** + * The rules decide who gets interrupted. Getting this wrong in either direction is a real failure: + * too little and a guardian misses the one thing only they can stop; too much and nobody reads the + * eleventh alert. + */ +const position = { transactionDigest: 'DIGEST', eventIndex: 0 }; + +function wrap(event: DecodedEvent['event']): DecodedEvent { + return { event, position }; +} + +const openedBase = { + name: 'ProposalOpened' as const, + vault: '0xV', + proposal: 7n, + kind: Kind.TRANSFER, + proposer: '0xP', + asset: '0x2::sui::SUI', + amount: 1_000n, + recipient: '0xR', + tier: Tier.LOW, + reasons: 0, + exposureBps: 10, + reqApprovals: 1, + reqGuardians: 0, + executableAt: 1, + expiresAt: 2, + reductionMask: 0, + memo: 'invoice', + at: 1, +}; + +describe('who hears about a new payment', () => { + it('tells approvers, and nobody else', () => { + const rules = rulesFor(wrap(openedBase)); + expect(rules).toHaveLength(1); + expect(rules[0].rule).toBe('transfer.opened'); + expect(rules[0].roles).toBe(Role.APPROVER); + expect(rules[0].severity).toBe('action'); + }); + + it('also tells guardians when the payment is critical, because only they can veto it', () => { + const rules = rulesFor(wrap({ ...openedBase, tier: Tier.CRITICAL, reqGuardians: 1 })); + const guardian = rules.find((r) => r.rule === 'transfer.critical'); + expect(guardian).toBeDefined(); + expect(guardian!.roles).toBe(Role.GUARDIAN); + expect(guardian!.severity).toBe('alert'); + }); + + it('explains why the tier landed where it did', () => { + const rules = rulesFor( + wrap({ ...openedBase, tier: Tier.HIGH, reasons: 1 | 256, reqApprovals: 2 }), + ); + expect(rules[0].body).toMatch(/never paid this address/); + expect(rules[0].body).toMatch(/2 approvals/); + }); + + it('routes a governance proposal to owners instead', () => { + const rules = rulesFor(wrap({ ...openedBase, kind: Kind.POLICY_UPDATE })); + expect(rules[0].rule).toBe('governance.opened'); + expect(rules[0].roles).toBe(Role.OWNER); + }); + + it('raises an alert to guardians and owners when a change would weaken the vault', () => { + const rules = rulesFor( + wrap({ ...openedBase, kind: Kind.POLICY_UPDATE, reductionMask: 1 }), + ); + const weakening = rules.find((r) => r.rule === 'governance.weakening'); + expect(weakening).toBeDefined(); + expect(weakening!.roles).toBe(Role.GUARDIAN | Role.OWNER); + expect(weakening!.severity).toBe('alert'); + expect(weakening!.body).toMatch(/veto/); + }); + + it('tells owners about a recovery, because any one of them can cancel it', () => { + const rules = rulesFor(wrap({ ...openedBase, kind: Kind.RECOVERY, reductionMask: 1 })); + expect(rules.some((r) => r.rule === 'recovery.opened' && r.roles === Role.OWNER)).toBe(true); + }); +}); + +describe('approvals', () => { + it('says nothing until the set is complete', () => { + expect( + rulesFor( + wrap({ + name: 'Approved', + vault: '0xV', + proposal: 7n, + approver: '0xA', + approvals: 1, + reqApprovals: 3, + at: 1, + }), + ), + ).toEqual([]); + }); + + it('tells executors once it is complete', () => { + const rules = rulesFor( + wrap({ + name: 'Approved', + vault: '0xV', + proposal: 7n, + approver: '0xA', + approvals: 3, + reqApprovals: 3, + at: 1, + }), + ); + expect(rules).toHaveLength(1); + expect(rules[0].roles).toBe(Role.EXECUTOR); + }); +}); + +describe('the things everyone hears about', () => { + it('tells the whole vault when the breaker trips, and says the money did not move', () => { + const rules = rulesFor( + wrap({ + name: 'BreakerTripped', + vault: '0xV', + proposal: 9n, + asset: '0x2::sui::SUI', + amount: 200_000n, + envelopeSpent: 0n, + envelopeLimit: 100_000n, + envelopeBasis: 1_000_000n, + at: 1, + }), + ); + expect(rules[0].roles).toBe(0); + expect(rules[0].severity).toBe('alert'); + expect(rules[0].body).toMatch(/did not move/); + expect(rules[0].body).toMatch(/Lockdown/); + }); + + it('distinguishes a freeze from a thaw', () => { + const raised = rulesFor( + wrap({ name: 'ModeChanged', vault: '0xV', from: Mode.NORMAL, to: Mode.LOCKDOWN, actor: '0xG', reasons: 0, at: 1 }), + ); + expect(raised[0].severity).toBe('alert'); + expect(raised[0].body).toMatch(/until owners and a guardian/); + + const lowered = rulesFor( + wrap({ name: 'ModeChanged', vault: '0xV', from: Mode.ELEVATED, to: Mode.NORMAL, actor: '0xO', reasons: 0, at: 1 }), + ); + expect(lowered[0].severity).toBe('info'); + }); + + it('alerts on a veto and merely notes an expiry', () => { + const vetoed = rulesFor( + wrap({ name: 'Settled', vault: '0xV', proposal: 1n, kind: Kind.TRANSFER, status: Status.VETOED, actor: '0xG', at: 1 }), + ); + expect(vetoed[0].severity).toBe('alert'); + + const expired = rulesFor( + wrap({ name: 'Settled', vault: '0xV', proposal: 1n, kind: Kind.TRANSFER, status: Status.EXPIRED, actor: '0xA', at: 1 }), + ); + expect(expired[0].severity).toBe('info'); + + const cancelled = rulesFor( + wrap({ name: 'Settled', vault: '0xV', proposal: 1n, kind: Kind.TRANSFER, status: Status.CANCELLED, actor: '0xA', at: 1 }), + ); + expect(cancelled).toEqual([]); + }); + + it('alerts when a recipient is blocked and stays quiet when one is merely verified', () => { + const blocked = rulesFor( + wrap({ name: 'RecipientTrustChanged', vault: '0xV', proposal: 0n, recipient: '0xR', from: Trust.NEW, to: Trust.BLOCKED, actor: '0xG', at: 1 }), + ); + expect(blocked[0].severity).toBe('alert'); + + const verified = rulesFor( + wrap({ name: 'RecipientTrustChanged', vault: '0xV', proposal: 1n, recipient: '0xR', from: Trust.NEW, to: Trust.VERIFIED, actor: '0xO', at: 1 }), + ); + expect(verified).toEqual([]); + }); + + it('marks a tightening policy change as information and a weakening as an alert', () => { + const tightened = rulesFor( + wrap({ name: 'PolicyChanged', vault: '0xV', proposal: 1n, version: 2n, reductionMask: 0, at: 1 }), + ); + expect(tightened[0].severity).toBe('info'); + + const weakened = rulesFor( + wrap({ name: 'PolicyChanged', vault: '0xV', proposal: 1n, version: 3n, reductionMask: 64, at: 1 }), + ); + expect(weakened[0].severity).toBe('alert'); + }); + + it('does not notify on a deposit, because incoming money is not an event anyone must act on', () => { + expect( + rulesFor( + wrap({ name: 'Deposited', vault: '0xV', asset: '0x2::sui::SUI', amount: 1n, balance: 1n, from: '0xX', at: 1 }), + ), + ).toEqual([]); + }); +}); From 3061c32092c4a5f0f6de32fd2ec66082b426939f Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 09:46:34 +0100 Subject: [PATCH 16/44] ci(sui): build and test the Move package, the SDK, the backend and the interface Pins the Sui toolchain version, because the Move compiler and the bundled framework move together and a job that silently upgrades either cannot reproduce a failure. Also applies the migrations against a real Postgres: a migration that does not apply to an empty database is one nobody can deploy. --- .github/workflows/sui.yml | 125 +++++++++++++++++++++++++++++++++++++ sdk/dist/bcs.d.ts | 9 --- sdk/dist/bcs.d.ts.map | 2 +- sdk/dist/bcs.js | 4 -- sdk/dist/bcs.js.map | 2 +- sdk/dist/errors.d.ts.map | 2 +- sdk/dist/errors.js | 2 - sdk/dist/errors.js.map | 2 +- sdk/dist/vault.d.ts.map | 2 +- sdk/dist/vault.js | 18 +++--- sdk/dist/vault.js.map | 2 +- sdk/src/bcs.ts | 8 --- sdk/src/errors.ts | 2 - sdk/src/vault.ts | 18 +++--- sui/deployments/README.md | 22 +++++++ sui/sources/vault.move | 19 +++--- sui/tests/vault_tests.move | 17 ++++- 17 files changed, 195 insertions(+), 61 deletions(-) create mode 100644 .github/workflows/sui.yml create mode 100644 sui/deployments/README.md diff --git a/.github/workflows/sui.yml b/.github/workflows/sui.yml new file mode 100644 index 0000000..800ecfd --- /dev/null +++ b/.github/workflows/sui.yml @@ -0,0 +1,125 @@ +name: Sui + +permissions: {} + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +env: + # Pin the toolchain: the Move compiler and the bundled framework move together, and a job that + # silently upgrades either is a job that cannot reproduce a failure. + SUI_VERSION: mainnet-v1.80.1 + +jobs: + move: + name: Move + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Cache the Sui CLI + id: cache-sui + uses: actions/cache@v4 + with: + path: ~/.local/bin/sui + key: sui-${{ env.SUI_VERSION }}-ubuntu + + - name: Install the Sui CLI + if: steps.cache-sui.outputs.cache-hit != 'true' + run: | + mkdir -p ~/.local/bin + curl -fsSL --retry 5 \ + "https://github.com/MystenLabs/sui/releases/download/${SUI_VERSION}/sui-${SUI_VERSION}-ubuntu-x86_64.tgz" \ + -o /tmp/sui.tgz + tar -xzf /tmp/sui.tgz -C /tmp + find /tmp -maxdepth 3 -type f -name sui -perm -u+x -exec cp {} ~/.local/bin/sui \; + chmod +x ~/.local/bin/sui + + - name: Build + run: ~/.local/bin/sui move build --path sui + + - name: Test + run: ~/.local/bin/sui move test --path sui + + typescript: + name: TypeScript + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: actions/setup-node@v4 + with: + node-version: 24 + + - name: Build and test the SDK + working-directory: sdk + run: | + npm install --no-audit --no-fund + npm run typecheck + npm run build + npm test + + - name: Test the backend + working-directory: server + env: + # The rule tests are pure; nothing here touches a database. + DATABASE_URL: postgres://localhost:5432/unused + SKUR_PACKAGE_ID: '0x0' + run: | + npm install --no-audit --no-fund + npm run typecheck + npm test + + - name: Typecheck the interface + working-directory: app + run: | + npm install --no-audit --no-fund + npm run typecheck + + migrations: + name: Migrations + runs-on: ubuntu-latest + permissions: + contents: read + services: + postgres: + image: postgres:17 + env: + # No password, rather than a hardcoded one. This container exists for the length of one + # job, is reachable only from it, and is thrown away afterwards — so a credential here + # protects nothing and is one more string to leak. `trust` removes it entirely. + POSTGRES_HOST_AUTH_METHOD: trust + POSTGRES_DB: skur + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + + - uses: actions/setup-node@v4 + with: + node-version: 24 + + # A migration that does not apply to an empty database is a migration nobody can deploy. + - name: Apply the migrations + working-directory: server + env: + DATABASE_URL: postgres://postgres@localhost:5432/skur + SKUR_PACKAGE_ID: '0x0' + run: | + npm install --no-audit --no-fund + npm run migrate diff --git a/sdk/dist/bcs.d.ts b/sdk/dist/bcs.d.ts index 48a8af2..75561f3 100644 --- a/sdk/dist/bcs.d.ts +++ b/sdk/dist/bcs.d.ts @@ -190,14 +190,5 @@ export declare const VaultBcs: import("@mysten/sui/bcs").BcsStruct<{ export declare const BalanceBcs: import("@mysten/sui/bcs").BcsStruct<{ value: import("@mysten/sui/bcs").BcsType; }, string>; -/** A `Table` entry is stored as `Field` under the table's own id. */ -export declare function fieldBcs(key: ReturnType, value: { - parse: (bytes: Uint8Array) => V; -}): { - key: import("@mysten/sui/bcs").BcsType; - value: { - parse: (bytes: Uint8Array) => V; - }; -}; export { bcs }; //# sourceMappingURL=bcs.d.ts.map \ No newline at end of file diff --git a/sdk/dist/bcs.d.ts.map b/sdk/dist/bcs.d.ts.map index 9efdca3..bf7948e 100644 --- a/sdk/dist/bcs.d.ts.map +++ b/sdk/dist/bcs.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"bcs.d.ts","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwBtC,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;UAkBpB,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;UAMzB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;UAMtB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;UAOvB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BtB,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoBnB,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,UAAU;;UAA8C,CAAC;AAEtE,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,GAAG,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,EAC/B,KAAK,EAAE;IAAE,KAAK,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC,CAAA;CAAE;;;eAA1B,CAAC,KAAK,EAAE,UAAU,KAAK,CAAC;;EAGzC;AAED,OAAO,EAAE,GAAG,EAAE,CAAC"} \ No newline at end of file +{"version":3,"file":"bcs.d.ts","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwBtC,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;UAkBpB,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;UAMzB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;UAMtB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;UAOvB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BtB,CAAC;AAEH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAoBnB,CAAC;AAEH,8DAA8D;AAC9D,eAAO,MAAM,UAAU;;UAA8C,CAAC;AAEtE,OAAO,EAAE,GAAG,EAAE,CAAC"} \ No newline at end of file diff --git a/sdk/dist/bcs.js b/sdk/dist/bcs.js index 2b7edf0..41d002e 100644 --- a/sdk/dist/bcs.js +++ b/sdk/dist/bcs.js @@ -109,9 +109,5 @@ export const VaultBcs = bcs.struct('Vault', { }); /** `sui::balance::Balance` is a single u64 on the wire. */ export const BalanceBcs = bcs.struct('Balance', { value: bcs.u64() }); -/** A `Table` entry is stored as `Field` under the table's own id. */ -export function fieldBcs(key, value) { - return { key, value }; -} export { bcs }; //# sourceMappingURL=bcs.js.map \ No newline at end of file diff --git a/sdk/dist/bcs.js.map b/sdk/dist/bcs.js.map index d4a74cb..df6cd4d 100644 --- a/sdk/dist/bcs.js.map +++ b/sdk/dist/bcs.js.map @@ -1 +1 @@ -{"version":3,"file":"bcs.js","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"bcs.js","sourceRoot":"","sources":["../src/bcs.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/errors.d.ts.map b/sdk/dist/errors.d.ts.map index 42ca0bf..f36d162 100644 --- a/sdk/dist/errors.d.ts.map +++ b/sdk/dist/errors.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBhD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyC/C,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAKvF;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAStD"} \ No newline at end of file +{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBhD,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuC/C,CAAC;AAEF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAKvF;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAStD"} \ No newline at end of file diff --git a/sdk/dist/errors.js b/sdk/dist/errors.js index 5da640b..7cf2111 100644 --- a/sdk/dist/errors.js +++ b/sdk/dist/errors.js @@ -55,12 +55,10 @@ export const VAULT_ERRORS = { 124: 'The amount must be greater than zero.', 125: 'That proposal is not one a guardian can veto.', 126: 'That address is already registered.', - 127: 'That recipient is not registered.', 128: 'That is not a valid trust level.', 129: 'That is not a valid security mode.', 130: 'That is not a relaxation of the current mode.', 131: 'Only the proposer or an owner can cancel.', - 132: 'A vault cannot be left without an owner.', 133: 'A guardian cannot hold a treasury role.', 134: 'That asset was already configured.', 135: 'The member list and the role list are different lengths.', diff --git a/sdk/dist/errors.js.map b/sdk/dist/errors.js.map index 5e4bb9e..20f40b0 100644 --- a/sdk/dist/errors.js.map +++ b/sdk/dist/errors.js.map @@ -1 +1 @@ -{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/dist/vault.d.ts.map b/sdk/dist/vault.d.ts.map index 0cc8622..1b5e92b 100644 --- a/sdk/dist/vault.d.ts.map +++ b/sdk/dist/vault.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAW5D,OAAO,EAML,KAAK,WAAW,EAEhB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAkEpB,wBAAsB,UAAU,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAkCvB;AA0BD,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAM/C;AAUD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,EAAE,CAAC,CAKtD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAGlD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,EAAE,CAAC,CAYrD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CAW5B;AAkCD,kCAAkC;AAClC,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAU1B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,KAAK,SAAK,GACT,OAAO,CAAC,QAAQ,EAAE,CAAC,CAMrB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,eAAe,CAAC,CAoB1B;AAED,mGAAmG;AACnG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAChG,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,CAAC;AAEF,wBAAsB,cAAc,CAClC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,EACf,aAAa,SAAK,GACjB,OAAO,CAAC,SAAS,CAAC,CAwBpB"} \ No newline at end of file +{"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAW5D,OAAO,EAML,KAAK,WAAW,EAEhB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAkEpB,wBAAsB,UAAU,CAC9B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CAkCvB;AA0BD,wBAAsB,YAAY,CAChC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAM/C;AAUD,wBAAsB,WAAW,CAC/B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,EAAE,CAAC,CAKtD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAGlD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,EAAE,CAAC,CAYrD;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CAW5B;AAkCD,kCAAkC;AAClC,wBAAsB,aAAa,CACjC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAU1B;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,YAAY,EACnB,KAAK,SAAK,GACT,OAAO,CAAC,QAAQ,EAAE,CAAC,CAMrB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IACL,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC,eAAe,CAAC,CAsB1B;AAED,mGAAmG;AACnG,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;KAAE,EAAE,CAAC;IAChG,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB,CAAC;AAEF,wBAAsB,cAAc,CAClC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,MAAM,EACf,aAAa,SAAK,GACjB,OAAO,CAAC,SAAS,CAAC,CAwBpB"} \ No newline at end of file diff --git a/sdk/dist/vault.js b/sdk/dist/vault.js index 0121293..f96cef0 100644 --- a/sdk/dist/vault.js +++ b/sdk/dist/vault.js @@ -227,22 +227,24 @@ export async function fetchRecentProposals(client, vault, count = 25) { export async function previewTransfer(client, input) { const tx = previewTransferTx(input.packageId, input); tx.setSender(input.sender); + // `commandResults` carries each command's return values as BCS bytes. The transaction is never + // signed or submitted — this is a read dressed as a transaction, which is the only way to call a + // Move function and get its return values back. const result = await client.core.simulateTransaction({ - transaction: await tx.build({ client }), + transaction: tx, include: { commandResults: true }, }); const values = result.commandResults?.[0]?.returnValues; if (!values || values.length < 6) { throw new Error('preview_transfer returned no values; is the package id correct?'); } - const at = (i) => values[i].bcs ?? values[i]; return { - tier: num(bcs.u8().parse(at(0))), - reasons: num(bcs.u16().parse(at(1))), - exposureBps: num(bcs.u64().parse(at(2))), - reqApprovals: num(bcs.u8().parse(at(3))), - reqGuardians: num(bcs.u8().parse(at(4))), - delay: num(bcs.u64().parse(at(5))), + tier: num(bcs.u8().parse(values[0].bcs)), + reasons: num(bcs.u16().parse(values[1].bcs)), + exposureBps: num(bcs.u64().parse(values[2].bcs)), + reqApprovals: num(bcs.u8().parse(values[3].bcs)), + reqGuardians: num(bcs.u8().parse(values[4].bcs)), + delay: num(bcs.u64().parse(values[5].bcs)), }; } export async function fetchVaultView(client, vaultId, proposalCount = 25) { diff --git a/sdk/dist/vault.js.map b/sdk/dist/vault.js.map index ad118ae..8877a99 100644 --- a/sdk/dist/vault.js.map +++ b/sdk/dist/vault.js.map @@ -1 +1 @@ -{"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"vault.js","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/sdk/src/bcs.ts b/sdk/src/bcs.ts index da65b11..1149d25 100644 --- a/sdk/src/bcs.ts +++ b/sdk/src/bcs.ts @@ -122,12 +122,4 @@ export const VaultBcs = bcs.struct('Vault', { /** `sui::balance::Balance` is a single u64 on the wire. */ export const BalanceBcs = bcs.struct('Balance', { value: bcs.u64() }); -/** A `Table` entry is stored as `Field` under the table's own id. */ -export function fieldBcs( - key: ReturnType, - value: { parse: (bytes: Uint8Array) => V }, -) { - return { key, value }; -} - export { bcs }; diff --git a/sdk/src/errors.ts b/sdk/src/errors.ts index 752b65a..cff95ba 100644 --- a/sdk/src/errors.ts +++ b/sdk/src/errors.ts @@ -56,12 +56,10 @@ export const VAULT_ERRORS: Record = { 124: 'The amount must be greater than zero.', 125: 'That proposal is not one a guardian can veto.', 126: 'That address is already registered.', - 127: 'That recipient is not registered.', 128: 'That is not a valid trust level.', 129: 'That is not a valid security mode.', 130: 'That is not a relaxation of the current mode.', 131: 'Only the proposer or an owner can cancel.', - 132: 'A vault cannot be left without an owner.', 133: 'A guardian cannot hold a treasury role.', 134: 'That asset was already configured.', 135: 'The member list and the role list are different lengths.', diff --git a/sdk/src/vault.ts b/sdk/src/vault.ts index ca4417e..9f57fac 100644 --- a/sdk/src/vault.ts +++ b/sdk/src/vault.ts @@ -305,22 +305,24 @@ export async function previewTransfer( ): Promise { const tx = previewTransferTx(input.packageId, input); tx.setSender(input.sender); + // `commandResults` carries each command's return values as BCS bytes. The transaction is never + // signed or submitted — this is a read dressed as a transaction, which is the only way to call a + // Move function and get its return values back. const result = await client.core.simulateTransaction({ - transaction: await tx.build({ client }), + transaction: tx, include: { commandResults: true }, }); const values = result.commandResults?.[0]?.returnValues; if (!values || values.length < 6) { throw new Error('preview_transfer returned no values; is the package id correct?'); } - const at = (i: number) => values[i].bcs ?? values[i]; return { - tier: num(bcs.u8().parse(at(0) as Uint8Array)) as Tier, - reasons: num(bcs.u16().parse(at(1) as Uint8Array)), - exposureBps: num(bcs.u64().parse(at(2) as Uint8Array)), - reqApprovals: num(bcs.u8().parse(at(3) as Uint8Array)), - reqGuardians: num(bcs.u8().parse(at(4) as Uint8Array)), - delay: num(bcs.u64().parse(at(5) as Uint8Array)), + tier: num(bcs.u8().parse(values[0].bcs)) as Tier, + reasons: num(bcs.u16().parse(values[1].bcs)), + exposureBps: num(bcs.u64().parse(values[2].bcs)), + reqApprovals: num(bcs.u8().parse(values[3].bcs)), + reqGuardians: num(bcs.u8().parse(values[4].bcs)), + delay: num(bcs.u64().parse(values[5].bcs)), }; } diff --git a/sui/deployments/README.md b/sui/deployments/README.md new file mode 100644 index 0000000..e26fb54 --- /dev/null +++ b/sui/deployments/README.md @@ -0,0 +1,22 @@ +# Deployments + +One file per network, written by [`../scripts/publish.sh`](../scripts/publish.sh). This is the only +place a package address is configured: the SDK, the interface and the backend all read it from here +or from an environment variable that overrides it. + +```json +{ + "network": "testnet", + "packageId": "0x…", + "publishedAtDigest": "…", + "deployer": "0x…", + "publishedAt": "2026-10-05T00:00:00Z", + "vaults": [{ "id": "0x…", "name": "Skur Demo Treasury" }] +} +``` + +`vaults` is for demonstration vaults worth linking to from the docs. It is not a registry: a vault +is a shared object and works whether or not it is listed here. + +Run `npm run sync-deployments` in [`../../app`](../../app) after publishing, to copy these into the +interface's bundle. diff --git a/sui/sources/vault.move b/sui/sources/vault.move index 9907f66..338d4d9 100644 --- a/sui/sources/vault.move +++ b/sui/sources/vault.move @@ -49,12 +49,10 @@ const E_INSUFFICIENT_BALANCE: u64 = 123; const E_ZERO_AMOUNT: u64 = 124; const E_NOT_VETOABLE: u64 = 125; const E_ALREADY_REGISTERED: u64 = 126; -const E_UNKNOWN_RECIPIENT: u64 = 127; const E_INVALID_TRUST: u64 = 128; const E_INVALID_MODE: u64 = 129; const E_NOT_A_RELAXATION: u64 = 130; const E_NOT_PROPOSER_OR_OWNER: u64 = 131; -const E_LAST_OWNER: u64 = 132; const E_GUARDIAN_HAS_TREASURY_ROLE: u64 = 133; const E_ASSET_ALREADY_SET_UP: u64 = 134; const E_ROSTER_MISMATCH: u64 = 135; @@ -430,7 +428,6 @@ public fun finish(s: VaultSetup, ctx: &TxContext) { // ---------------------------------------------------------------- roster bookkeeping fun tally(v: &mut Vault, bits: u8, add: bool) { - let d = if (add) 1 else 0; if (types::has_role(bits, types::role_owner())) { v.owner_count = if (add) v.owner_count + 1 else v.owner_count - 1; }; @@ -443,7 +440,6 @@ fun tally(v: &mut Vault, bits: u8, add: bool) { if (types::has_role(bits, types::role_guardian())) { v.guardian_count = if (add) v.guardian_count + 1 else v.guardian_count - 1; }; - let _ = d; } fun roles_of(v: &Vault, who: address): u8 { @@ -1532,20 +1528,19 @@ public fun propose_mode_relax( public fun execute_mode_relax(v: &mut Vault, id: u64, clock: &Clock, ctx: &TxContext) { let now = clock::timestamp_ms(clock); - let (to, confirm_keys) = { + let (to, approval_keys, confirm_keys) = { let p = v.proposals.borrow(id); assert!(p.kind == types::kind_mode_relax(), E_WRONG_KIND); assert!(p.status == types::status_pending(), E_NOT_PENDING); assert!(now < p.expires_at, E_EXPIRED); assert!(now >= p.executable_at, E_TOO_EARLY); - let keys = *p.approvals.keys(); - assert!( - count_with_role(v, &keys, types::role_owner()) - >= (v.policy.governance_threshold() as u64), - E_NOT_ENOUGH_APPROVALS, - ); - (p.target_mode, *p.confirmations.keys()) + (p.target_mode, *p.approvals.keys(), *p.confirmations.keys()) }; + assert!( + count_with_role(v, &approval_keys, types::role_owner()) + >= (v.policy.governance_threshold() as u64), + E_NOT_ENOUGH_APPROVALS, + ); assert!( count_with_role(v, &confirm_keys, types::role_guardian()) >= (v.policy.guardian_threshold() as u64), diff --git a/sui/tests/vault_tests.move b/sui/tests/vault_tests.move index c84fa40..1bba753 100644 --- a/sui/tests/vault_tests.move +++ b/sui/tests/vault_tests.move @@ -568,6 +568,7 @@ fun leaving_lockdown_takes_owners_a_guardian_and_time() { ts::end(sc); } +/// Every owner can agree and the freeze still holds: a guardian has to sign it off. #[test] #[expected_failure(abort_code = E_NOT_ENOUGH_GUARDIANS)] fun owners_alone_cannot_lift_a_freeze() { @@ -579,12 +580,24 @@ fun owners_alone_cannot_lift_a_freeze() { ts::next_tx(&mut sc, GUARD); let mut v = ts::take_shared(&sc); vault::raise_mode(&mut v, types::mode_lockdown(), 0, &clock, sc.ctx()); - let rid = vault::propose_mode_relax(&mut v, types::mode_normal(), &clock, sc.ctx()); ts::return_shared(v); + ts::next_tx(&mut sc, OWNER); + let mut v2 = ts::take_shared(&sc); + let rid = vault::propose_mode_relax(&mut v2, types::mode_normal(), &clock, sc.ctx()); + ts::return_shared(v2); + + approve(&mut sc, OWNER, rid, &clock); + approve(&mut sc, OWNER2, rid, &clock); + + tick(&mut clock, 2 * DAY + HOUR); + ts::next_tx(&mut sc, OWNER); + let mut v3 = ts::take_shared(&sc); + vault::execute_mode_relax(&mut v3, rid, &clock, sc.ctx()); + ts::return_shared(v3); + clock::destroy_for_testing(clock); ts::end(sc); - let _ = rid; } // ---------------------------------------------------------------- guardians From 0654d45755bc71aba405729d403aacfea1972469 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:35:52 +0100 Subject: [PATCH 17/44] docs(sui): a reading order for the Move package, and fewer toolchain assumptions The Bag reads and the string literals now use module-qualified calls instead of method sugar whose availability moves between toolchain versions. Same behaviour, one less thing to be surprised by on a different CLI. --- app/src/app/VaultApp.tsx | 3 -- app/src/components/Overview.tsx | 3 +- app/src/components/Send.tsx | 3 +- sui/README.md | 77 +++++++++++++++++++++++++++++++++ sui/sources/vault.move | 32 +++++++------- 5 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 sui/README.md diff --git a/app/src/app/VaultApp.tsx b/app/src/app/VaultApp.tsx index b8d116e..4426711 100644 --- a/app/src/app/VaultApp.tsx +++ b/app/src/app/VaultApp.tsx @@ -5,7 +5,6 @@ import { useState } from 'react'; import { Role, hasRole } from '@skur/sdk'; import { CONFIGURED } from '@/config'; import { useVaultTx, useVaultView } from '@/hooks/useVault'; -import { CreateVault } from '@/components/CreateVault'; import { Overview } from '@/components/Overview'; import { People } from '@/components/People'; import { PolicyPanel } from '@/components/PolicyPanel'; @@ -87,5 +86,3 @@ function RoleBadge({ roles }: { roles: number }) { if (hasRole(roles, Role.PROPOSER)) names.push('proposer'); return {names.join(' · ')}; } - -export { CreateVault }; diff --git a/app/src/components/Overview.tsx b/app/src/components/Overview.tsx index 13e58a1..6f64fec 100644 --- a/app/src/components/Overview.tsx +++ b/app/src/components/Overview.tsx @@ -2,7 +2,6 @@ import { Mode, - Reason, Status, describeReasons, fmtAmount, @@ -10,7 +9,7 @@ import { type VaultView, } from '@skur/sdk'; import { EXPLORER } from '@/config'; -import { Addr, Amount, ModePill, Notice, coinDecimals, coinSymbol } from './ui'; +import { Addr, ModePill, Notice, coinDecimals, coinSymbol } from './ui'; /** * What the vault is right now: its posture, what it holds, how much of each window is used, and diff --git a/app/src/components/Send.tsx b/app/src/components/Send.tsx index 4bbafb1..c5f567e 100644 --- a/app/src/components/Send.tsx +++ b/app/src/components/Send.tsx @@ -3,7 +3,6 @@ import { useCurrentAccount } from '@mysten/dapp-kit-react'; import { useMemo, useState } from 'react'; import { - Role, Trust, canPropose, describeReasons, @@ -13,7 +12,7 @@ import { tx as build, type VaultView, } from '@skur/sdk'; -import { API_URL, PACKAGE_ID } from '@/config'; +import { PACKAGE_ID } from '@/config'; import { useTransferPreview, type TxState } from '@/hooks/useVault'; import { Addr, Amount, Countdown, Notice, TierPill, TrustPill, coinDecimals, coinSymbol } from './ui'; diff --git a/sui/README.md b/sui/README.md new file mode 100644 index 0000000..cddbaea --- /dev/null +++ b/sui/README.md @@ -0,0 +1,77 @@ +# The Skur Move package + +Four modules. The first three are pure and the fourth holds the state, which is deliberate: the +rules can be read, tested and argued about without reasoning about the object they act on. + +| Module | Lines | What it is | +|---|---|---| +| [`types.move`](sources/types.move) | ~145 | The vocabulary: role bits, risk tiers, trust levels, security modes, proposal kinds, statuses and the reason bitmask. No state, no logic beyond `roles_valid` | +| [`policy.move`](sources/policy.move) | ~340 | The seventeen policy fields, the per-asset limits, every validation rule, and `reductions` — the comparison that decides whether a change weakens the vault | +| [`risk.move`](sources/risk.move) | ~170 | The classifier. Five signals in, a tier, a reason mask and an exposure out. Pure and total | +| [`vault.move`](sources/vault.move) | ~1,630 | The shared object, the proposal lifecycle and every enforcement point | + +## Reading order, for a review + +1. **`risk::classify`** — five signals, each able to raise the tier and none able to lower it. If + this is wrong, every number the product shows is wrong. +2. **`policy::reductions`** — the policy firewall. The interesting cases are the ones where a + number going *down* is a loosening: `threshold_loosens` exists because a threshold of zero means + "disabled", so moving to zero is the loosest move available and moving away from it can only + tighten. +3. **`vault::execute_transfer`** — the last gate, and the function that matters most. Everything is + re-evaluated against live state, the stricter of the pinned and live requirements applies, and + the circuit breaker is checked last and charged in the same step as the payment. +4. **`vault::begin` / `finish`** — creation as a hot potato. `VaultSetup` has no abilities, so the + transaction that starts a vault must also finish it. + +## The one unusual control flow + +`execute_transfer` does not abort when the loss envelope would be crossed. It marks the proposal +`BLOCKED`, sets the vault to `LOCKDOWN`, emits `BreakerTripped`, and **returns** — so the +transaction succeeds and those writes persist. The coin is never split and never sent. + +Aborting would be the obvious thing and it would be wrong: the abort would roll back the Lockdown +along with everything else, leaving the vault open and the attacker free to try again for the price +of gas. `crossing_the_loss_envelope_freezes_the_vault_instead_of_paying` asserts all three +outcomes — the status, the unchanged balance, and the Lockdown. + +## Tests + +```bash +sui move test # everything +sui move test engine_ # the pure vectors +sui move test vault_ # the end-to-end suite +sui move test crossing_the_loss # one test by name +``` + +[`tests/engine_tests.move`](tests/engine_tests.move) pins the classifier and the policy rules. The +same vectors are pinned in TypeScript in [`../sdk/test/engine.test.ts`](../sdk/test/engine.test.ts); +both suites have to agree, because the only thing worse than a wrong tier is two components +disagreeing about it. + +[`tests/vault_tests.move`](tests/vault_tests.move) is named after the attacks rather than the +functions. `a_removed_signers_approval_stops_counting`, `splitting_a_drain_does_not_beat_the_daily_cap` +and `an_agent_cannot_execute` say what they defend; `test_execute_transfer_3` would not. + +## Conventions + +- **Durations are milliseconds**, because that is what `sui::clock` reports. Converting at each + comparison is how an off-by-one-thousand gets in. +- **Amounts are `u64`** in the coin's smallest unit, and any intermediate that could overflow — + exposure, the velocity comparison, the envelope limit — is computed in `u128`. +- **Validation returns a code, and a separate function aborts with it.** An interface can dry-run a + draft policy and show the precise reason; the vault asserts with the same number. +- **Zero means "no limit"** for every cap and threshold. This is load-bearing: it is why + `threshold_loosens` cannot be a plain `>`. +- **Effects before interactions.** The proposal's status is written before any coin moves. Move has + no dynamic dispatch into a caller, so reentrancy is absent by construction rather than defended + against, but the ordering is kept anyway because it costs nothing and survives a refactor. + +## Publishing + +```bash +scripts/publish.sh testnet +``` + +Builds, runs the tests, publishes, and writes [`deployments/testnet.json`](deployments/). It will +not publish a package whose tests fail. diff --git a/sui/sources/vault.move b/sui/sources/vault.move index 338d4d9..8c3bf36 100644 --- a/sui/sources/vault.move +++ b/sui/sources/vault.move @@ -8,7 +8,7 @@ /// interface or a backend. module skur::vault; -use std::string::String; +use std::string::{Self, String}; use std::type_name::{Self, TypeName}; use sui::bag::{Self, Bag}; use sui::balance::{Self, Balance}; @@ -470,8 +470,8 @@ public fun member_roles(v: &Vault, who: address): u8 { roles_of(v, who) } public fun balance_of(v: &Vault): u64 { let key = type_name::get(); - if (!v.funds.contains(key)) return 0; - balance::value(v.funds.borrow>(key)) + if (!bag::contains(&v.funds, key)) return 0; + balance::value(bag::borrow>(&v.funds, key)) } public fun limits_of(v: &Vault): AssetLimits { @@ -551,10 +551,10 @@ public fun deposit(v: &mut Vault, c: Coin, clock: &Clock, ctx: &TxContext) let amount = c.value(); assert!(amount > 0, E_ZERO_AMOUNT); let incoming = c.into_balance(); - if (v.funds.contains(key)) { - balance::join(v.funds.borrow_mut>(key), incoming); + if (bag::contains(&v.funds, key)) { + balance::join(bag::borrow_mut>(&mut v.funds, key), incoming); } else { - v.funds.add(key, incoming); + bag::add(&mut v.funds, key, incoming); }; event::emit(Deposited { vault: object::id(v), @@ -624,7 +624,7 @@ public fun guardian_restrict( activates_at: now, paid_count: 0, last_paid: 0, - label: b"".to_string(), + label: string::utf8(b""), }); types::trust_unknown() }; @@ -720,7 +720,7 @@ fun blank( asset: option::none(), amount: 0, recipient: @0x0, - memo: b"".to_string(), + memo: string::utf8(b""), new_policy: option::none(), new_limits: option::none(), member: @0x0, @@ -1174,7 +1174,7 @@ public fun execute_transfer(v: &mut Vault, id: u64, clock: &Clock, ctx: &mut r.last_paid = now; }; - let paid = balance::split(v.funds.borrow_mut>(key), amount); + let paid = balance::split(bag::borrow_mut>(&mut v.funds, key), amount); transfer::public_transfer(coin::from_balance(paid, ctx), recipient); event::emit(Executed { @@ -1279,7 +1279,7 @@ public fun propose_policy( let delay = if (mask == 0) 0 else v.policy.policy_change_delay(); let id = open_governance(v, types::kind_policy_update(), mask, delay, now, ctx.sender()); v.proposals.borrow_mut(id).new_policy = option::some(next); - emit_opened(v, id, types::kind_policy_update(), ctx.sender(), mask, b"policy".to_string()); + emit_opened(v, id, types::kind_policy_update(), ctx.sender(), mask, string::utf8(b"policy")); id } @@ -1326,7 +1326,7 @@ public fun propose_asset_limits( p.new_limits = option::some(next); p.asset = option::some(key); }; - emit_opened(v, id, types::kind_asset_limits(), ctx.sender(), mask, b"limits".to_string()); + emit_opened(v, id, types::kind_asset_limits(), ctx.sender(), mask, string::utf8(b"limits")); id } @@ -1389,7 +1389,7 @@ public fun propose_member( p.member = who; p.member_roles = roles; }; - emit_opened(v, id, types::kind_member_set(), ctx.sender(), mask, b"member".to_string()); + emit_opened(v, id, types::kind_member_set(), ctx.sender(), mask, string::utf8(b"member")); id } @@ -1453,7 +1453,7 @@ public fun propose_recipient_trust( p.recipient = who; p.trust_level = to; }; - emit_opened(v, id, types::kind_recipient_trust(), ctx.sender(), mask, b"trust".to_string()); + emit_opened(v, id, types::kind_recipient_trust(), ctx.sender(), mask, string::utf8(b"trust")); id } @@ -1476,7 +1476,7 @@ public fun execute_recipient_trust(v: &mut Vault, id: u64, clock: &Clock, ctx: & activates_at: now + v.policy.recipient_activation_delay(), paid_count: 0, last_paid: 0, - label: b"".to_string(), + label: string::utf8(b""), }); types::trust_unknown() }; @@ -1522,7 +1522,7 @@ public fun propose_mode_relax( p.target_mode = to; v.proposals.add(id, p); v.pending_count = v.pending_count + 1; - emit_opened(v, id, types::kind_mode_relax(), sender, 1, b"relax".to_string()); + emit_opened(v, id, types::kind_mode_relax(), sender, 1, string::utf8(b"relax")); id } @@ -1587,7 +1587,7 @@ public fun propose_recovery( p.member_roles = roles_of(v, lost); v.proposals.add(id, p); v.pending_count = v.pending_count + 1; - emit_opened(v, id, types::kind_recovery(), sender, 1, b"recovery".to_string()); + emit_opened(v, id, types::kind_recovery(), sender, 1, string::utf8(b"recovery")); id } From 9e3d7ccbbde9e4cd7f30e4a4f0fe390decdbe8bc Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:47:10 +0100 Subject: [PATCH 18/44] feat(app): the marketing site and the documentation, on the new stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site was the last surface still pitching the EVM build. It is now part of the Next.js app, in two route groups so the marketing design and the vault interface never have to fight each other's base styles. The design the project already settled on is carried over as-is. The content is rewritten for where this actually sits: the comparison table is against native multisig, smart-account frameworks and offchain policy custody rather than 'a plain multisig', and the claims match what the Move code does — fifteen invariants, no audit, no mainnet. Fourteen documentation pages, including two the EVM build had no need for: automated proposers, and the Move package itself with a reading order for a review. The limitations page says what the design gives up, including the throughput ceiling a shared object implies. --- app/src/app/{ => (dapp)/app}/page.tsx | 4 +- app/src/app/(dapp)/layout.tsx | 5 + app/src/app/{ => (dapp)}/vault/[id]/page.tsx | 0 app/src/app/(marketing)/docs/[slug]/page.tsx | 13 + app/src/app/(marketing)/docs/page.tsx | 7 + app/src/app/(marketing)/layout.tsx | 5 + app/src/app/(marketing)/page.tsx | 564 +++++++++++++ app/src/app/(marketing)/product/page.tsx | 196 +++++ app/src/app/(marketing)/security/page.tsx | 180 ++++ app/src/app/(marketing)/solutions/page.tsx | 175 ++++ app/src/app/layout.tsx | 14 +- app/src/marketing/Mockup.tsx | 63 ++ app/src/marketing/Reveal.tsx | 19 + app/src/marketing/Shell.tsx | 186 ++++ app/src/marketing/Ticker.tsx | 58 ++ app/src/marketing/docs.tsx | 777 +++++++++++++++++ app/src/marketing/icons.tsx | 221 +++++ app/src/marketing/motion.ts | 76 ++ app/src/marketing/styles.css | 846 +++++++++++++++++++ 19 files changed, 3404 insertions(+), 5 deletions(-) rename app/src/app/{ => (dapp)/app}/page.tsx (77%) create mode 100644 app/src/app/(dapp)/layout.tsx rename app/src/app/{ => (dapp)}/vault/[id]/page.tsx (100%) create mode 100644 app/src/app/(marketing)/docs/[slug]/page.tsx create mode 100644 app/src/app/(marketing)/docs/page.tsx create mode 100644 app/src/app/(marketing)/layout.tsx create mode 100644 app/src/app/(marketing)/page.tsx create mode 100644 app/src/app/(marketing)/product/page.tsx create mode 100644 app/src/app/(marketing)/security/page.tsx create mode 100644 app/src/app/(marketing)/solutions/page.tsx create mode 100644 app/src/marketing/Mockup.tsx create mode 100644 app/src/marketing/Reveal.tsx create mode 100644 app/src/marketing/Shell.tsx create mode 100644 app/src/marketing/Ticker.tsx create mode 100644 app/src/marketing/docs.tsx create mode 100644 app/src/marketing/icons.tsx create mode 100644 app/src/marketing/motion.ts create mode 100644 app/src/marketing/styles.css diff --git a/app/src/app/page.tsx b/app/src/app/(dapp)/app/page.tsx similarity index 77% rename from app/src/app/page.tsx rename to app/src/app/(dapp)/app/page.tsx index 02e0fd0..c08114c 100644 --- a/app/src/app/page.tsx +++ b/app/src/app/(dapp)/app/page.tsx @@ -1,10 +1,10 @@ 'use client'; import dynamic from 'next/dynamic'; -import { Providers } from './providers'; +import { Providers } from '@/app/providers'; // Wallet detection needs a browser, so nothing in the app tree is server-rendered. -const HomeApp = dynamic(() => import('./HomeApp'), { +const HomeApp = dynamic(() => import('@/app/HomeApp'), { ssr: false, loading: () =>
      Loading…
      , }); diff --git a/app/src/app/(dapp)/layout.tsx b/app/src/app/(dapp)/layout.tsx new file mode 100644 index 0000000..003aa54 --- /dev/null +++ b/app/src/app/(dapp)/layout.tsx @@ -0,0 +1,5 @@ +import '../globals.css'; + +export default function DappLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/app/src/app/vault/[id]/page.tsx b/app/src/app/(dapp)/vault/[id]/page.tsx similarity index 100% rename from app/src/app/vault/[id]/page.tsx rename to app/src/app/(dapp)/vault/[id]/page.tsx diff --git a/app/src/app/(marketing)/docs/[slug]/page.tsx b/app/src/app/(marketing)/docs/[slug]/page.tsx new file mode 100644 index 0000000..6bff021 --- /dev/null +++ b/app/src/app/(marketing)/docs/[slug]/page.tsx @@ -0,0 +1,13 @@ +import { notFound } from 'next/navigation'; +import { DOC_SLUGS, DocsView, type DocSlug } from '@/marketing/docs'; + +/** Every page is known at build time, so the docs are static. */ +export function generateStaticParams() { + return DOC_SLUGS.map((slug) => ({ slug })); +} + +export default async function Page({ params }: { params: Promise<{ slug: string }> }) { + const { slug } = await params; + if (!DOC_SLUGS.includes(slug as DocSlug)) notFound(); + return ; +} diff --git a/app/src/app/(marketing)/docs/page.tsx b/app/src/app/(marketing)/docs/page.tsx new file mode 100644 index 0000000..49da38b --- /dev/null +++ b/app/src/app/(marketing)/docs/page.tsx @@ -0,0 +1,7 @@ +import { DocsView } from '@/marketing/docs'; + +export const metadata = { title: 'Documentation' }; + +export default function Page() { + return ; +} diff --git a/app/src/app/(marketing)/layout.tsx b/app/src/app/(marketing)/layout.tsx new file mode 100644 index 0000000..5001861 --- /dev/null +++ b/app/src/app/(marketing)/layout.tsx @@ -0,0 +1,5 @@ +import '../../marketing/styles.css'; + +export default function MarketingLayout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/app/src/app/(marketing)/page.tsx b/app/src/app/(marketing)/page.tsx new file mode 100644 index 0000000..c590617 --- /dev/null +++ b/app/src/app/(marketing)/page.tsx @@ -0,0 +1,564 @@ +'use client'; + +import Link from 'next/link'; +import { MarketingShell } from '@/marketing/Shell'; +import { AppMockup } from '@/marketing/Mockup'; +import { ScoreTicker } from '@/marketing/Ticker'; +import { Reveal } from '@/marketing/Reveal'; +import { + IconArrowRight, + IconCheck, + IconChevronRight, +} from '@/marketing/icons'; +import { useCountUp } from '@/marketing/motion'; +import { NETWORK } from '@/config'; + +function Stat({ n, label }: { n: number; label: string }) { + const { ref, value } = useCountUp(n, 1400); + return ( +
      + + {value} + +
      {label}
      +
      + ); +} + +const FAQ: [string, string][] = [ + [ + 'What is Skur?', + 'A self-custodial treasury vault on Sui whose authorization requirements rise and fall with the risk of each payment. It keeps the k-of-n approval you already trust and adds onchain rules about how much can move, where it can go, how fast, and how long the risky ones wait.', + ], + [ + 'How is this different from a multisig?', + 'A multisig asks one question: did enough keys sign? Skur asks a second one: should this payment settle right now? The amount, its share of holdings, the recipient’s standing, what already left today and the vault’s security posture all sit between a valid approval and the money. Sui has signature aggregation in the protocol already — that is not what is missing.', + ], + [ + 'Does Skur ever hold funds or keys?', + 'No. The vault is a shared object that holds the assets; your wallets hold the keys. No Skur service is in the execution path. The indexer makes a dashboard faster and can be switched off without affecting your ability to move money, read the policy or approve a payment.', + ], + [ + 'What happens if one of our signers is compromised?', + 'Alone, a stolen key cannot reach any tier’s threshold unless you set that tier to one — and even then it is bounded by the routine maximum, the per-payment cap, the day’s remaining allowance and the loss envelope. If several keys are stolen, the larger payments still wait out a delay any guardian can use to veto, and the envelope freezes the vault on the first attempt that would cross it.', + ], + [ + 'What can a guardian do?', + 'Freeze the vault, veto a critical payment or any weakening of the policy, confirm the largest payments, block a recipient immediately, and start a recovery for a lost signer. A guardian holds no treasury role — the contract refuses to give it one — so a stolen guardian key cannot move a single coin.', + ], + [ + 'Can an automated agent use it?', + 'Yes, and this is the part a threshold cannot express. An agent holds a proposer role: it can open a payment and nothing else. It cannot approve, confirm or execute. A fully compromised agent key produces a queue of proposals that no human approved.', + ], + [ + 'Why Sui, and why Move?', + 'A vault is one shared object, so “what are the rules right now” is a single read. Programmable transaction blocks make creation atomic without a factory. sui::clock gives millisecond time in the transaction, so timelocks are durations rather than block arithmetic. And the treasury is keyed by coin type, so one vault holds any asset with its own limits and its own envelope — no token allowlist to maintain or get wrong.', + ], + [ + 'Has it been audited?', + 'No. The Move core is covered by two test suites, each test named after the attack it defends against, and the TypeScript engines are pinned against the same vectors. That is not an audit. Do not put real value behind Skur before one is complete.', + ], +]; + +const HERO_CELLS: [number, number][] = [ + [0, 130], + [130, 260], + [1180, 0], + [1310, 0], + [1310, 130], + [910, 390], + [1050, 260], + [520, 0], +]; + +export default function Landing() { + const words = 'Treasury security that'.split(' '); + + return ( + +
      + + Every control runs in Move, in a shared object you can read → + +
      + +
      +
      + {HERO_CELLS.map(([x, y], i) => ( + + ))} +
      +
      + 15 invariants enforced by the vault, not by a server +
      +

      + {words.map((w, i) => ( + + + {w} + {' '} + + ))} + + {['assumes', 'compromise'].map((w, i) => ( + + + {w} + + {i === 0 ? ' ' : ''} + + ))} + +

      +

      + An approval proves someone was authorized. Skur decides whether the payment is safe: + how much can move, where it can go, how fast, and how long the risky ones wait — even + when your signers are compromised. +

      +
      + + Launch app + + + See how it works + +
      +
      + Self-custodial + Sui · {NETWORK} + Enforced in Move +
      +
      +
      + +
      +
      + +
      +
      +
      +
      +
      + +
      +
      + +

      Made for organizations that hold real money onchain

      +

      + Startups, protocols, funds, payment companies, nonprofits and family offices that need + more than a signature count between a stolen key and the treasury. +

      +
      +
      +
      + {[...Array(2)].flatMap((_, k) => + [ + 'Startups', + 'Protocols & DAOs', + 'Venture funds', + 'Payment companies', + 'Nonprofits', + 'Family offices', + 'Finance teams', + 'Grant programmes', + ].map((t) => ( + + {t} + + )), + )} +
      +
      +
      +
      + +
      +
      + +
      01 / Controls
      +

      Your treasury, under control

      +

      + Every rule below is Move code in a shared object, not a setting on our server. If Skur + disappeared tomorrow, your vault and its policy would not. +

      +
      + +
      +

      Risk-tiered authorization

      +

      + The vault scores every payment from its amount, its share of holdings, who receives + it, what already left today and the current security mode. The score sets how many + approvals it needs, whether a guardian must sign, and how long it waits. +

      +
      +
      + {[ + '1,000 USDC to a known supplier', + '12,000 USDC to a new address', + '60,000 USDC, 24% of holdings', + ].map((t) => ( + + {t} + + ))} +
      +
      + S +
      +
      + + Routine · 1 approval · executes now + + + High risk · 2 approvals · waits 1 day + + + Critical · 2 + a guardian · 1 day · vetoable + +
      +
      +
      + +
      +

      Recipient trust

      +

      + Recipients are security objects, not strings. An address the vault has never paid is + escalated every time. A newly registered one serves an activation delay before it + can be paid at all. +

      +
      + {[ + ['New', 'activates in 23h', '#1b3a5c', '#cfe2ff', '0x7c4f…41e2'], + ['Verified', 'normal policy', '#1b4332', '#d1e7dd', '0x3a91…c0de'], + ['Restricted', 'always critical', '#4d3a05', '#fff3cd', '0xe2b7…9f10'], + ['Blocked', 'refused', '#4a1c22', '#f8d7da', '0x0d55…77aa'], + ].map(([s, d, bg, fg, addr]) => ( +
      + + {addr} + + + {s} · {d} + +
      + ))} +
      +
      + +
      +

      Cumulative limits

      +

      + Per-payment and 24-hour caps, counted against what has already left. Crossing half + the day’s allowance escalates everything after it, so splitting a drain into twenty + pieces meets a higher bar partway through instead of never. +

      +
      + {[ + ['Payment 1–5', '49,500 USDC', 'Routine'], + ['Payment 6', 'half the day gone', 'Escalated'], + ['Payment 11', 'envelope crossed', 'Refused'], + ].map(([a, b, c]) => ( +
      + {a} + {b} + {c} +
      + ))} +
      +
      + +
      +

      A circuit breaker that latches

      +

      + A share of the balance that may leave per window, measured against the balance when + the window opened. The payment that would cross it is not made — the vault freezes + instead, and the freeze survives the attempt. +

      +
      + +
      +

      An agent that cannot pay itself

      +

      + Software that requests payments holds a proposer role: it can open one and nothing + else. A compromised automation key produces a queue nobody approved, not a + withdrawal. No threshold product can express this, because to a threshold every key + is the same kind of key. +

      + + How the agent role works + +
      +
      +
      +
      + +
      +
      + +
      02 / The firewall
      +

      Weakening the vault is the attack

      +

      + An attacker with enough keys does not withdraw first. They lower the thresholds, widen + the caps and shorten the delays, and then withdraw. So that is the path Skur guards + hardest. +

      +
      + +
      +

      Tightening is instant. Loosening is not.

      +

      + Every policy change is compared field by field against the live one — including the + cases that look like tightening and are not, such as setting a threshold to zero to + disable it, or extending how long a proposal stays alive. +

      +
        +
      • + Loosening any control waits out the policy-change delay +
      • +
      • + Any guardian can veto it inside that window +
      • +
      • + Lockdown refuses to let it be proposed at all +
      • +
      +
      +
      + +
      +
      +
      +
      + +
      +
      + +
      03 / Compared
      +

      What else a Sui treasury can use today

      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      + SkurNative multisigSmart-account frameworksOffchain policy custody
      AuthorizationFollows the risk of the paymentFixed k-of-nFixed, per configConfigurable, offchain
      Cumulative outflowCounted per asset, split-proofNot expressibleNot implementedProvider-dependent
      Enough signers compromisedCaps, delays, veto and a breakerFunds goneFunds goneDepends on the provider
      Policy tamperingDelayed, vetoable, refused in LockdownNo policy to tamper withImmediateProvider-controlled
      Where the rules liveA shared object anyone can readIn the protocolOnchainSomebody’s backend
      +
      +
      +
      + +
      + +
      + “Control not only who can move treasury funds, but how much can move, where it can + go, and what happens when risk changes.” +
      + The Skur thesis +
      + + + +
      +
      +
      + +
      +
      + +
      04 / Who it is for
      +

      Two kinds of power, held by different people

      +

      + Finance teams move the money. Guardians hold the brake. The contract will not let one + address do both jobs. +

      +
      + +
      +

      For finance teams

      +

      + Tiered approvals, trusted recipients, daily caps, and a plain-language review — read + from the vault itself — before any wallet opens. +

      + + How teams use Skur + +
      + +
      +
      +
      +

      For guardians

      +

      + Freeze the vault, veto the critical and the security-reducing, confirm the largest + payments, block a recipient on the spot, recover a lost signer. Never touch a coin. +

      + + What a guardian can do + +
      + +
      +
      +
      +
      +
      + +
      +
      + +
      05 / Lifecycle
      +

      How a payment moves

      +

      + Requirements are pinned at step one. Everything is checked again at step four, and the + stricter of the two applies. +

      +
      + +
      +
      1
      +

      Opened and scored

      +

      + The vault reads the amount, its share of holdings, the recipient’s standing, today’s + outflow and the security mode, then pins the tier and its requirements to the + proposal. +

      +
      +
      +
      2
      +

      Reviewed in plain language

      +

      + Approvers see what leaves, what remains, who receives it and every reason the tier + was assigned — read from the vault, not computed by the interface. +

      +
      +
      +
      3
      +

      Confirmed, or vetoed

      +

      + Approvals are recounted against the live roster, so a removed signer’s approval stops + counting. Any guardian can veto a critical or security-reducing proposal until it + executes. +

      +
      +
      +
      4
      +

      Executed only if still safe

      +

      + Caps, exposure, the recipient’s standing and the loss envelope are all re-checked. + Over the envelope, the vault freezes instead of paying. +

      +
      +
      +
      +
      + +
      +
      + +
      06 / Questions
      +

      Questions, answered plainly

      +
      + +
      + {FAQ.map(([q, a]) => ( +
      + + {q} + + + +
      {a}
      +
      + ))} +
      +
      +
      +
      + + ); +} diff --git a/app/src/app/(marketing)/product/page.tsx b/app/src/app/(marketing)/product/page.tsx new file mode 100644 index 0000000..09a155d --- /dev/null +++ b/app/src/app/(marketing)/product/page.tsx @@ -0,0 +1,196 @@ +'use client'; + +import Link from 'next/link'; +import { MarketingShell, SubHero } from '@/marketing/Shell'; +import { AppMockup } from '@/marketing/Mockup'; +import { Reveal } from '@/marketing/Reveal'; +import { + IconBank, + IconBook, + IconClock, + IconGuard, + IconLab, + IconLayers, + IconShield, + IconTrend, + IconTx, +} from '@/marketing/icons'; + +export default function Product() { + return ( + + + Multisig approvals, +
      + plus a firewall + + } + sub="Keep the k-of-n you already trust. Add the controls that decide whether a valid approval should move money right now." + > + + Read the security model + +
      + +
      +
      + +

      Seven controls between an approval and the money

      +

      + Each one is Move code you can read on the explorer. The interface never shows a rule + the vault does not enforce. +

      +
      + +
      +
      +

      Risk-tiered approvals

      +

      + Amount, share of holdings, recipient standing, today’s outflow and the security mode + set the tier. The tier sets the approvals, the guardian sign-off and the wait. +

      +
      +
      +
      +

      Recipient trust

      +

      + A never-paid address is escalated every time. A newly registered one waits out an + activation delay. Owners can verify, trust, restrict or block any recipient through + governance; a guardian can block one on the spot. +

      +
      +
      +
      +

      Velocity limits

      +

      + Per-payment and 24-hour caps, counted cumulatively per asset. Splitting a payment + into pieces changes nothing, and crossing half the day escalates the rest. +

      +
      +
      +
      +

      Circuit breaker

      +

      + A loss envelope per window, measured against the balance when the window opened. The + payment that would cross it is not made; the vault latches into Lockdown, and the + latch survives the attempt. +

      +
      +
      +
      +

      Guardians

      +

      + An independent role that can freeze, veto, confirm critical payments, block a + recipient and recover a lost signer — and that the contract refuses to give any + path to withdraw. +

      +
      +
      +
      +

      Policy-change firewall

      +

      + Loosening any control waits out a delay, can be vetoed by a guardian, and cannot + even be proposed while the vault is in Lockdown. +

      +
      +
      +
      +

      An automation role

      +

      + A proposer can open a payment and nothing else — not approve, not confirm, not + execute. It is how an agent asks the treasury to pay without ever being able to. +

      +
      +
      +
      +
      + +
      +
      + +

      Know exactly what you are signing

      +

      + Before the wallet opens, the vault itself describes the payment: what leaves, what + remains, who receives it, why it was scored the way it was, and what it needs to + execute. +

      +
      + +
      +

      A review written by the contract

      +

      + The preview is the vault’s own classification, simulated live against the same + function execution runs. The interface cannot promise something the vault would + later refuse. +

      +
        +
      • Amount, treasury impact and remaining balance
      • +
      • Every reason the tier was assigned, not just the loudest
      • +
      • Approvals, guardian sign-off and delay, exactly as pinned
      • +
      +
      +
      + +
      +
      +
      +
      + +
      +
      + +

      Test the policy before it is live

      +

      + The simulator runs the attacks that actually happen against your policy, using the + same deterministic rules the Move modules apply. +

      +
      + +
      +
      +

      Attack scenarios

      +

      + One stolen key paying a new address. Three stolen keys taking 40%. A drain split into + twenty payments. A policy weakened before a withdrawal. A stolen guardian key. A + compromised agent. +

      +
      +
      +
      +

      Maximum possible loss

      +

      + One conservative number per asset: what could leave with no delay, what could leave + within a day, and how long the largest payments wait. Assumptions stated alongside, + never a guarantee. +

      +
      +
      +
      +

      Posture report

      +

      + Confirmed controls and obvious weaknesses, in plain words. It produces no score, + because a score would imply a precision nobody has. +

      +
      +
      + +
      + +
      +
      +
      +
      +
      + ); +} diff --git a/app/src/app/(marketing)/security/page.tsx b/app/src/app/(marketing)/security/page.tsx new file mode 100644 index 0000000..4199142 --- /dev/null +++ b/app/src/app/(marketing)/security/page.tsx @@ -0,0 +1,180 @@ +'use client'; + +import { MarketingShell, SubHero } from '@/marketing/Shell'; +import { Reveal } from '@/marketing/Reveal'; +import { IconCheck } from '@/marketing/icons'; +import { NETWORK, PACKAGE_ID, CONFIGURED } from '@/config'; + +/** The fifteen invariants, each with the control that enforces it. */ +const INVARIANTS: [string, string][] = [ + ['Nothing executes before every active condition is met', 'ordered assertions in execute_transfer'], + ['A guardian cannot move treasury assets through guardian authority', 'types::roles_valid · role gates'], + ['Lockdown stops outgoing execution and new payments', 'assert_not_lockdown'], + ['A security-reducing change never takes effect immediately', 'policy::reductions · delay · veto'], + ['Cumulative outflow cannot be bypassed by splitting', 'day bucket · loss envelope'], + ['A proposal cannot execute twice', 'status written before the coin moves'], + ['A removed signer’s approval stops counting', 'count_with_role against the live roster'], + ['An approval cannot be duplicated or replayed', 'one entry per address in a VecSet'], + ['A new recipient cannot skip its activation delay', 'executable_at = max(delay, activates_at)'], + ['Recovery cannot quietly weaken the vault', 'roles copied · policy untouched · Elevated after'], + ['Balance accounting reconciles', 'one Balance per type · split is the only exit'], + ['The roster always satisfies the policy', 'assert_counts_valid after every change'], + ['The breaker’s latch survives the attempt', 'execute_transfer returns without aborting'], + ['Leaving a raised posture is never unilateral', 'owners + guardians + delay'], + ['An automation key cannot authorize itself', 'PROPOSER satisfies only can_propose'], +]; + +export default function SecurityPage() { + return ( + + + Built for the day +
      + a key is stolen + + } + sub="A stolen key, a compromised laptop or a rogue signer should be a bad day, not the end of the treasury. This page is what holds, and what has not been proven yet." + > + {CONFIGURED ? ( + + The published package + + ) : null} +
      + +
      +
      + +

      What we claim, and what we do not

      +

      + Skur does not make signer compromise harmless. It adds independent, programmable + controls that limit or delay the damage when authorized credentials are misused. +

      +
      + +
      +
      1
      +

      One signer compromised

      +

      + Cannot reach any tier’s threshold alone unless you set that tier to one — and even + then it is bounded by the routine maximum, the per-payment cap, the day’s remaining + allowance and the loss envelope. +

      +
      +
      +
      2
      +

      Enough signers compromised

      +

      + The high and critical delays are a guardian’s veto window, critical payments need a + guardian, and the envelope freezes the vault on the first attempt that would cross + it. +

      +
      +
      +
      3
      +

      An owner quorum weakens the policy

      +

      + Loosening waits out the policy-change delay, can be vetoed by any guardian, and + cannot be proposed at all while the vault is in Lockdown. +

      +
      +
      +
      4
      +

      A guardian is compromised

      +

      + There is no withdrawal path. A recovery is delayed and any owner can cancel it. A + guardian can only freeze, veto and block. +

      +
      +
      +
      +
      + +
      +
      + +

      Fifteen invariants, each with a test

      +

      + Every control is enforced by the Move code and proven by a test named after the attack + it defends against. The mapping is public in the security model. +

      +
      + + {INVARIANTS.map(([t, how], i) => ( +
      +
      + {i + 1} +
      +

      {t}

      +

      {how}

      +
      + ))} +
      +
      +
      + +
      +
      + +

      Verification, honestly stated

      +

      What has been done, and what has not.

      +
      + +
      +
      +

      Two Move test suites

      +

      + One pins the risk classifier and the policy rules as vectors; one drives the vault + end to end, with a test per attack rather than per function. +

      +
      +
      +
      +

      The engines agree with the chain

      +

      + The TypeScript risk engine is pinned against the same vectors as the Move suite, so + a preview and an execution cannot disagree about a tier. +

      +
      +
      +
      +

      Reproducible builds

      +

      + The toolchain version is pinned in CI, because the Move compiler and the bundled + framework move together and a job that silently upgrades either cannot reproduce a + failure. +

      +
      +
      +
      –
      +

      Independent audit

      +

      Not yet. Do not put real value behind Skur until one has been completed.

      +
      +
      +
      –
      +

      Mainnet deployment

      +

      Not yet. Testnet exists for evaluation.

      +
      +
      +
      +

      Known limitations, listed

      +

      + Anchored windows, per-asset exposure with no oracle, a breaker that latches rather + than refunds, single-guardian vaults, and a throughput ceiling per shared object. + All of it is in the model. +

      +
      +
      +
      +
      +
      + ); +} diff --git a/app/src/app/(marketing)/solutions/page.tsx b/app/src/app/(marketing)/solutions/page.tsx new file mode 100644 index 0000000..79f8e74 --- /dev/null +++ b/app/src/app/(marketing)/solutions/page.tsx @@ -0,0 +1,175 @@ +'use client'; + +import Link from 'next/link'; +import { MarketingShell, SubHero } from '@/marketing/Shell'; +import { AppMockup } from '@/marketing/Mockup'; +import { Reveal } from '@/marketing/Reveal'; +import { + IconArrowRight, + IconBank, + IconClock, + IconGuard, + IconLayers, + IconShield, + IconUsers, +} from '@/marketing/icons'; +import { TEMPLATES, fmtDuration } from '@skur/sdk'; +import { NETWORK } from '@/config'; + +export default function Solutions() { + return ( + + + Treasury control +
      + for onchain organizations + + } + sub="Approvals that scale with risk, recipients that earn trust, and guardians who can stop a bad day without ever being able to cause one." + /> + +
      +
      + +

      Three steps to a protected treasury

      +

      + Nobody designs seventeen policy fields from first principles. Pick a template, name + the people, sign once. +

      +
      + +
      +
      +

      Name signers and guardians

      +

      + Owners govern, approvers confirm payments, executors execute, proposers can only + ask. Guardians hold the brake and nothing else; the contract will not let them hold + both. +

      +
      +
      +
      +

      Pick a policy template

      +

      + Seven profiles, from Startup to Family office, set the tiers, delays, caps and loss + envelope. Every number can be tuned later through governance. +

      +
      +
      +
      +

      Operate behind a firewall

      +

      + Every payment is scored and reviewed in plain language. Every loosening of the + policy waits, and any guardian can stop it. +

      +
      +
      +
      +
      + +
      +
      + +

      One vault, seven starting points

      +

      + Each template is a complete, valid policy. Start with the closest fit and tighten from + there. +

      +
      + + {TEMPLATES.map((t) => ( +
      +
      +

      {t.name}

      +

      {t.tagline}

      +

      {t.audience}

      +

      + Critical payments wait {fmtDuration(t.policy.delayCritical)} · new recipients wait{' '} + {fmtDuration(t.policy.recipientActivationDelay)} · loss envelope{' '} + {t.policy.envelopeBps / 100}% per {fmtDuration(t.policy.envelopeWindow)} +

      +
      + ))} +
      +
      +
      + +
      +
      + +

      For guardians

      +

      + A cold key in a drawer, a board member, a security firm: anyone who should be able to + stop money but must never be able to move it. +

      +
      + +
      +

      Hold the brake, not the wheel

      +

      + The contract refuses to give a guardian any treasury role, and refuses to give a + treasury member the guardian role. That makes guardians the second control plane an + attacker has to breach, and the one they cannot profit from. +

      +
        +
      • + Freeze the vault the moment something looks wrong +
      • +
      • + Veto critical payments and any weakening of the policy +
      • +
      • + Replace a lost signer after a delay owners can cancel +
      • +
      +
      +
      + +
      +
      +
      +
      + +
      +
      + +

      No custody. No fees on assets. No lock-in.

      +

      + Skur never holds a key and never takes a percentage. The vault is a shared object you + can reach with any compatible interface. +

      +
      + +
      +

      Self-custodial by construction

      +

      + The vault object holds the assets. Your wallets hold the keys. Nothing created the + vault that retains authority over it, because there is no factory — a vault is + configured and shared in one transaction. +

      + + Read the security model + +
      +
      +

      Reachable without Skur

      +

      + The package is published on Sui and every endpoint lives in one configuration file. + The indexer makes a dashboard faster; switching it off costs you speed, not control. +

      + + Open the explorer + +
      + +
      +
      +
      +
      +
      +
      + ); +} diff --git a/app/src/app/layout.tsx b/app/src/app/layout.tsx index edc840c..ca8a6c4 100644 --- a/app/src/app/layout.tsx +++ b/app/src/app/layout.tsx @@ -1,11 +1,19 @@ import type { Metadata } from 'next'; -import './globals.css'; export const metadata: Metadata = { - title: 'Skur', - description: 'A programmable authorization and treasury security layer for Sui organizations.', + title: { + default: 'Skur — a programmable authorization layer for Sui treasuries', + template: '%s · Skur', + }, + description: + 'Skur decides how much authorization a payment needs, and whether it may settle right now, from the amount, the destination, the recent outflow and the vault’s own security posture. Enforced in Move.', }; +/** + * The root layout carries no stylesheet. The marketing pages and the vault interface are two + * different design languages, each loaded only on its own routes, so neither has to fight the + * other's base rules. + */ export default function RootLayout({ children }: { children: React.ReactNode }) { return ( diff --git a/app/src/marketing/Mockup.tsx b/app/src/marketing/Mockup.tsx new file mode 100644 index 0000000..f4ac71a --- /dev/null +++ b/app/src/marketing/Mockup.tsx @@ -0,0 +1,63 @@ +'use client'; + +/** Static miniature of the app used as artwork on the landing page, the way safe.global shows its dashboard. */ +export function AppMockup({ variant = "overview" }: { variant?: "overview" | "queue" | "policy" }) { + return ( +
      +
      +
      S  Home
      +
      + New transaction
      + {["Overview", "Queue", "Pay", "Policy", "People", "Security"].map((n, i) => ( +
      {n}
      + ))} +
      Security
      + {["Templates", "Simulator", "Max loss"].map((n) => ( +
      {n}
      + ))} +
      +
      +
      + + Main treasury
      0xa91c…42dc
      + 2/3 · 250,000 USDC · Normal +
      + {variant === "overview" && ( + <> +
      +
      Total balance
      +
      250,000.00 USDC
      + ↗ Send⌗ Receive +
      Top assets
      +
      $ USDC250,000
      +
      S SUI1,240
      +
      +
      +
      Pending transactions
      +
      Pay 12,000 USDC1 out of 2
      +
      Pay 900 USDC✓ 1 out of 1
      +
      Update policy⏱ 1d timelock
      +
      + + )} + {variant === "queue" && ( +
      +
      Queue
      +
      ↗ Pay 12,000 USDC to 0x4F…a1c2High risk · 1 out of 2
      +
      ↗ Pay 60,000 USDC to 0x9bd2…77e0Critical · guardian · 1d
      +
      ⚙ Lower approvals to 1Weakens the vault · vetoable
      +
      🤖 Agent: pay 2,400 USDC (invoice 1182)Routine · needs 1 human
      +
      + )} + {variant === "policy" && ( +
      +
      Policy simulator
      +
      One finance signer compromisedBlocked
      +
      Drain split into twenty transfersBlocked
      +
      Attacker weakens policy, then withdrawsDelayed 1d
      +
      Guardian key compromisedNot possible
      +
      + )} +
      +
      + ); +} diff --git a/app/src/marketing/Reveal.tsx b/app/src/marketing/Reveal.tsx new file mode 100644 index 0000000..8dddcca --- /dev/null +++ b/app/src/marketing/Reveal.tsx @@ -0,0 +1,19 @@ +'use client'; + +import type { ReactNode } from "react"; +import { useReveal } from "./motion"; + +/** Scroll-reveal wrapper. `stagger` animates each direct child in sequence. */ +export function Reveal({ children, stagger = false, className = "", as: Tag = "div" }: { children: ReactNode; stagger?: boolean; className?: string; as?: "div" | "section" | "ul" }) { + const ref = useReveal(); + return ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + + {children} + + ); +} + +export function Skeleton({ w = "100%", h = 14, style = {} }: { w?: number | string; h?: number; style?: React.CSSProperties }) { + return ; +} diff --git a/app/src/marketing/Shell.tsx b/app/src/marketing/Shell.tsx new file mode 100644 index 0000000..89ded91 --- /dev/null +++ b/app/src/marketing/Shell.tsx @@ -0,0 +1,186 @@ +'use client'; + +import Link from 'next/link'; +import type { ReactNode } from 'react'; +import { NETWORK } from '@/config'; +import { IconChevronRight } from './icons'; +import { useScrolled } from './motion'; + +export type MarketingPage = 'landing' | 'product' | 'solutions' | 'security' | 'docs'; + +const REPO = 'https://github.com/Emmyhack/skur'; + +/** Nav, closing call to action and footer, shared by every marketing page. */ +export function MarketingShell({ + page, + children, + hideCta = false, +}: { + page: MarketingPage; + children: ReactNode; + hideCta?: boolean; +}) { + const scrolled = useScrolled(); + return ( +
      +
      +
      + + S + Skur + + +
      + Sui · {NETWORK} + + Launch app + +
      +
      +
      + {children} + {!hideCta && ( +
      +
      +
      + Start here +
      +

      + Put an authorization layer +
      + in front of the treasury +

      +

      + Self-custodial, enforced in Move, and readable by the people who sign. +

      +
      + + Read the docs + + + Launch app + +
      +
      +
      + )} +
      +
      +
      +
      +
      + + Skur + +

      + A programmable authorization and treasury security layer for Sui organizations. +

      +
      +
      +
      Product
      +
        +
      • Risk-tiered authorization
      • +
      • Guardians
      • +
      • Policy simulator
      • +
      • Agent proposers
      • +
      • Move package
      • +
      +
      +
      +
      Solutions
      +
        +
      • Finance teams
      • +
      • Guardians
      • +
      • Protocols and funds
      • +
      +
      +
      +
      Project
      + +
      +
      +
      Resources
      + +
      +
      +
      + Skur V1 · Sui {NETWORK} + + MIT licensed. Skur limits and delays damage; it is not a guarantee against loss, and + it has not been audited. + +
      +
      Skur
      +
      +
      +
      + ); +} + +/** The hero used by the product, solutions and security pages. */ +export function SubHero({ + eyebrow, + title, + sub, + children, +}: { + eyebrow: string; + title: ReactNode; + sub: string; + children?: ReactNode; +}) { + return ( + <> +
      +
      + {[ + [0, 130], + [1310, 0], + [1180, 260], + [130, 390], + [910, 390], + ].map(([x, y], i) => ( + + ))} +
      +
      {eyebrow}
      +

      {title}

      +

      {sub}

      +
      + + Launch app + + {children} +
      +
      +
      +
      + + ); +} diff --git a/app/src/marketing/Ticker.tsx b/app/src/marketing/Ticker.tsx new file mode 100644 index 0000000..5c40ff1 --- /dev/null +++ b/app/src/marketing/Ticker.tsx @@ -0,0 +1,58 @@ +'use client'; + +import { useEffect, useState } from "react"; + +type Sample = { amt: string; to: string; tier: "low" | "high" | "critical" | "blocked"; label: string; why: string[] }; + +const SAMPLES: Sample[] = [ + { amt: "1,000 USDC", to: "Design retainer · verified", tier: "low", label: "LOW · 1 approval · executes now", why: ["Below the routine threshold", "Recipient verified, paid 14 times before", "Uses 3% of today's cap"] }, + { amt: "12,000 USDC", to: "0x7c4f…41e2 · never paid", tier: "high", label: "HIGH · 2 approvals · waits 24h", why: ["Above the routine threshold", "This vault has never paid the address", "Activation delay applies; any guardian can veto"] }, + { amt: "60,000 USDC", to: "Exchange deposit · verified", tier: "critical", label: "CRITICAL · 2 + guardian · 24h", why: ["24% of holdings in one payment", "Above the high threshold", "Needs a guardian; any guardian can veto"] }, + { amt: "9,900 USDC × 20", to: "Split across one day", tier: "blocked", label: "BLOCKED · circuit breaker", why: ["Outflow is counted cumulatively", "Loss envelope crossed on payment 11", "Vault enters Lockdown instead of paying"] }, +]; + +/** Live scorer for the hero: cycles through sample payments and shows how the vault would tier each one. */ +export function ScoreTicker() { + const [reduced, setReduced] = useState(false); + const [i, setI] = useState(0); + const [phase, setPhase] = useState<"scoring" | "done">("scoring"); + useEffect(() => { + // Read the preference after mount: reading it during render makes the server pass and the + // hydration disagree. + const m = window.matchMedia?.("(prefers-reduced-motion: reduce)"); + if (m?.matches) { + setReduced(true); + setPhase("done"); + } + }, []); + useEffect(() => { + if (reduced) return; + const t = setTimeout(() => setPhase("done"), phase === "scoring" ? 1100 : 3400); + if (phase === "done") { + const n = setTimeout(() => { setI((x) => (x + 1) % SAMPLES.length); setPhase("scoring"); }, 3400); + return () => { clearTimeout(t); clearTimeout(n); }; + } + return () => clearTimeout(t); + }, [phase, reduced]); + const s = SAMPLES[i]; + return ( +
      +
      Risk engine · live previewPolicy v3 · Normal
      +
      +
      Payment{s.amt}
      +
      Recipient{s.to}
      +
      +
      + {phase === "scoring" ? Scoring against policy… : {s.label}} +
      +
        + {phase === "done" && s.why.map((w, k) =>
      • {w}
      • )} +
      +
      +
      + Requirements are pinned at proposal and checked again at execution. + {SAMPLES.map((_, k) => )} +
      +
      + ); +} diff --git a/app/src/marketing/docs.tsx b/app/src/marketing/docs.tsx new file mode 100644 index 0000000..a1ed6ce --- /dev/null +++ b/app/src/marketing/docs.tsx @@ -0,0 +1,777 @@ +'use client'; + +import Link from 'next/link'; +import type { ReactNode } from 'react'; +import { POLICY_GROUPS, TEMPLATES, fmtDuration } from '@skur/sdk'; +import { CONFIGURED, NETWORK, PACKAGE_ID } from '@/config'; +import { MarketingShell } from './Shell'; + +export type DocSlug = + | 'introduction' + | 'quick-start' + | 'roles' + | 'risk-tiers' + | 'policy' + | 'recipients' + | 'limits' + | 'modes' + | 'changes' + | 'recovery' + | 'agents' + | 'move-package' + | 'invariants' + | 'limitations'; + +type Doc = { slug: DocSlug; title: string; group: string; body: () => ReactNode }; + +const H = ({ children }: { children: ReactNode }) => ( +

      {children}

      +); +const Note = ({ children }: { children: ReactNode }) =>
      {children}
      ; + +function Table({ head, rows }: { head: string[]; rows: ReactNode[][] }) { + return ( +
      + + + + {head.map((h) => ( + + ))} + + + + {rows.map((r, i) => ( + + {r.map((c, j) => ( + + ))} + + ))} + +
      {h}
      {c}
      +
      + ); +} + +const REPO = 'https://github.com/Emmyhack/skur'; + +const DOCS: Doc[] = [ + { + slug: 'introduction', + title: 'Introduction', + group: 'Start', + body: () => ( + <> +

      + Skur is a programmable authorization and treasury security layer for Sui organizations: a + self-custodial vault whose requirements rise and fall with the risk of each payment. +

      +

      + A multisig asks one question — did enough keys sign? Skur asks a second one: should this + payment settle right now? Between a valid approval and the money sit amount tiers, + recipient standing, velocity caps, a loss envelope, guardian veto and a firewall around + policy changes. Every one is enforced by the Move code in a shared object, not by a + server. +

      + Why this is not a multisig +

      + Sui has signature aggregation in the protocol: a multisig address can hold up to ten keys + with weights and mixed schemes, for free. That is not the part that is missing. What is + missing is anything that depends on what the transaction does, who receives + it, or what has already happened today — and that is the whole of Skur. +

      + What Skur does not claim +

      + Skur does not make signer compromise harmless. It limits and delays the damage when + authorized credentials are misused. A stolen key alone cannot reach a tier’s threshold + unless you set that tier to one, and even then it is bounded by the per-payment cap, the + day’s remaining allowance and the loss envelope. +

      + + Skur has not been audited and is not deployed to mainnet. Do not put real value behind it + until an independent audit is complete. + + + ), + }, + { + slug: 'quick-start', + title: 'Quick start', + group: 'Start', + body: () => ( + <> +

      Reading a vault needs no wallet. Acting on one needs the key that holds the role.

      + Open a vault +

      + A vault is a shared object, so anyone can read it: the balances, the queue, the policy and + the security posture all come from the chain. Paste a vault id into the app, or connect a + wallet to see the vaults you hold a role in. +

      + Create your own +
        +
      1. Connect a wallet on Sui {NETWORK}.
      2. +
      3. + Pick the template closest to your organization. Every value can be changed later through + governance — tightening takes effect at once, loosening waits. +
      4. +
      5. + List the signers and their roles. Owners govern, approvers confirm payments, executors + execute, proposers can only ask, guardians hold the brake. +
      6. +
      7. + Sign once. One transaction creates the vault, sets the policy, installs the roster and + approves the first asset — and if any part is invalid, nothing is created. +
      8. +
      + Open a payment +

      + Enter the recipient, the asset and the amount. Before the wallet opens, the vault itself + classifies the payment: the tier, the approvals it needs, whether a guardian must sign, + how long it waits, and every reason. That preview is a simulation of the same function + execution runs, so it cannot promise something the vault would refuse. +

      + Run it yourself +

      + The Move package, the SDK, the indexer and this interface are all in{' '} + + the repository + + . sui move test runs the security suite; each test is named after the attack + it defends against. +

      + + ), + }, + { + slug: 'roles', + title: 'Roles', + group: 'Model', + body: () => ( + <> +

      + Five roles, held as a bitmask. A member can hold several treasury roles; a guardian can + hold none. +

      + + Why guardians are exclusive +

      + The contract refuses to give a guardian a treasury role, and refuses to give a treasury + member the guardian role. Every path that writes a role goes through the same check, so + there is no way to install an exception. That makes guardians a second control plane an + attacker has to breach separately — and one they cannot profit from, because there is no + withdrawal path from guardian authority. +

      + Why approvals are recounted +

      + An approval is recorded against the address, not counted into a number. At execution the + set is recounted against the live roster, so a signer removed after approving stops + counting. A tally frozen at approval time would let a compromised key’s approval outlive + its removal. +

      + + ), + }, + { + slug: 'risk-tiers', + title: 'Risk tiers', + group: 'Model', + body: () => ( + <> +

      + Every payment is scored when it is opened. Five signals, each able to raise the tier and + none able to lower it. +

      +
      + What a tier costs +
      + Pinned, then tighten-only +

      + The requirements are pinned to the proposal when it is opened. At execution the payment is + reclassified against live state and the stricter of the pinned and live + requirements applies. Tightening the policy affects payments already in flight; loosening + it cannot rescue one. +

      + + Exposure is computed per asset, as a share of that asset’s own balance. A vault holding + several coin types has several independent calculations and no portfolio-wide number — + producing one would need a price oracle, and a wrong portfolio number is worse than an + honest per-asset one. + + + ), + }, + { + slug: 'policy', + title: 'The policy', + group: 'Model', + body: () => ( + <> +

      + Seventeen fields. Durations are stored in milliseconds, because that is what{' '} + sui::clock reports. +

      + {POLICY_GROUPS.map((g) => ( +
      + {g.title} +

      {g.sub}

      +
      [ + {f.key}, + f.unit === 'hours' ? 'hours' : f.unit === 'bps' ? 'percent' : f.unit === 'bool' ? 'on/off' : 'count', + `${f.label}${f.hint ? ` — ${f.hint}` : ''}`, + ])} + /> + + ))} + Coherence rules the vault enforces +
        +
      • Approvals must be monotonic: routine ≤ high risk ≤ critical.
      • +
      • The critical delay cannot be shorter than the high-risk delay.
      • +
      • The high exposure threshold cannot exceed the critical one, and neither can exceed 100%.
      • +
      • The hard block cannot sit below the critical exposure threshold.
      • +
      • The envelope window must be at least an hour when the envelope is on.
      • +
      • + The proposal lifetime must exceed the longest delay by at least an hour — otherwise a + payment could expire before its own timelock elapsed. +
      • +
      • + The roster must be able to satisfy the thresholds. A threshold nobody can reach is a + frozen vault, and the contract refuses to create or leave one. +
      • +
      + Starting points +
      [ + {t.name}, + t.audience, + fmtDuration(t.policy.delayCritical), + fmtDuration(t.policy.recipientActivationDelay), + `${t.policy.envelopeBps / 100}% / ${fmtDuration(t.policy.envelopeWindow)}`, + ])} + /> + + ), + }, + { + slug: 'recipients', + title: 'Recipients', + group: 'Model', + body: () => ( + <> +

      + A recipient is a security object with a standing and a clock, not a string in a form. +

      +
      + The activation delay +

      + Registering a recipient starts it at New with an activation delay. A payment to it + cannot execute before that moment — the tier’s delay and the activation delay run + concurrently and the later one governs. Re-checked at execution, so a payment approved + early still waits. +

      + Raising and lowering trust +

      + Registering is immediate, because New with a delay is stricter than never-paid. Raising + trust beyond that is a governance action that waits out the policy-change delay and can be + vetoed. Restricting or blocking is immediate on an owner threshold — and a guardian can + block a recipient alone, instantly. That is the one unilateral power in the system, and it + can only ever stop money. +

      + + Paying an address does not promote it. Only governance changes trust, so a payment to a + never-registered address is escalated every time, forever. This is intended, and + occasionally surprising. + + + ), + }, + { + slug: 'limits', + title: 'Limits and the breaker', + group: 'Reference', + body: () => ( + <> +

      + Per-asset caps bound a single payment. Cumulative accounting bounds a campaign of them. +

      +
      + Why splitting does not work +

      + The day’s outflow is counted, not inferred. Crossing half the day’s allowance escalates + every further payment to at least high risk, so a drain split into twenty pieces meets a + higher bar partway through rather than at the end — and the daily cap refuses the piece + that would cross it. +

      + The envelope, and its basis +

      + The envelope is a share of the balance when the window opened, not of the live + balance. Measuring against the live balance would let a drain shrink its own denominator + and keep every later payment under the same percentage. The cost of this choice is that a + large deposit mid-window does not raise the window’s allowance until the window rolls. +

      + Why the breaker does not revert +

      + When a payment would cross the envelope, the vault marks the proposal refused, enters + Lockdown, emits an event — and the transaction succeeds. The coin is never moved. + Aborting would be the obvious thing and it would be wrong: the abort would roll back the + Lockdown along with everything else, leaving the vault open and the attacker free to try + again for the price of gas. +

      + + A 24-hour bucket anchors on its first charge rather than sliding, so up to two days’ + allowance can leave across a boundary. The envelope and the per-payment cap bound that, + and the maximum-loss view states it rather than assuming the best case. + + + ), + }, + { + slug: 'modes', + title: 'Security modes', + group: 'Reference', + body: () => ( + <> +

      Three postures. Raising one is immediate. Lowering one never is.

      +
      + Leaving a raised posture +

      + It takes owners, a guardian and time, in that order: an owner threshold of approvals, the + guardian threshold of confirmations, and the policy-change delay. Whoever raised the + posture cannot lower it alone, which is the point. +

      + What else raises it +
        +
      • A guardian veto moves a Normal vault to Elevated — reaching for the brake is itself a signal.
      • +
      • A completed recovery leaves the vault Elevated, because a recovery means something went wrong.
      • +
      • The circuit breaker latches straight to Lockdown.
      • +
      + + Deposits are never gated, in any mode, from any address. The controls exist to govern money + leaving; refusing money arriving would only strand it. + + + ), + }, + { + slug: 'changes', + title: 'Changing the policy', + group: 'Reference', + body: () => ( + <> +

      + An attacker with enough keys does not withdraw first. They weaken the policy, then + withdraw. So this is the path guarded hardest. +

      + What counts as weakening +

      + Every change is compared to the live policy field by field. The interesting cases are the + ones where a number going down is a loosening: +

      +
        +
      • + Setting a threshold to zero disables it, which is the loosest possible move — so + moving to zero is a weakening and moving away from zero can only tighten. +
      • +
      • + A longer proposal lifetime keeps a stale approval set alive for longer, so it + weakens the vault even though the number went up. +
      • +
      • + Granting a role to an address that did not hold one is a new way in, so adding a + signer is treated as a weakening while removing one is not. +
      • +
      • + Lifting a restriction on a recipient weakens the vault; imposing one does not. +
      • +
      + What a weakening costs +
        +
      1. An owner threshold of approvals, as with any governance action.
      2. +
      3. The policy-change delay, which runs before it can take effect.
      4. +
      5. A veto window: any guardian can stop it outright until it executes.
      6. +
      7. And it cannot be opened at all while the vault is in Lockdown.
      8. +
      +

      + A change that only tightens the vault skips all of that and takes effect as soon as owners + agree. The policy is also re-validated against the roster at execution, not only when + proposed, so a change that became incoherent in the meantime is refused. +

      + + ), + }, + { + slug: 'recovery', + title: 'Recovery', + group: 'Reference', + body: () => ( + <> +

      A lost key should not cost the treasury, and a stolen guardian key should not gain it.

      + How it works +
        +
      1. A guardian opens a recovery naming the lost signer and the replacement.
      2. +
      3. The guardian threshold of confirmations is required.
      4. +
      5. The recovery delay runs. Any owner can cancel it during that time.
      6. +
      7. + On execution the roles move across unchanged — whatever the lost signer holds at that + moment, not what they held when it was proposed. +
      8. +
      9. The policy is untouched, and the vault comes out of it in Elevated.
      10. +
      + What it cannot do +
        +
      • It cannot change the policy, the limits or anyone else’s roles.
      • +
      • It cannot name an address that is already a member.
      • +
      • A guardian cannot nominate themselves as the replacement.
      • +
      • It cannot leave the roster unable to satisfy the policy.
      • +
      + + With a single guardian, one key both opens the recovery and confirms it. The owner cancel + is what bounds that, and the protocol, fund and larger templates ship with two guardians + for exactly this reason. + + + ), + }, + { + slug: 'agents', + title: 'Automated proposers', + group: 'Reference', + body: () => ( + <> +

      + An organization increasingly wants software to request payments. Nobody sensibly + wants software to authorize them. +

      +

      + An invoice processor, a rebalancer, an agent reading a vendor inbox: each needs to put a + payment in front of people. Giving it a signing key in a multisig gives it a fraction of + the authority to move money, because to a threshold every key is the same kind of key. +

      + The proposer role +

      + A member holding only PROPOSER can open a proposal and do nothing else. It + cannot approve, cannot confirm, cannot execute, cannot govern, and cannot be a guardian. + Its approval would not count even if it submitted one — the vault checks the approver role + when counting, not merely membership. +

      +

      + A fully compromised agent key therefore produces a queue of proposals that no human + approved. That is the difference between an automation incident and a loss. +

      + What an agent still faces +
        +
      • Everything it opens is scored like any other payment.
      • +
      • Paying a new address is escalated and waits out the activation delay.
      • +
      • Its payments count against the day’s allowance and the loss envelope like anyone’s.
      • +
      • An agent that starts behaving oddly trips the same breaker a human would.
      • +
      + + Give an automation its own key and its own role. Sharing a human’s key with a script is + the thing this role exists to make unnecessary. + + + ), + }, + { + slug: 'move-package', + title: 'The Move package', + group: 'Assurance', + body: () => ( + <> +

      + Four modules. The three pure ones hold the rules; the fourth holds the state. +

      +
      + Reading order for a review +
        +
      1. + risk::classify — if this is wrong, every number the product shows is wrong. +
      2. +
      3. + policy::reductions — the firewall, and the cases where a smaller number is + a weakening. +
      4. +
      5. + vault::execute_transfer — the last gate, where everything is re-evaluated + against live state. +
      6. +
      7. + vault::begin and finish — creation as a hot potato, so a + half-configured vault is never reachable. +
      8. +
      + Conventions +
        +
      • Durations in milliseconds; amounts in the coin’s smallest unit.
      • +
      • Any intermediate that could overflow is computed in 128-bit space.
      • +
      • + Validation returns a code and a separate function aborts with it, so an interface can + dry-run a draft policy and show the precise reason. +
      • +
      • Zero means “no limit” for every cap and threshold. This is load-bearing.
      • +
      + {CONFIGURED ? ( + <> + This deployment +
      + {PACKAGE_ID} + , + ], + ]} + /> + + ) : ( + + No package is published for {NETWORK} yet. Publish with{' '} + sui/scripts/publish.sh; it builds, runs the tests, and refuses to publish a + package whose tests fail. + + )} + + ), + }, + { + slug: 'invariants', + title: 'Invariants', + group: 'Assurance', + body: () => ( + <> +

      + Fifteen properties, each enforced by named code and proven by a test named after the + attack it defends against. +

      +
        +
      1. Nothing executes before every active condition is met.
      2. +
      3. A guardian cannot move treasury assets through guardian authority.
      4. +
      5. Lockdown stops outgoing execution and new payments.
      6. +
      7. A security-reducing change never takes effect immediately.
      8. +
      9. Cumulative outflow cannot be bypassed by splitting.
      10. +
      11. A proposal cannot execute twice.
      12. +
      13. A removed signer’s approval stops counting.
      14. +
      15. An approval cannot be duplicated or replayed.
      16. +
      17. A new recipient cannot skip its activation delay.
      18. +
      19. Recovery cannot quietly weaken the vault.
      20. +
      21. Balance accounting reconciles.
      22. +
      23. The roster always satisfies the policy.
      24. +
      25. The breaker’s latch survives the attempt.
      26. +
      27. Leaving a raised posture is never unilateral.
      28. +
      29. An automation key cannot authorize itself.
      30. +
      +

      + The full mapping — invariant, the code that enforces it, the test that proves it — is in{' '} + + the security model + + . +

      + What is absent by construction +

      + Reentrancy is not defended against; it cannot happen. Move has no dynamic dispatch into a + caller, and the only outgoing value movement is a coin split after the proposal’s status + has already been written. The ordering is kept anyway, because it costs nothing and + survives a refactor. +

      + + ), + }, + { + slug: 'limitations', + title: 'Limitations', + group: 'Assurance', + body: () => ( + <> +

      + Design positions, not oversights. State these to anyone evaluating the system. +

      +
        +
      • + No independent audit. Do not put real value behind Skur until one is complete. +
      • +
      • + Anchored windows, not sliding ones. A day bucket anchors on its first charge, so + up to two days’ allowance can leave across a boundary. +
      • +
      • + Exposure is per asset. No portfolio-wide number without a price oracle, and a + wrong portfolio number would be worse than an honest per-asset one. +
      • +
      • + The breaker latches; it does not refund. Everything that executed before the trip + stays paid. What it buys is that the trip happens instead of the payment that would have + crossed the line. +
      • +
      • + The envelope basis is the balance when the window opened. A large deposit + mid-window does not raise that window’s allowance. +
      • +
      • + Single-guardian vaults. One key both freezes and, with owners, unfreezes. The + larger templates ship with two. +
      • +
      • + A shared object serializes. Every write to a vault goes through consensus on that + object, so one vault has a throughput ceiling. For a treasury doing thousands of + payments an hour the answer is several vaults, not a pretence otherwise. +
      • +
      • + No arbitrary contract calls in V1. Only coin transfers exist, so “unlimited + approval” and “malicious contract” are excluded by construction rather than analysed — + which is also why decoding arbitrary calls is on the roadmap rather than claimed. +
      • +
      • + Paying an address does not promote it. Only governance changes trust, so payments + to a never-registered address are escalated every time. +
      • +
      + + ), + }, +]; + +const GROUPS = ['Start', 'Model', 'Reference', 'Assurance']; + +export const DOC_SLUGS = DOCS.map((d) => d.slug); + +export function DocsView({ slug }: { slug: DocSlug }) { + const doc = DOCS.find((d) => d.slug === slug) ?? DOCS[0]; + const i = DOCS.indexOf(doc); + const prev = i > 0 ? DOCS[i - 1] : null; + const next = i < DOCS.length - 1 ? DOCS[i + 1] : null; + return ( + +
      + +
      +
      Docs / {doc.group}
      +

      {doc.title}

      + {doc.body()} + +
      +
      +
      + ); +} diff --git a/app/src/marketing/icons.tsx b/app/src/marketing/icons.tsx new file mode 100644 index 0000000..76018f8 --- /dev/null +++ b/app/src/marketing/icons.tsx @@ -0,0 +1,221 @@ +'use client'; + +/** Small inline icon set (24px grid, 1.75 stroke), matching the line-icon style of the Safe interface. */ +import type { SVGProps } from "react"; + +const base = (props: SVGProps) => ({ + width: 18, + height: 18, + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + strokeWidth: 1.75, + strokeLinecap: "round" as const, + strokeLinejoin: "round" as const, + ...props, +}); + +export const IconOverview = (p: SVGProps) => ( + + + + +); +export const IconAssets = (p: SVGProps) => ( + + + + +); +export const IconTx = (p: SVGProps) => ( + + + +); +export const IconBook = (p: SVGProps) => ( + + + + + +); +export const IconUsers = (p: SVGProps) => ( + + + + +); +export const IconApps = (p: SVGProps) => ( + + + + + + +); +export const IconPolicy = (p: SVGProps) => ( + + + + +); +export const IconShield = (p: SVGProps) => ( + + + + +); +export const IconLab = (p: SVGProps) => ( + + + +); +export const IconSettings = (p: SVGProps) => ( + + + + +); +export const IconSend = (p: SVGProps) => ( + + + +); +export const IconReceive = (p: SVGProps) => ( + + + + +); +export const IconCopy = (p: SVGProps) => ( + + + + +); +export const IconExternal = (p: SVGProps) => ( + + + +); +export const IconChevron = (p: SVGProps) => ( + + + +); +export const IconChevronRight = (p: SVGProps) => ( + + + +); +export const IconArrowRight = (p: SVGProps) => ( + + + +); +export const IconCheck = (p: SVGProps) => ( + + + +); +export const IconSun = (p: SVGProps) => ( + + + + +); +export const IconMoon = (p: SVGProps) => ( + + + +); +export const IconLock = (p: SVGProps) => ( + + + + +); +export const IconClose = (p: SVGProps) => ( + + + +); +export const IconClock = (p: SVGProps) => ( + + + + +); +export const IconWallet = (p: SVGProps) => ( + + + + +); +export const IconPlus = (p: SVGProps) => ( + + + +); +export const IconSearch = (p: SVGProps) => ( + + + + +); +export const IconBell = (p: SVGProps) => ( + + + + +); +export const IconHelp = (p: SVGProps) => ( + + + + +); +export const IconDocs = (p: SVGProps) => ( + + + + +); +export const IconTrend = (p: SVGProps) => ( + + + +); +export const IconLayers = (p: SVGProps) => ( + + + + +); +export const IconGuard = (p: SVGProps) => ( + + + + +); +export const IconBank = (p: SVGProps) => ( + + + +); +export const IconSwap = (p: SVGProps) => ( + + + +); +export const IconCollapse = (p: SVGProps) => ( + + + + +); +export const IconMenu = (p: SVGProps) => ( + + + +); diff --git a/app/src/marketing/motion.ts b/app/src/marketing/motion.ts new file mode 100644 index 0000000..5740bd7 --- /dev/null +++ b/app/src/marketing/motion.ts @@ -0,0 +1,76 @@ +'use client'; + +import { useEffect, useRef, useState } from "react"; + +/** Adds the `in` class when the element scrolls into view, once. Pairs with .reveal / .reveal-stagger. */ +export function useReveal(threshold = 0.15) { + const ref = useRef(null); + useEffect(() => { + const el = ref.current; + if (!el) return; + if (typeof IntersectionObserver === "undefined") { + el.classList.add("in"); + return; + } + const io = new IntersectionObserver( + (entries) => { + for (const e of entries) { + if (e.isIntersecting) { + el.classList.add("in"); + io.disconnect(); + } + } + }, + { threshold, rootMargin: "0px 0px -8% 0px" }, + ); + io.observe(el); + return () => io.disconnect(); + }, [threshold]); + return ref; +} + +/** Counts from 0 to `target` once visible. */ +export function useCountUp(target: number, durationMs = 1200) { + const ref = useRef(null); + const [value, setValue] = useState(0); + useEffect(() => { + const el = ref.current; + if (!el) return; + const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; + if (reduce || typeof IntersectionObserver === "undefined") { + setValue(target); + return; + } + let raf = 0; + const io = new IntersectionObserver((entries) => { + if (!entries.some((e) => e.isIntersecting)) return; + io.disconnect(); + const start = performance.now(); + const tick = (now: number) => { + const t = Math.min(1, (now - start) / durationMs); + const eased = 1 - Math.pow(1 - t, 3); + setValue(Math.round(target * eased)); + if (t < 1) raf = requestAnimationFrame(tick); + }; + raf = requestAnimationFrame(tick); + }); + io.observe(el); + return () => { + io.disconnect(); + cancelAnimationFrame(raf); + }; + }, [target, durationMs]); + return { ref, value }; +} + +/** True once the window has scrolled past `px`. Used for the sticky nav's shadow. */ +export function useScrolled(px = 8) { + const [scrolled, setScrolled] = useState(false); + useEffect(() => { + const onScroll = () => setScrolled(window.scrollY > px); + onScroll(); + window.addEventListener("scroll", onScroll, { passive: true }); + return () => window.removeEventListener("scroll", onScroll); + }, [px]); + return scrolled; +} diff --git a/app/src/marketing/styles.css b/app/src/marketing/styles.css new file mode 100644 index 0000000..9bcba5b --- /dev/null +++ b/app/src/marketing/styles.css @@ -0,0 +1,846 @@ +/* Skur. Identity: charcoal #212529 with #FFD000 used the way hazard tape and a highlighter are used: sparingly, to mark what matters. + Space Grotesk for display, DM Sans for text, DM Mono for numbers and labels. Sharp 4-8px radii, hairlines, numbered sections. + Light: charcoal primary, yellow accent on white. Dark: #212529 canvas, #2b3035 panels, yellow primary with charcoal text. + Motion: entrance reveals, staggered lists, live scorer, tape that runs in Lockdown, reduced-motion aware. */ +@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&family=DM+Mono:wght@400;500&family=Space+Grotesk:wght@500;600;700&display=swap"); + +:root { + --text: #212529; + --text-2: #6c757d; + --text-3: #adb5bd; + --canvas: #f1f3f5; + --panel: #ffffff; + --panel-2: #e9ecef; + --panel-3: #f8f9fa; + --border: #dee2e6; + --border-2: #adb5bd; + --brand: #212529; + --brand-hover: #343a40; + --brand-contrast: #ffffff; + --brand-bg: #e9ecef; + --brand-bg-2: #dee2e6; + --accent: #ffd000; + --accent-hover: #e6bb00; + --accent-contrast: #212529; + --accent-bg: #fff6c2; + --accent-bg-2: #ffec85; + --accent-soft: rgba(255, 208, 0, 0.35); + --success: #198754; + --success-bg: #d1e7dd; + --success-text: #0f5132; + --warning: #e5850b; + --warning-bg: #fff3cd; + --warning-text: #664d03; + --error: #dc3545; + --error-bg: #f8d7da; + --error-text: #842029; + --info: #0a58ca; + --info-bg: #cfe2ff; + --info-text: #052c65; + --review: #c2410c; + --review-bg: #ffe8d6; + --radius: 8px; + --radius-sm: 6px; + --sidebar: 236px; + --ease: cubic-bezier(0.22, 1, 0.36, 1); + --shadow-1: 0 1px 2px rgba(33, 37, 41, 0.06), 0 0 0 1px rgba(33, 37, 41, 0.04); + --shadow-2: 0 12px 32px rgba(33, 37, 41, 0.12); +} +[data-theme="dark"] { + --text: #f8f9fa; + --text-2: #adb5bd; + --text-3: #6c757d; + --canvas: #212529; + --panel: #2b3035; + --panel-2: #343a40; + --panel-3: #30353a; + --border: #343a40; + --border-2: #6c757d; + --brand: #ffd000; + --brand-hover: #ffdc33; + --brand-contrast: #212529; + --brand-bg: #3d3400; + --brand-bg-2: #4f4400; + --accent: #ffd000; + --accent-hover: #ffdc33; + --accent-contrast: #212529; + --accent-bg: #3d3400; + --accent-bg-2: #4f4400; + --accent-soft: rgba(255, 208, 0, 0.3); + --success: #75b798; + --success-bg: #1b4332; + --success-text: #d1e7dd; + --warning: #ffa94d; + --warning-bg: #4d2e05; + --warning-text: #fff3cd; + --error: #ea868f; + --error-bg: #4a1c22; + --error-text: #f8d7da; + --info: #6ea8fe; + --info-bg: #1b3a5c; + --info-text: #cfe2ff; + --review: #ffa94d; + --review-bg: #4a2a0b; + --shadow-1: 0 0 0 1px rgba(255, 255, 255, 0.04); + --shadow-2: 0 12px 32px rgba(0, 0, 0, 0.4); +} + +* { box-sizing: border-box; } +html, body { margin: 0; } +html { scroll-behavior: smooth; } +body { font-family: "DM Sans", system-ui, sans-serif; font-size: 14px; line-height: 20px; color: var(--text); background: var(--canvas); -webkit-font-smoothing: antialiased; transition: background 0.25s var(--ease), color 0.25s var(--ease); } +h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; } +h1 { font-size: 32px; line-height: 36px; } +h2 { font-size: 27px; line-height: 34px; } +h3 { font-size: 20px; line-height: 26px; } +h4 { font-size: 16px; line-height: 22px; } +p { margin: 0; } +a { color: inherit; text-decoration: none; } +code, .mono { font-family: "DM Mono", ui-monospace, Menlo, monospace; font-size: 12.5px; } +button, input, select, textarea { font-family: inherit; } +h1, h2, h3, .display, .balance-card .amount, .scorecard .v, .stats .v { font-family: "Space Grotesk", "DM Sans", system-ui, sans-serif; } +.muted { color: var(--text-2); } +.faint { color: var(--text-3); } +.small { font-size: 12px; line-height: 16px; } +.caption { font-size: 12px; line-height: 16px; color: var(--text-2); } +.overline { font-size: 11px; line-height: 14px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--text-2); } +.strong { font-weight: 700; } +.num { font-variant-numeric: tabular-nums; } +.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.accent { color: var(--text); background: var(--accent); padding: 0 4px; } +[data-theme="dark"] .accent { color: var(--accent); background: none; padding: 0; } + +/* ================================================================== motion */ +@keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } } +@keyframes fade { from { opacity: 0; } to { opacity: 1; } } +@keyframes pop { from { opacity: 0; transform: scale(0.96) translateY(8px); } to { opacity: 1; transform: none; } } +@keyframes shimmer { from { background-position: -600px 0; } to { background-position: 600px 0; } } +@keyframes cell { 0%, 100% { opacity: 0.15; } 50% { opacity: 0.6; } } +@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } } +@keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 var(--accent-soft); } 70% { box-shadow: 0 0 0 14px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } +@keyframes spin { to { transform: rotate(360deg); } } +@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } +@keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } + +.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); } +.reveal.in { opacity: 1; transform: none; } +.reveal-stagger > * { opacity: 0; transform: translateY(16px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); } +.reveal-stagger.in > * { opacity: 1; transform: none; } +.reveal-stagger.in > *:nth-child(1) { transition-delay: 0.05s; } +.reveal-stagger.in > *:nth-child(2) { transition-delay: 0.12s; } +.reveal-stagger.in > *:nth-child(3) { transition-delay: 0.19s; } +.reveal-stagger.in > *:nth-child(4) { transition-delay: 0.26s; } +.reveal-stagger.in > *:nth-child(5) { transition-delay: 0.33s; } +.reveal-stagger.in > *:nth-child(6) { transition-delay: 0.40s; } +.reveal-stagger.in > *:nth-child(n+7) { transition-delay: 0.47s; } +.enter { animation: rise 0.5s var(--ease) both; } +.enter-2 { animation: rise 0.5s var(--ease) 0.08s both; } +.enter-3 { animation: rise 0.5s var(--ease) 0.16s both; } +.enter-4 { animation: rise 0.5s var(--ease) 0.24s both; } +.page-enter { animation: fade 0.35s var(--ease) both; } +.page-enter > * { animation: rise 0.45s var(--ease) both; } +.page-enter > *:nth-child(2) { animation-delay: 0.06s; } +.page-enter > *:nth-child(3) { animation-delay: 0.12s; } +.page-enter > *:nth-child(4) { animation-delay: 0.18s; } +.lift { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); } +.lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); } +.skeleton { position: relative; overflow: hidden; background: var(--panel-2); border-radius: 6px; color: transparent !important; } +.skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent); background-size: 600px 100%; animation: shimmer 1.4s linear infinite; } +[data-theme="dark"] .skeleton::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent); background-size: 600px 100%; } +.spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--border-2); border-top-color: var(--brand); animation: spin 0.8s linear infinite; display: inline-block; vertical-align: middle; } +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } + .reveal, .reveal-stagger > * { opacity: 1; transform: none; } +} + +/* ================================================================== buttons */ +.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 20px; border-radius: var(--radius-sm); border: 1px solid transparent; font-size: 14px; font-weight: 700; cursor: pointer; white-space: nowrap; transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease), box-shadow 0.15s var(--ease); } +.btn:active:not(:disabled) { transform: scale(0.98); } +.btn:disabled { opacity: 0.4; cursor: not-allowed; } +.btn-primary { background: var(--brand); color: var(--brand-contrast); } +.btn-primary:hover:not(:disabled) { background: var(--brand-hover); box-shadow: var(--shadow-2); } +.btn-secondary { background: transparent; color: var(--text); border-color: var(--border-2); } +.btn-secondary:hover:not(:disabled) { background: var(--panel-2); } +.btn-dark { background: var(--panel-2); color: var(--text); } +.btn-dark:hover:not(:disabled) { background: var(--brand-bg-2); } +.btn-danger { background: transparent; color: var(--error); border-color: var(--error); } +.btn-danger:hover:not(:disabled) { background: var(--error-bg); } +.btn-ghost { background: transparent; color: var(--text); } +.btn-ghost:hover:not(:disabled) { background: var(--panel-2); } +.btn-accent { background: var(--accent); color: var(--accent-contrast); } +.btn-accent:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 10px 28px rgba(255,208,0,0.35); } +.btn-white { background: #fff; color: #212529; border-color: #dee2e6; } +.btn-white:hover:not(:disabled) { background: #f1f3f5; } +.btn-black { background: #212529; color: #fff; } +.btn-black:hover:not(:disabled) { background: #343a40; } +.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; } +.btn-lg { height: 52px; padding: 0 28px; font-size: 16px; } +.btn-block { width: 100%; } +.icon-btn { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 999px; border: 0; background: var(--panel-2); color: var(--text-2); cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.15s; } +.icon-btn:hover { color: var(--text); background: var(--brand-bg-2); } +.icon-btn:active { transform: scale(0.94); } +.icon-btn.small { width: 28px; height: 28px; background: transparent; } +.icon-btn.small:hover { background: var(--panel-2); } + +/* ================================================================== app shell */ +.shell { display: flex; min-height: 100vh; } +.shell.collapsed { --sidebar: 68px; } +.shell.collapsed .sidebar { padding: 12px 8px 16px; } +.shell.collapsed .lbl, .shell.collapsed .nav-group, .shell.collapsed .promo, .shell.collapsed .nav .count, .shell.collapsed .tag-new { display: none; } +.shell.collapsed .home-pill { padding: 0 8px; } +.shell.collapsed .sidebar-top { flex-direction: column; gap: 6px; } +.shell.collapsed .nav button { justify-content: center; padding: 0; } +.shell.collapsed .nav button.active::before { left: -6px; } +.shell.collapsed .newtx .btn { font-size: 0; gap: 0; padding: 0; } +.shell.collapsed .newtx .btn svg { width: 16px; height: 16px; } +.sidebar { transition: width 0.25s var(--ease), padding 0.25s var(--ease); } +.sidebar { width: var(--sidebar); flex: none; background: var(--panel); border-right: 1px solid var(--border); padding: 12px 10px 16px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; overflow-y: auto; } +.home-pill { display: inline-flex; align-items: center; gap: 10px; height: 40px; padding: 0 14px 0 8px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; background: var(--accent-bg); color: var(--text); font-weight: 700; cursor: pointer; border: 0; align-self: flex-start; transition: background 0.15s; } +.home-pill:hover { background: var(--accent-bg-2); } +.home-pill .mark { width: 24px; height: 24px; border-radius: 4px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 13px; } +.sidebar-top { display: flex; align-items: center; justify-content: space-between; padding: 4px 4px 8px; } +.newtx { margin: 4px 0 16px; } +.newtx .btn { width: 100%; justify-content: center; border-color: var(--border-2); background: transparent; color: var(--text-2); font-weight: 500; } +.newtx .btn:not(:disabled) { color: var(--text); border-color: var(--accent); } +.newtx .btn:hover:not(:disabled) { background: var(--accent); color: var(--accent-contrast); } +.nav { display: flex; flex-direction: column; gap: 2px; position: relative; } +.nav button { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; height: 38px; padding: 0 12px; border-radius: var(--radius-sm); border: 0; background: transparent; color: var(--text); font-size: 14px; font-weight: 500; cursor: pointer; position: relative; transition: background 0.15s, color 0.15s; } +.nav button:hover { background: var(--panel-2); } +.nav button.active { background: var(--accent-bg); font-weight: 700; } +.nav button.active::before { content: ""; position: absolute; left: -10px; top: 8px; bottom: 8px; width: 3px; border-radius: 2px; background: var(--accent); animation: grow 0.3s var(--ease); transform-origin: center; } +.nav button .ico { width: 18px; height: 18px; color: var(--text-2); display: inline-grid; place-items: center; transition: color 0.15s, transform 0.2s var(--ease); } +.nav button:hover .ico { transform: translateX(2px); } +.nav button.active .ico { color: var(--text); } +[data-theme="dark"] .nav button.active .ico { color: var(--accent); } +.nav .count { margin-left: auto; font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; background: var(--review-bg); color: var(--review); } +.nav-group { font-size: 12px; color: var(--text-2); padding: 14px 12px 6px; } +.sidebar-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 2px; } +.promo { border-radius: 10px; padding: 16px; background: linear-gradient(180deg, var(--brand-bg) 0%, var(--panel) 100%); margin: 0 4px 12px; animation: pop 0.4s var(--ease); } +.promo .tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); margin-bottom: 8px; } +.promo h4 { font-size: 14px; margin-bottom: 4px; } +.promo p { font-size: 12px; color: var(--text-2); margin-bottom: 10px; } +.tag-new { display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); font-size: 11px; font-weight: 700; } + +.main { flex: 1; min-width: 0; padding: 20px 24px 48px; } +.main-inner { max-width: 1160px; } +.header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; animation: fade 0.4s var(--ease); } +.acct-pill { display: inline-flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px 0 8px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); cursor: pointer; border: 0; color: var(--text); text-align: left; max-width: 100%; transition: box-shadow 0.2s; } +.acct-pill:hover { box-shadow: var(--shadow-2); } +.acct-pill .name { font-size: 14px; font-weight: 700; } +.acct-pill .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 11.5px; color: var(--text-2); } +.acct-pill .addr b { color: var(--text); font-weight: 600; } +.acct-pill .meta { display: inline-flex; align-items: center; gap: 12px; margin-left: 8px; padding-left: 12px; border-left: 1px solid var(--border); font-size: 14px; } +.acct-pill .meta .chip-s { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 6px; background: var(--panel-2); font-size: 12px; color: var(--text-2); } +.tools-pill { display: inline-flex; align-items: center; gap: 6px; height: 56px; padding: 0 10px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); } +.tools-pill .btn { height: 36px; border-radius: 6px; } +.tools-pill .btn-secondary { border-color: var(--border-2); color: var(--text-2); } +.tools-pill .btn-secondary.on { color: var(--text); } + +/* ================================================================== cards, lists, tables */ +.card { background: var(--panel); border-radius: 10px; padding: 24px; margin-bottom: 24px; box-shadow: var(--shadow-1); } +.card.flush { padding: 0; overflow: hidden; } +.card.flush .card-head { padding: 20px 24px 8px; } +.card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } +.card-head h4 { font-size: 16px; } +.card-head .sub { color: var(--text-2); font-size: 14px; margin-top: 4px; } +.card-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } +.link { color: var(--text); font-weight: 500; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; display: inline-flex; align-items: center; gap: 4px; } +.link:hover { text-decoration: underline; } +.link.accent { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } +[data-theme="dark"] .link.accent { color: var(--accent); box-shadow: none; } +.grid { display: grid; gap: 24px; } +.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } +.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } +.overview-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 24px; align-items: start; } +@media (max-width: 1000px) { .overview-grid { grid-template-columns: 1fr; } } + +.balance-card .label { font-size: 15px; font-weight: 500; margin-bottom: 4px; color: var(--text-2); } +.balance-card .amount { font-size: 42px; line-height: 46px; font-weight: 800; letter-spacing: -0.03em; } +.balance-card .amount .dec { color: var(--text-3); font-weight: 600; } +.balance-card .actions { display: flex; gap: 8px; flex-wrap: wrap; } +.balance-card .actions .btn { background: var(--panel-2); color: var(--text); border: 0; height: 38px; font-weight: 600; } +.balance-card .actions .btn.hi { background: var(--brand); color: var(--brand-contrast); } +.balance-card .actions .btn:hover:not(:disabled) { background: var(--brand-bg-2); } +.balance-card .actions .btn.hi:hover:not(:disabled) { background: var(--brand-hover); } +.balance-row { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; } + +.banner { border-radius: 10px; padding: 20px 24px; display: flex; gap: 20px; align-items: center; margin-bottom: 24px; background: linear-gradient(90deg, #dee2e6 0%, #e9ecef 60%, #f1f3f5 100%); color: #212529; position: relative; overflow: hidden; } +[data-theme="dark"] .banner { background: linear-gradient(90deg, #343a40 0%, #2b3035 70%); color: #f8f9fa; } +.banner .glyph { width: 52px; height: 52px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; flex: none; animation: pulse-ring 2.4s ease-out infinite; } +.banner h4 { font-size: 18px; margin-bottom: 4px; } +.banner p { color: var(--text-2); margin-bottom: 8px; } +.banner .cta { font-weight: 700; color: var(--text); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; } +.banner .cta svg { transition: transform 0.2s var(--ease); } +.banner .cta:hover svg { transform: translateX(4px); } +.banner.warn { background: linear-gradient(90deg, #ffe5b4 0%, #fff3cd 70%); color: #212529; } +[data-theme="dark"] .banner.warn { background: linear-gradient(90deg, #4d3a05 0%, #2b3035 70%); color: #f8f9fa; } +.banner.warn .glyph { background: var(--warning); color: #212529; } +.banner .close { margin-left: auto; align-self: flex-start; background: none; border: 0; cursor: pointer; color: inherit; opacity: 0.6; } +.banner .close:hover { opacity: 1; } + +.list { list-style: none; margin: 0; padding: 0; } +.list > li { display: flex; align-items: center; gap: 14px; padding: 14px 24px; border-top: 1px solid var(--border); transition: background 0.15s; } +.list > li:hover { background: var(--panel-3); } +.list > li:first-child { border-top: 0; } +.list .grow { flex: 1; min-width: 0; } +.list .title { font-weight: 700; } +.list .sub { font-size: 12px; color: var(--text-2); } +.list .right { text-align: right; } +/* Colour and glyph come from lib/tokens.ts, so both interfaces draw an asset the same way. */ +.token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; line-height: 1; } +table { width: 100%; border-collapse: collapse; } +th, td { text-align: left; padding: 14px 24px; border-top: 1px solid var(--border); vertical-align: middle; } +thead th { border-top: 0; color: var(--text-2); font-weight: 500; font-size: 13px; } +tbody tr { transition: background 0.15s; } +tbody tr:hover { background: var(--panel-3); } +td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; } +.card:not(.flush) table th, .card:not(.flush) table td { padding-left: 0; padding-right: 0; } +.explore { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; } +.explore button { border: 1px solid var(--border); border-radius: 10px; background: var(--panel-3); color: var(--text); padding: 20px 16px; text-align: left; font-weight: 700; font-size: 15px; cursor: pointer; display: flex; flex-direction: column; gap: 20px; transition: transform 0.25s var(--ease), border-color 0.25s, box-shadow 0.25s; } +.explore button:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow-2); } +.explore .ico { width: 56px; height: 56px; color: var(--text); transition: transform 0.3s var(--ease); } +[data-theme="dark"] .explore .ico { color: var(--accent); } +.explore button { position: relative; overflow: hidden; } +.explore button::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 0.3s var(--ease); } +.explore button:hover::after { transform: scaleX(1); } +.explore button:hover .ico { transform: scale(1.08) rotate(-4deg); } + +/* ================================================================== pills */ +.pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 6px; font-size: 12px; font-weight: 700; white-space: nowrap; } +.pill-neutral { background: var(--panel-2); color: var(--text-2); } +.pill-ok { background: var(--success-bg); color: var(--success-text); } +.pill-warn { background: var(--warning-bg); color: var(--warning-text); } +.pill-bad { background: var(--error-bg); color: var(--error-text); } +.pill-info { background: var(--info-bg); color: var(--info-text); } +.pill-review { background: var(--review-bg); color: var(--review); } +[data-theme="light"] .pill-review, :root:not([data-theme="dark"]) .pill-review { color: #7a5c00; } +.pill-brand { background: var(--accent); color: var(--accent-contrast); } +.pill svg { width: 12px; height: 12px; } + +/* ================================================================== tabs */ +.tabs { display: flex; gap: 8px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; } +.tabs button { background: none; border: 0; padding: 10px 16px; font-size: 14px; font-weight: 700; cursor: pointer; color: var(--text-2); border-bottom: 2px solid transparent; margin-bottom: -1px; display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; transition: color 0.15s, border-color 0.15s; } +.tabs button:hover { color: var(--text); } +.tabs button.active { color: var(--text); border-bottom-color: var(--accent); } +.tabs-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; border-bottom: 1px solid var(--border); margin-bottom: 20px; } +.tabs-row .tabs { margin-bottom: 0; border-bottom: 0; } + +/* ================================================================== transactions */ +.date-label { font-size: 12px; font-weight: 500; color: var(--text-2); letter-spacing: 0.06em; text-transform: uppercase; margin: 20px 0 10px; } +.txcard { background: var(--panel); border-radius: 10px; margin-bottom: 8px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) both; } +.txcard .row { display: grid; grid-template-columns: 24px minmax(120px, 1fr) minmax(0, 1.4fr) 110px auto 24px; align-items: center; gap: 16px; padding: 18px 20px; cursor: pointer; border-radius: 10px; transition: background 0.15s; } +.txcard .row:hover { background: var(--panel-3); } +.txcard .kind { font-weight: 600; } +.txcard .amt { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; } +.txcard .when { color: var(--text-2); font-size: 13px; } +.txcard .status { text-align: right; font-weight: 700; } +.status-success { color: var(--success); } +.status-cancel { color: var(--text-2); } +.status-veto { color: var(--error); } +.txcard .detail { padding: 8px 20px 20px 60px; border-top: 1px solid var(--border); display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr); gap: 24px; animation: rise 0.3s var(--ease); } +@media (max-width: 900px) { .txcard .row { grid-template-columns: 24px 1fr auto 24px; } .txcard .hide-sm { display: none; } .txcard .detail { grid-template-columns: 1fr; padding-left: 20px; } } +.chev { transition: transform 0.2s var(--ease); color: var(--text-2); } +.chev.open { transform: rotate(180deg); } +.timeline { list-style: none; margin: 0; padding: 0; } +.timeline li { position: relative; padding: 0 0 16px 24px; } +.timeline li::before { content: ""; position: absolute; left: 4px; top: 5px; width: 10px; height: 10px; border-radius: 50%; background: var(--border-2); transition: background 0.3s; } +.timeline li.done::before { background: var(--accent); } +.timeline li.active::before { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-bg); animation: pulse-ring 2s ease-out infinite; } +.timeline li:not(:last-child)::after { content: ""; position: absolute; left: 8px; top: 16px; bottom: 0; width: 2px; background: var(--border); } +.timeline .t-title { font-weight: 700; } +.timeline .t-sub { font-size: 12px; color: var(--text-2); } +.timeline .signers { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; font-size: 12px; } +.tx-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; } +.empty-illus { padding: 64px 24px; text-align: center; color: var(--text-2); animation: fade 0.5s var(--ease); } +.empty-illus .glyph { width: 96px; height: 96px; border-radius: 50%; background: var(--panel-2); display: grid; place-items: center; margin: 0 auto 16px; color: var(--accent); animation: float 4s ease-in-out infinite; } + +/* ================================================================== sections (settings-style) */ +.section { background: var(--panel); border-radius: 10px; padding: 28px 32px; margin-bottom: 20px; display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 24px; box-shadow: var(--shadow-1); } +.section > h3 { font-size: 20px; } +.section > h3 small { display: block; font-size: 13px; font-weight: 400; color: var(--text-2); margin-top: 6px; line-height: 18px; } +.section .body { min-width: 0; } +.section .body h4 { margin-bottom: 8px; } +.section .body p.desc { color: var(--text-2); margin-bottom: 16px; font-size: 15px; } +@media (max-width: 860px) { .section { grid-template-columns: 1fr; } } +.member-row { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-top: 1px solid var(--border); } +.member-row:first-of-type { border-top: 0; } +.member-row .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 13px; } +.member-row .addr b { font-family: "DM Sans", sans-serif; font-weight: 700; } +.member-row .roles { display: flex; gap: 6px; flex-wrap: wrap; } +.member-row .tools { margin-left: auto; display: flex; gap: 4px; } +.kv { display: grid; grid-template-columns: 1fr; margin: 0; } +.kv div { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px; } +.kv div:first-child { border-top: 0; } +.kv dt { color: var(--text-2); } +.kv dd { margin: 0; text-align: right; font-weight: 500; } +.addr { display: inline-flex; align-items: center; gap: 6px; color: var(--text); } +.addr code { font-size: 12.5px; } +.addr:hover code { text-decoration: underline; } + +/* policy editor controls */ +.pfield { display: grid; grid-template-columns: minmax(0, 1fr) 160px; gap: 16px; align-items: center; padding: 14px 0; border-top: 1px solid var(--border); } +.pfield:first-child { border-top: 0; } +.pfield .lbl { font-weight: 600; } +.pfield .hint { font-size: 12px; color: var(--text-2); margin-top: 2px; } +.pfield input, .pfield select { height: 40px; } +.pfield .unit { display: flex; align-items: center; gap: 8px; } +.pfield .unit span { color: var(--text-2); font-size: 12px; white-space: nowrap; } +.pfield.changed .lbl::after { content: " •"; color: var(--warning); } +.stepper { display: inline-flex; align-items: center; border: 1px solid var(--border-2); border-radius: 8px; overflow: hidden; height: 40px; } +.stepper button { width: 36px; height: 100%; border: 0; background: var(--panel-2); color: var(--text); cursor: pointer; font-size: 16px; } +.stepper button:hover { background: var(--brand-bg-2); } +.stepper input { border: 0; width: 64px; text-align: center; height: 100%; border-radius: 0; } +.mode-hero { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } +.mode-hero > div { border: 1px solid var(--border); border-radius: 10px; padding: 18px; position: relative; transition: border-color 0.25s, transform 0.25s var(--ease); } +.mode-hero > div.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); transform: translateY(-2px); } +.mode-hero .m { font-size: 18px; font-weight: 800; margin-bottom: 4px; } +.mode-hero .d { color: var(--text-2); font-size: 13px; } +.mode-hero .cur { position: absolute; top: 12px; right: 12px; } +@media (max-width: 860px) { .mode-hero { grid-template-columns: 1fr; } } +.gauge { display: flex; align-items: center; gap: 16px; } +.gauge .ring { width: 72px; height: 72px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 18px; background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--panel-2) 0); position: relative; } +.gauge .ring::after { content: ""; position: absolute; inset: 8px; border-radius: 50%; background: var(--panel); } +.gauge .ring span { position: relative; z-index: 1; font-size: 15px; } +.scorecard { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; } +.scorecard > div { background: var(--panel); border-radius: 10px; padding: 16px 18px; box-shadow: var(--shadow-1); } +.scorecard .v { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } +.scorecard .l { font-size: 12px; color: var(--text-2); } + +/* ================================================================== forms */ +.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } +.field-label { font-size: 14px; font-weight: 700; } +.field-hint { font-size: 12px; color: var(--text-2); } +input, select, textarea { height: 48px; padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--panel); color: var(--text); width: 100%; font-size: 14px; transition: border-color 0.15s, box-shadow 0.15s; } +select option { background: var(--panel); color: var(--text); } +input[type="checkbox"] { height: auto; width: auto; accent-color: var(--accent); } +input[type="range"] { height: auto; padding: 0; border: 0; accent-color: var(--accent); } +input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } +input:read-only { color: var(--text-2); } +.row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; } +.row > .field { flex: 1; min-width: 180px; } +.inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } +.stack { display: flex; flex-direction: column; gap: 8px; } +.notice { padding: 14px 16px; border-radius: var(--radius-sm); margin: 12px 0; font-size: 14px; display: flex; gap: 10px; align-items: flex-start; animation: rise 0.3s var(--ease); } +.notice-ok { background: var(--success-bg); color: var(--success-text); } +.notice-bad { background: var(--error-bg); color: var(--error-text); } +.notice-warn { background: var(--warning-bg); color: var(--warning-text); } +.notice-info { background: var(--info-bg); color: var(--info-text); } +.empty { padding: 40px 24px; text-align: center; color: var(--text-2); } +.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; } +.switch .track { width: 40px; height: 22px; border-radius: 999px; background: var(--border-2); position: relative; transition: background 0.2s; } +.switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform 0.2s var(--ease); } +.switch.on .track { background: var(--accent); } +.switch.on .track::after { transform: translateX(18px); } +.segmented { display: inline-flex; padding: 4px; border-radius: 999px; background: var(--panel); gap: 4px; box-shadow: var(--shadow-1); } +.segmented button { border: 0; background: transparent; color: var(--text-2); font-weight: 700; padding: 10px 28px; border-radius: 999px; cursor: pointer; transition: background 0.2s, color 0.2s; } +.segmented button.active { background: var(--brand); color: var(--brand-contrast); } +.review { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel-3); padding: 4px 16px; } +.review-line { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); } +.review-line:first-child { border-top: 0; } +.review-line > span:first-child { color: var(--text-2); flex: none; } +.review-line > *:last-child { text-align: right; } +.reasons { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } +.bar { height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden; margin-top: 8px; } +.bar > i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: grow 0.8s var(--ease); } +.bar.warn > i { background: var(--warning); } +.bar.bad > i { background: var(--error); } +.templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; } +.template { border: 1px solid var(--border); border-radius: 10px; padding: 16px; cursor: pointer; background: var(--panel-3); text-align: left; color: var(--text); transition: border-color 0.2s, transform 0.2s var(--ease), box-shadow 0.2s; } +.template:hover { border-color: var(--border-2); transform: translateY(-2px); } +.template.active { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 3px var(--accent-soft); } +.template strong { display: block; margin-bottom: 4px; } +.scenario { border-radius: 10px; padding: 20px 24px; margin-bottom: 12px; background: var(--panel); border-left: 4px solid var(--border-2); box-shadow: var(--shadow-1); transition: transform 0.25s var(--ease), box-shadow 0.25s; } +.scenario:hover { transform: translateX(4px); box-shadow: var(--shadow-2); } +.scenario.blocked, .scenario.impossible { border-left-color: var(--success); } +.scenario.delayed { border-left-color: var(--info); } +.scenario.escalated { border-left-color: var(--warning); } +.scenario.allowed { border-left-color: var(--error); } +.scenario ul { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } +.posture { list-style: none; margin: 0; padding: 0; } +.posture li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; } +.posture .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-3); } +.posture .dot.ok { background: var(--success); } +.posture .dot.warn { background: var(--warning); } +.posture .dot.bad { background: var(--error); } +.assumptions { font-size: 12px; color: var(--text-2); margin: 12px 0 0; padding-left: 18px; } + +/* modal */ +.modal-backdrop { position: fixed; inset: 0; background: rgba(33, 37, 41, 0.55); backdrop-filter: blur(4px); z-index: 50; display: flex; align-items: flex-start; justify-content: center; padding: 48px 16px; overflow-y: auto; animation: fade 0.2s var(--ease); } +.modal { width: 100%; max-width: 640px; background: var(--panel); border-radius: 14px; box-shadow: 0 24px 64px rgba(0,0,0,0.35); animation: pop 0.3s var(--ease); } +.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px; border-bottom: 1px solid var(--border); } +.modal-body { padding: 24px; } +.modal-foot { display: flex; justify-content: space-between; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--border); } +.steps { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--text-2); } +.steps .step { display: inline-flex; align-items: center; gap: 6px; } +.steps .n { width: 20px; height: 20px; border-radius: 50%; display: inline-grid; place-items: center; background: var(--panel-2); font-weight: 700; font-size: 11px; transition: background 0.2s, color 0.2s; } +.steps .step.on .n { background: var(--accent); color: var(--accent-contrast); } +.steps .step.on { color: var(--text); font-weight: 700; } + +/* ================================================================== welcome / create */ +.entry { min-height: 100vh; background: radial-gradient(60% 40% at 50% 28%, var(--panel-2) 0%, var(--canvas) 60%); display: flex; flex-direction: column; } +.entry-top { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; animation: fade 0.4s var(--ease); } +.entry-top .logo { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 18px; } +.entry-top .logo .mark { width: 28px; height: 28px; border-radius: 7px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; } +.entry-center { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 40px 16px; gap: 16px; } +.entry-card { width: 100%; max-width: 440px; background: var(--panel); border-radius: 16px; padding: 32px; text-align: center; box-shadow: var(--shadow-2); animation: pop 0.45s var(--ease) both; } +.entry-card h2 { font-size: 24px; margin: 12px 0 8px; } +.entry-card p { color: var(--text-2); margin-bottom: 20px; } +.entry-card .or { display: flex; align-items: center; gap: 12px; color: var(--text-2); font-size: 12px; margin: 16px 0; } +.entry-card .or::before, .entry-card .or::after { content: ""; flex: 1; height: 1px; background: var(--border-2); } +.entry-note { max-width: 440px; width: 100%; background: var(--panel); border-radius: 10px; padding: 10px 16px; display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 14px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) 0.1s both; } +.entry-foot { display: flex; gap: 16px; justify-content: center; padding: 24px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; } +.entry-foot a { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } +[data-theme="dark"] .entry-foot a { color: var(--accent); box-shadow: none; } +.wordmark-lg { font-size: 28px; font-weight: 800; letter-spacing: -0.02em; display: inline-flex; align-items: center; gap: 10px; justify-content: center; } +.wordmark-lg .brace { color: var(--text-2); font-weight: 500; } +.create { max-width: 1160px; margin: 0 auto; padding: 24px; } +.create-grid { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 24px; align-items: start; } +@media (max-width: 960px) { .create-grid { grid-template-columns: 1fr; } } +.stepcard { background: var(--panel); border-radius: 10px; overflow: hidden; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease); } +.stepcard .progress { height: 4px; background: var(--border); } +.stepcard .progress i { display: block; height: 100%; background: var(--accent); transition: width 0.5s var(--ease); } +.stepcard .step-head { display: flex; gap: 16px; align-items: flex-start; padding: 24px 28px; border-bottom: 1px solid var(--border); } +.stepcard .step-head .n { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 12px; flex: none; margin-top: 2px; } +.stepcard .step-head h3 { font-size: 20px; } +.stepcard .step-head p { color: var(--text-2); margin-top: 2px; } +.stepcard .step-body { padding: 28px; animation: fade 0.3s var(--ease); } +.stepcard .step-foot { display: flex; justify-content: space-between; padding: 20px 28px; border-top: 1px solid var(--border); } +.preview { background: var(--panel); border-radius: 10px; padding: 24px; text-align: center; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease) 0.1s both; position: sticky; top: 24px; } +.preview h4 { font-size: 18px; margin: 8px 0 16px; } +.preview .kv div { text-align: left; } + +/* ================================================================== marketing site (safe.global) */ +.land { --lt: #212529; --ls: #6c757d; font-size: 16px; line-height: 24px; color: #212529; background: #fff; overflow-x: hidden; } +.land .wrap { max-width: 1216px; margin: 0 auto; padding: 0 24px; } +.land-nav { position: sticky; top: 0; z-index: 30; background: rgba(255,255,255,0.85); backdrop-filter: blur(12px); border-bottom: 1px solid transparent; transition: border-color 0.2s, box-shadow 0.2s; } +.land-nav.scrolled { border-bottom-color: #e9ecef; box-shadow: 0 4px 24px rgba(33,37,41,0.06); } +.land-nav .nav-right { display: flex; align-items: center; gap: 14px; } +.netchip { display: inline-flex; align-items: center; gap: 8px; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #6c757d; border: 1px solid #dee2e6; padding: 7px 10px; border-radius: 4px; } +.netchip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #ffd000; box-shadow: 0 0 0 3px rgba(255,208,0,0.25); } +.land-nav .wrap { height: 72px; display: flex; align-items: center; justify-content: space-between; gap: 24px; } +.land-nav .logo { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 22px; letter-spacing: -0.02em; font-family: "Space Grotesk", sans-serif; } +.land-nav .logo .mark { width: 28px; height: 28px; border-radius: 4px; background: #ffd000; color: #212529; display: grid; place-items: center; font-weight: 800; font-size: 14px; } +.land-nav .logo .brace { color: #6c757d; font-weight: 500; } +.land-nav nav { display: flex; gap: 32px; } +.land-nav nav a { color: #6c757d; font-weight: 500; position: relative; z-index: 0; transition: color 0.15s; } +.land-nav nav a::after { content: ""; position: absolute; left: -4px; right: -4px; bottom: 1px; height: 9px; z-index: -1; background: #ffd000; transform: scaleX(0); transform-origin: left; transition: transform 0.25s var(--ease); } +.land-nav nav a:hover, .land-nav nav a.on { color: #212529; } +.land-nav nav a:hover::after, .land-nav nav a.on::after { transform: scaleX(1); } +.land .announce { background: #212529; color: #fff; text-align: center; padding: 12px 24px; font-size: 14px; } +.land .announce a { font-weight: 500; } +.land .announce a span { color: #ffd000; } +.land .announce a span { display: inline-block; transition: transform 0.2s var(--ease); } +.land .announce a:hover span { transform: translateX(4px); } +.hero { position: relative; overflow: hidden; background: #f8f9fa; padding: 104px 0 0; text-align: center; } +.hero.sub-hero { padding: 88px 0 72px; } +.hero .grid-bg { position: absolute; inset: 0; background-image: linear-gradient(#e9ecef 1px, transparent 1px), linear-gradient(90deg, #e9ecef 1px, transparent 1px); background-size: 131px 131px; } +.hero .cell { position: absolute; width: 130px; height: 130px; background: linear-gradient(180deg, rgba(255,208,0,0) 0%, rgba(255,208,0,0.55) 100%); animation: cell 6s ease-in-out infinite; } +.hero .wrap { position: relative; } +.hero .eyebrow { font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 24px; animation: rise 0.6s var(--ease) both; display: flex; align-items: center; justify-content: center; gap: 12px; } +.hero .eyebrow b { background: #ffd000; color: #212529; padding: 3px 7px; font-weight: 500; } +.hero h1 { font-size: 84px; line-height: 84px; letter-spacing: -0.035em; font-weight: 700; max-width: 960px; margin: 0 auto 24px; animation: rise 0.7s var(--ease) 0.08s both; } +.hero h1 .w { display: inline-block; } +.hero .sub { font-size: 19px; line-height: 28px; color: #6c757d; max-width: 600px; margin: 0 auto 32px; animation: rise 0.7s var(--ease) 0.18s both; } +.hero .cta-row { animation: rise 0.7s var(--ease) 0.26s both; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } +.hero .mockwrap { position: relative; max-width: 960px; margin: 72px auto 0; text-align: left; animation: rise 0.9s var(--ease) 0.35s both; } +.hero .mock { border-radius: 8px 8px 0 0; box-shadow: 0 -8px 60px rgba(33,37,41,0.18); overflow: hidden; border: 1px solid #dee2e6; border-bottom: 0; } +.hero .float { position: absolute; right: -56px; bottom: 36px; width: 400px; animation: rise 0.9s var(--ease) 0.7s both; } +.hero .float .ticker { box-shadow: 0 30px 80px rgba(33,37,41,0.35), 0 0 0 1px rgba(255,255,255,0.06); } +@media (max-width: 1120px) { .hero .float { position: static; width: auto; margin: 24px 0 0; } .hero .mock { border-bottom: 1px solid #dee2e6; border-radius: 8px; } } +@media (max-width: 900px) { .hero h1 { font-size: 48px; line-height: 50px; } } +.land .light { background: #f8f9fa; padding: 96px 0; } +.land .white { background: #fff; padding: 96px 0; } +.land .dark { background: #212529; color: #fff; padding: 96px 0; } +.land h2 { font-size: 44px; line-height: 48px; letter-spacing: -0.03em; text-align: left; margin-bottom: 12px; font-weight: 700; max-width: 760px; } +.land .lead { text-align: left; color: #adb5bd; font-size: 17px; max-width: 640px; margin: 0 0 56px; } +.land .center h2, .land .center .lead { text-align: center; margin-left: auto; margin-right: auto; } +.land .light .lead, .land .white .lead { color: #6c757d; } +.marquee { overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); } +.marquee .track { display: flex; gap: 12px; width: max-content; animation: marquee 28s linear infinite; } +.marquee .track:hover { animation-play-state: paused; } +.marquee .chip-l { padding: 12px 22px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; border: 1px solid #dee2e6; background: #fff; font-weight: 600; white-space: nowrap; color: #212529; } +.bento { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } +.bento .big { grid-column: 1 / -1; } +.bcard { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 32px; min-height: 340px; background-image: radial-gradient(60% 40% at 50% 0%, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 100%); transition: transform 0.35s var(--ease), border-color 0.35s, box-shadow 0.35s; } +.bcard:hover { transform: translateY(-4px); border-color: #ffd000; box-shadow: 0 24px 60px rgba(0,0,0,0.35); } +.bcard h3 { font-size: 24px; margin-bottom: 8px; } +.bcard p { color: #adb5bd; margin-bottom: 24px; } +.bcard.center { text-align: center; } +.bcard .art { margin-top: 8px; } +@media (max-width: 860px) { .bento { grid-template-columns: 1fr; } } +.dashed { display: grid; grid-template-columns: 1fr 1fr; max-width: 900px; margin: 0 auto; } +.dashed > div { padding: 40px 32px 40px 48px; border-left: 1px dashed #495057; border-top: 1px dashed #495057; } +.dashed > div:nth-child(-n+2) { border-top: 0; } +.dashed > div:nth-child(odd) { border-left: 0; } +.dashed h4 { font-size: 18px; margin-bottom: 8px; } +.dashed p { color: #adb5bd; } +.badges { display: flex; gap: 40px; justify-content: center; align-items: center; flex-wrap: wrap; padding: 40px 0; border-top: 1px solid #343a40; color: #adb5bd; font-weight: 700; font-size: 18px; } +.badges .lbl { font-weight: 400; font-size: 14px; } +.shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; } +.shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; } +.shield p { color: #adb5bd; margin-bottom: 32px; max-width: 320px; } +.shield ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; font-size: 20px; font-weight: 700; } +.shield ul li { display: flex; gap: 12px; align-items: center; } +.shield ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 26px; height: 26px; } +.shield .tilt { transform: perspective(1200px) rotateY(-12deg) rotateX(4deg) rotate(6deg) scale(1.05); transform-origin: left center; border-radius: 10px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,0.5); transition: transform 0.6s var(--ease); } +.shield:hover .tilt { transform: perspective(1200px) rotateY(-6deg) rotateX(2deg) rotate(3deg) scale(1.03); } +@media (max-width: 900px) { .shield { grid-template-columns: 1fr; } .shield .tilt { transform: none; } } +.compare { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 12px; max-width: 1000px; margin: 0 auto; overflow-x: auto; } +.compare table { border-collapse: separate; border-spacing: 8px 0; } +.compare th, .compare td { border: 0; padding: 20px 20px; vertical-align: top; background: #343a40; border-radius: 0; font-size: 15px; color: #adb5bd; } +.compare th { font-weight: 500; font-size: 16px; } +.compare td:first-child { color: #fff; font-weight: 500; } +.compare .hl { background: #ffd000; color: #212529 !important; font-weight: 700; } +.compare th.hl { border-radius: 8px 8px 0 0; } +.compare tr:last-child td.hl { border-radius: 0 0 8px 8px; } +.quote { text-align: center; max-width: 960px; margin: 0 auto; } +.quote blockquote { font-size: 36px; line-height: 44px; font-style: italic; color: #dee2e6; margin: 0 0 32px; font-weight: 400; letter-spacing: -0.01em; } +.quote cite { font-style: normal; font-weight: 700; font-size: 20px; } +.stats { display: flex; gap: 96px; justify-content: center; flex-wrap: wrap; margin-top: 56px; } +.stats .v { font-size: 64px; line-height: 68px; color: #ffd000; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; } +.stats .l { color: #adb5bd; margin-top: 8px; font-size: 14px; } +.audiences { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; } +.acard { background: #212529; color: #fff; border-radius: 8px; padding: 28px; min-height: 420px; transition: transform 0.35s var(--ease), box-shadow 0.35s; } +.acard:hover { transform: translateY(-4px); box-shadow: 0 24px 60px rgba(33,37,41,0.3); } +.acard h3 { font-size: 22px; margin-bottom: 8px; } +.acard p { color: #adb5bd; margin-bottom: 20px; max-width: 320px; } +.acard a, .acard .link { color: #ffd000; font-weight: 700; } +.acard .art { margin-top: 24px; } +@media (max-width: 860px) { .audiences { grid-template-columns: 1fr; } } +.steps4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } +.steps4 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } +.steps4 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } +.steps4 .n { width: 32px; height: 32px; border-radius: 4px; background: #ffd000; color: #212529; font-family: "DM Mono", monospace; display: grid; place-items: center; font-weight: 800; margin-bottom: 20px; } +.steps4 h4 { font-size: 18px; margin-bottom: 8px; } +.steps4 p { color: #6c757d; } +@media (max-width: 900px) { .steps4 { grid-template-columns: 1fr 1fr; } } +.feat6 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } +.feat6 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } +.feat6 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } +.feat6 .ico { width: 44px; height: 44px; border-radius: 10px; background: #212529; color: #fff; display: grid; place-items: center; margin-bottom: 20px; } +.feat6 h4 { font-size: 18px; margin-bottom: 8px; } +.feat6 p { color: #6c757d; } +.dark .feat6 > div { background: #2b3035; border-color: #343a40; } +.dark .feat6 .ico { background: #ffd000; color: #212529; } +.dark .feat6 p { color: #adb5bd; } +@media (max-width: 900px) { .feat6 { grid-template-columns: 1fr; } } +.faq { max-width: 770px; margin: 0 auto; } +.faq details { border-bottom: 1px solid #e9ecef; } +.faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 20px 0; font-weight: 700; font-size: 17px; } +.faq summary::-webkit-details-marker { display: none; } +.faq summary .plus { width: 24px; height: 24px; border-radius: 4px; border: 1.5px solid #6c757d; display: grid; place-items: center; color: #6c757d; font-weight: 400; transition: transform 0.3s var(--ease), background 0.2s, color 0.2s; } +.faq details[open] summary .plus { transform: rotate(45deg); background: #ffd000; color: #212529; border-color: #ffd000; } +.faq .ans { padding: 0 0 20px; color: #6c757d; max-width: 680px; animation: rise 0.3s var(--ease); } +.cta { position: relative; overflow: hidden; background: #fff; background-image: radial-gradient(#d9dde2 1.2px, transparent 1.2px); background-size: 26px 26px; padding: 120px 0; text-align: center; } +.cta h2 { font-size: 56px; line-height: 60px; text-align: center; margin: 0 auto 12px; } +.cta h2 span { color: #6c757d; } +.cta .sub { color: #6c757d; font-size: 18px; margin: 20px 0 32px; } +.land-footer { background: #212529; color: #fff; padding: 72px 0 0; overflow: hidden; } +.land-footer .cols { display: grid; grid-template-columns: 2fr repeat(5, 1fr); gap: 24px; padding-bottom: 56px; border-bottom: 1px solid #343a40; } +.land-footer h5 { margin: 0 0 16px; font-size: 14px; color: #adb5bd; font-weight: 700; } +.land-footer ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; font-size: 15px; } +.land-footer ul a { transition: color 0.15s; } +.land-footer ul a:hover { color: #adb5bd; } +.land-footer .legal { display: flex; justify-content: space-between; padding: 32px 0; color: #6c757d; font-size: 14px; } +.land-footer .giant { font-size: 30vw; line-height: 0.8; font-weight: 800; letter-spacing: -0.05em; color: transparent; -webkit-text-stroke: 1.5px #ffd000; text-align: left; margin-top: 24px; user-select: none; } +@media (max-width: 900px) { .land-footer .cols { grid-template-columns: 1fr 1fr; } .land-nav nav { display: none; } } + +/* mini app mockup used on the marketing pages */ +.mock-app { background: #212529; color: #fff; font-size: 12px; display: grid; grid-template-columns: 180px 1fr; min-height: 420px; } +.mock-app .sb { background: #2b3035; padding: 12px; border-right: 1px solid #343a40; } +.mock-app .sb .pill { height: 26px; border-radius: 4px; background: #3d3400; padding: 0 10px; font-weight: 700; margin-bottom: 8px; } +.mock-app .sb .ntx { border: 1px solid #6c757d; border-radius: 6px; padding: 6px; color: #adb5bd; text-align: center; margin-bottom: 12px; } +.mock-app .sb .it { padding: 6px 8px; color: #fff; border-radius: 6px; } +.mock-app .sb .it.on { background: #3d3400; font-weight: 700; } +.mock-app .ct { padding: 14px; display: grid; gap: 12px; grid-template-columns: 1.7fr 1fr; align-items: start; } +.mock-app .acct { grid-column: 1 / -1; background: #2b3035; border-radius: 10px; padding: 8px 12px; display: flex; align-items: center; gap: 10px; } +.mock-app .pn { background: #2b3035; border-radius: 10px; padding: 14px; } +.mock-app .big { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } +.mock-app .big span { color: #6c757d; } +.mock-app .mb { display: inline-block; background: #343a40; border-radius: 6px; padding: 4px 10px; margin-right: 6px; margin-top: 8px; } +.mock-app .li { display: flex; justify-content: space-between; padding: 8px 0; border-top: 1px solid #343a40; } +.mock-app .ok { color: #75b798; font-weight: 700; } +.mock-app .rv { color: #ffcd39; font-weight: 700; } +.mock-app .ident { width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(#ffd000, #6c757d, #adb5bd, #ffd000); } + +@media (max-width: 860px) { + .shell { flex-direction: column; } + .sidebar { width: auto; height: auto; position: static; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px 12px; } + .newtx { margin: 0; flex: 1 1 100%; } + .nav { flex-direction: row; flex-wrap: wrap; } + .nav button.active::before { display: none; } + .nav-group, .sidebar-bottom { display: none; } + .main { padding: 16px; } +} + +/* ================================================================== identity: tape, section index, marker, live scorer, mode strip */ +.tape { height: 10px; background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } +.tape.thin { height: 6px; } +.tape.run { animation: tape 0.9s linear infinite; } +@keyframes tape { to { background-position: 45.25px 0; } } +.secno { display: flex; align-items: center; gap: 12px; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 18px; } +.secno::before { content: ""; width: 28px; height: 3px; background: #ffd000; flex: none; } +.dark .secno { color: #adb5bd; } +.mark-hl { background-image: linear-gradient(180deg, transparent 60%, #ffd000 60%, #ffd000 92%, transparent 92%); background-repeat: no-repeat; background-size: 0% 100%; -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: hlin 0.8s var(--ease) 0.7s forwards; } +@keyframes hlin { to { background-size: 100% 100%; } } +.hero-meta { margin-top: 32px; display: flex; gap: 24px; flex-wrap: wrap; justify-content: center; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: #6c757d; animation: rise 0.7s var(--ease) 0.4s both; } +.hero-meta span { display: inline-flex; align-items: center; gap: 8px; } +.hero-meta span::before { content: ""; width: 8px; height: 3px; background: #ffd000; } + +.ticker { background: #212529; color: #fff; border-radius: 8px; box-shadow: 0 30px 80px rgba(33,37,41,0.28); overflow: hidden; font-size: 14px; } +.ticker .head { display: flex; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #343a40; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #adb5bd; } +.ticker .head b { color: #ffd000; font-weight: 500; } +.ticker .body { padding: 20px 18px 16px; display: grid; gap: 14px; } +.ticker .row { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; } +.ticker .row > span:first-child { color: #adb5bd; font-size: 13px; } +.ticker .amt { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.02em; } +.ticker .to { font-family: "DM Mono", monospace; font-size: 12.5px; color: #dee2e6; } +.ticker .prog { height: 6px; background: #343a40; border-radius: 3px; overflow: hidden; } +.ticker .prog i { display: block; height: 100%; background: #ffd000; width: 0; } +.ticker .prog.on i { animation: growx 1.1s var(--ease) both; } +.ticker .prog.done i { width: 100%; } +@keyframes growx { from { width: 0; } to { width: 100%; } } +.ticker .verdict { display: flex; align-items: center; gap: 10px; min-height: 34px; flex-wrap: wrap; } +.ticker .tier { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; padding: 7px 10px; border-radius: 4px; font-weight: 500; color: #212529; animation: pop 0.3s var(--ease) both; } +.ticker .tier.low { background: #ffd000; } +.ticker .tier.high { background: #ffa94d; } +.ticker .tier.critical { background: #ea868f; } +.ticker .tier.blocked { background: #fff; } +.ticker .scoring { color: #adb5bd; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; } +.ticker .why { list-style: none; padding: 0; margin: 0; display: grid; gap: 7px; color: #dee2e6; font-size: 13px; min-height: 66px; } +.ticker .why li { animation: rise 0.4s var(--ease) both; padding-left: 18px; position: relative; } +.ticker .why li::before { content: ""; position: absolute; left: 0; top: 8px; width: 9px; height: 3px; background: #ffd000; } +.ticker .foot { padding: 12px 18px; border-top: 1px solid #343a40; font-size: 12px; color: #adb5bd; display: flex; justify-content: space-between; gap: 12px; } +.ticker .dots { display: flex; gap: 6px; } +.ticker .dots i { width: 18px; height: 3px; background: #495057; } +.ticker .dots i.on { background: #ffd000; } +.mode-strip { height: 6px; margin: -20px -24px 16px; background: transparent; transition: background 0.3s; } +.mode-strip.elevated { background: #ffd000; } +.mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } +@media (prefers-reduced-motion: reduce) { .tape.run, .mark-hl, .ticker .prog.on i, .ticker .why li, .ticker .tier { animation: none; } .mark-hl { background-size: 100% 100%; } .ticker .prog.on i { width: 100%; } } + +/* ================================================================== phone mockups (marketing) + Authored at true device scale (393 x 852 points) and scaled as a unit, so the app's own type sizes + and spacing survive. --pwn is unitless: calc() dividing two lengths yields a length, which scale() + would reject. */ +.phone { --pwn: 268; --scale: calc(var(--pwn) / 417); position: relative; width: calc(var(--pwn) * 1px); height: calc(876px * var(--scale)); flex: none; } +.phone-device { position: absolute; top: 0; left: 0; width: 417px; height: 876px; transform: scale(var(--scale)); transform-origin: top left; background: #0b0d10; border-radius: 58px; padding: 12px; box-shadow: 0 40px 90px rgba(16,20,24,0.3), 0 0 0 1px rgba(255,255,255,0.08) inset; } +.ph-island { position: absolute; top: 24px; left: 50%; transform: translateX(-50%); width: 122px; height: 35px; background: #0b0d10; border-radius: 20px; z-index: 3; } +.phone-screen { position: relative; width: 100%; height: 100%; border-radius: 46px; background: #fff; overflow: hidden; display: flex; flex-direction: column; color: #101418; font-size: 15px; } +.ph-home-ind { position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%); width: 140px; height: 5px; border-radius: 3px; background: #101418; opacity: 0.85; } +.ph-status { height: 56px; padding: 16px 30px 0; display: flex; align-items: center; justify-content: space-between; font-size: 16px; } +.ph-status b { font-family: "DM Sans", sans-serif; font-weight: 700; letter-spacing: -0.2px; } +.ph-status-icons { display: flex; align-items: center; gap: 6px; fill: #101418; color: #101418; } +.ph-body { flex: 1; padding: 6px 16px 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; } + +.ph-top { display: flex; align-items: center; gap: 10px; height: 44px; } +.ph-top > b { font-size: 17px; font-weight: 700; } +.ph-ident { position: relative; width: 36px; height: 36px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #7dd3fc, #2ec27e); flex: none; } +.ph-ident i { position: absolute; top: -6px; left: 16px; background: #ffd000; color: #101418; font-style: normal; font-size: 10px; font-weight: 800; border-radius: 8px; padding: 1px 5px; border: 2px solid #fff; } +.ph-caret { color: #98a2b3; font-size: 13px; } +.ph-caret.r { margin-left: auto; } +.ph-top-btns { margin-left: auto; display: flex; gap: 8px; } +.ph-top-btns i { width: 40px; height: 40px; border-radius: 50%; background: #f6f7f9; display: block; position: relative; } +.ph-top-btns i::before { content: ""; position: absolute; inset: 13px; border: 2px solid #101418; border-radius: 3px; -webkit-mask: linear-gradient(#000 0 0) top/100% 4px no-repeat, linear-gradient(#000 0 0) bottom/100% 4px no-repeat, linear-gradient(#000 0 0) left/4px 100% no-repeat, linear-gradient(#000 0 0) right/4px 100% no-repeat; } +.ph-top-btns i.bell::before { inset: 11px 13px 12px; border: 0; background: #101418; -webkit-mask: none; border-radius: 7px 7px 2px 2px; } +.ph-top-btns i.bell::after { content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px; border-radius: 50%; background: #ffd000; } +.ph-pending { display: flex; align-items: center; gap: 10px; background: #fff6cc; color: #8a6d00; border-radius: 14px; padding: 0 14px; height: 48px; font-weight: 700; font-size: 15px; } +.ph-pending .n { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 12px; } +.ph-chain { display: flex; align-items: center; gap: 8px; font-size: 14px; } +.ph-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-size: 13px; } +.ph-ark { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 11px; font-weight: 800; } +.ph-balance { font-family: "Space Grotesk", sans-serif; font-size: 44px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } +.ph-balance small { font-size: 20px; color: #667085; margin-left: 8px; letter-spacing: -0.02em; } +.ph-actions { display: flex; gap: 10px; } +.ph-actions span { flex: 1; height: 48px; display: grid; place-items: center; border-radius: 14px; background: #f6f7f9; font-weight: 700; font-size: 15px; } +.ph-actions .go { background: #ffd000; } +.ph-label { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 4px; } +.ph-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #eceef2; } +.ph-row.last, .ph-card .ph-row:last-child { border-bottom: 0; } +.ph-card { background: #f6f7f9; border-radius: 16px; padding: 0 14px; } +.ph-card.pad { padding: 4px 14px; } +.ph-mark, .ph-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } +.ph-circle { width: 40px; height: 40px; background: #eceef2; font-size: 16px; } +.ph-circle.sm { width: 34px; height: 34px; font-size: 15px; } +.ph-name { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } +.ph-name b { font-size: 15px; font-weight: 700; } +.ph-name small { font-size: 13px; color: #667085; } +.ph-amt { font-size: 15px; font-weight: 700; } +.ph-badge { background: #eceef2; color: #667085; border-radius: 99px; padding: 4px 9px; font-weight: 700; font-size: 12px; } +.ph-badge.warn { background: #fff3d6; color: #a86a00; } +.ph-title { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 700; display: flex; align-items: center; gap: 10px; height: 44px; } +.ph-title.back { font-size: 18px; } +.ph-title .ph-plus { margin-left: auto; width: 40px; height: 40px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 20px; } +.ph-tabsline { display: flex; gap: 22px; border-bottom: 1px solid #eceef2; font-size: 15px; } +.ph-tabsline b { border-bottom: 2px solid #ffd000; padding-bottom: 9px; } +.ph-tabsline span { color: #98a2b3; padding-bottom: 9px; } +.ph-chips { display: flex; gap: 8px; } +.ph-chips b, .ph-chips span { border-radius: 99px; padding: 6px 12px; font-size: 12px; font-weight: 700; background: #f6f7f9; color: #667085; } +.ph-chips b { background: #ffd000; color: #101418; } +.ph-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0 4px; } +.ph-hero-mark { position: relative; } +.ph-hero-mark i { position: absolute; right: -4px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #b42318; color: #fff; font-style: normal; font-size: 12px; display: grid; place-items: center; border: 3px solid #fff; } +.ph-hero b { font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -0.03em; } +.ph-hero small { color: #667085; font-size: 14px; } +.ph-kv { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eceef2; font-size: 14px; } +.ph-kv.last { border-bottom: 0; } +.ph-kv span { color: #667085; } +.ph-sign { margin-top: auto; margin-bottom: 12px; background: #ffd000; border-radius: 16px; height: 56px; padding: 0 18px; display: flex; align-items: center; gap: 10px; font-size: 16px; } +.ph-sign b { font-weight: 700; } +.ph-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 5px 10px; font-family: "DM Mono", monospace; font-size: 12px; } +.ph-tabs { height: 84px; border-top: 1px solid #eceef2; display: flex; align-items: flex-start; padding-top: 14px; } +.ph-tabs span { flex: 1; text-align: center; font-size: 24px; color: #98a2b3; position: relative; } +.ph-tabs span.on { color: #ffd000; } +.ph-tab-badge { position: absolute; top: -4px; left: 55%; background: #ffd000; color: #101418; font-style: normal; font-size: 11px; font-weight: 800; border-radius: 99px; padding: 1px 6px; } +.phones { display: flex; gap: 30px; justify-content: center; align-items: flex-start; flex-wrap: wrap; } +.phones .phone:nth-child(2) { margin-top: -26px; } +@media (max-width: 900px) { .phones .phone:nth-child(2) { margin-top: 0; } .phone { --pwn: 240; } } + +/* The landing's mobile strip: copy on the left, two phones on the right, the card sized by both. */ +.mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } +.mstrip h2 { text-align: left; margin-bottom: 16px; } +.mstrip p { color: #6c757d; max-width: 380px; margin-bottom: 26px; } +.mstrip ul { list-style: none; padding: 0; margin: 0 0 26px; display: flex; flex-direction: column; gap: 14px; font-size: 17px; font-weight: 700; color: #212529; } +.mstrip ul li { display: flex; gap: 12px; align-items: center; } +.mstrip ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 24px; height: 24px; flex: none; } +.phones.two { display: flex; gap: 16px; align-items: flex-start; } +.phones.two .phone { --pwn: 196; } +.phones.two .phone:nth-child(2) { margin-top: 30px; } +@media (max-width: 980px) { .mstrip { grid-template-columns: 1fr; } .phones.two { justify-content: center; } .phones.two .phone:nth-child(2) { display: none; } } + +/* ================================================================== documentation */ +.docs { max-width: 1216px; margin: 0 auto; padding: 0 24px; display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; align-items: start; } +.docs-nav { position: sticky; top: 96px; padding: 40px 0 60px; display: flex; flex-direction: column; gap: 22px; } +.docs-group { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 8px; } +.docs-nav button { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 7px 12px; margin-left: -12px; border-radius: 8px; font: inherit; font-size: 15px; color: #6c757d; cursor: pointer; } +.docs-nav button:hover { background: #f1f3f5; color: #212529; } +.docs-nav button.on { background: #fff6cc; color: #212529; font-weight: 700; } +.docs-body { padding: 40px 0 96px; min-width: 0; } +.docs-crumb { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 12px; } +.docs-body h1 { font-family: "Space Grotesk", sans-serif; font-size: 44px; line-height: 48px; letter-spacing: -0.03em; margin-bottom: 20px; } +.docs-body h3 { font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -0.02em; margin: 40px 0 10px; scroll-margin-top: 96px; } +.docs-body p { font-size: 17px; line-height: 27px; color: #495057; margin-bottom: 16px; max-width: 70ch; } +.docs-body .doc-lead { font-size: 20px; line-height: 30px; color: #212529; margin-bottom: 24px; } +.docs-body ul, .docs-body ol { margin: 0 0 20px 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 26px; color: #495057; max-width: 70ch; } +.docs-body li b { color: #212529; } +.docs-body ol.doc-inv { counter-reset: inv; list-style: none; margin-left: 0; } +.docs-body ol.doc-inv li { counter-increment: inv; padding-left: 40px; position: relative; color: #212529; font-weight: 500; } +.docs-body ol.doc-inv li::before { content: counter(inv); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; border-radius: 6px; background: #ffd000; color: #212529; display: grid; place-items: center; font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; } +.doc-note { border-left: 3px solid #ffd000; background: #fffdf2; padding: 14px 18px; border-radius: 0 8px 8px 0; font-size: 16px; line-height: 25px; color: #495057; margin: 22px 0; max-width: 70ch; } +.doc-table { overflow-x: auto; margin: 0 0 24px; } +.doc-table table { border-collapse: collapse; width: 100%; font-size: 15px; } +.doc-table th { text-align: left; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #98a2b3; font-weight: 400; padding: 0 16px 10px 0; border-bottom: 1px solid #e9ecef; } +.doc-table td { padding: 12px 16px 12px 0; border-bottom: 1px solid #f1f3f5; color: #495057; vertical-align: top; line-height: 23px; } +.doc-table td:first-child { color: #212529; font-weight: 700; white-space: nowrap; } +.doc-table code { font-family: "DM Mono", monospace; font-size: 13px; background: #f1f3f5; padding: 2px 6px; border-radius: 4px; color: #212529; } +.docs-paging { display: flex; justify-content: space-between; gap: 16px; margin-top: 56px; padding-top: 24px; border-top: 1px solid #e9ecef; } +.docs-paging button { background: none; border: 0; font: inherit; font-weight: 700; color: #212529; cursor: pointer; padding: 8px 0; } +.docs-paging button:hover { color: #6c757d; } +@media (max-width: 900px) { + .docs { grid-template-columns: 1fr; gap: 0; } + .docs-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 24px 0 0; } + .docs-nav > div { display: contents; } + .docs-group { display: none; } + .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } + .docs-body h1 { font-size: 34px; line-height: 38px; } +} From 6f8b10fe5db16277e6d5b42336f06f9dab82d0b8 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:51:53 +0100 Subject: [PATCH 19/44] test(sdk): round-trip the BCS layouts, and stop hardcoding a status in SQL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCS is positional and silent: a field at the wrong offset reads the next field's bytes and produces a plausible wrong number rather than an error. These round-trips cannot prove the layout agrees with Move — only a deployment can — but they catch the mistakes that happen while editing the file, and they pin the fixed widths so a changed type shows up as a length failure. The advisory queries were comparing status to a literal 2. They now take the Status constant, and all three were run against a real Postgres to confirm they bind and parse. --- sdk/test/bcs.test.ts | 197 +++++++++++++++++++++++++++++++++++++++++ server/src/advisory.ts | 7 +- 2 files changed, 201 insertions(+), 3 deletions(-) create mode 100644 sdk/test/bcs.test.ts diff --git a/sdk/test/bcs.test.ts b/sdk/test/bcs.test.ts new file mode 100644 index 0000000..0c6cb68 --- /dev/null +++ b/sdk/test/bcs.test.ts @@ -0,0 +1,197 @@ +import { describe, expect, it } from 'vitest'; +import { + AssetLimitsBcs, + PolicyBcs, + ProposalBcs, + RecipientBcs, + VaultBcs, + VelocityBcs, + bcs, +} from '../src/bcs'; + +/** + * BCS is positional and silent: a field in the wrong place does not error, it reads the next + * field's bytes and produces a plausible wrong number. These round-trips will not catch a layout + * that disagrees with Move — only a deployment can do that — but they do catch the mistakes that + * happen while editing this file: a width changed, a field dropped, two fields transposed to the + * same width. + * + * Every value below is distinct, so a transposition shows up as a wrong value rather than a + * coincidence. + */ +const policy = { + approvals_low: 1, + approvals_high: 2, + approvals_critical: 3, + governance_threshold: 4, + guardian_threshold: 5, + guardian_required_critical: true, + delay_high: '3600000', + delay_critical: '86400000', + recipient_activation_delay: '43200000', + policy_change_delay: '172800000', + recovery_delay: '259200000', + proposal_ttl: '2592000000', + high_exposure_bps: '1000', + critical_exposure_bps: '2500', + hard_block_exposure_bps: '9000', + envelope_bps: '3000', + envelope_window: '86400000', +}; + +const limits = { + approved: true, + low_max: '1000', + high_max: '10000', + per_tx_max: '50000', + daily_max: '100000', +}; + +const A1 = `0x${'11'.repeat(32)}`; +const A2 = `0x${'22'.repeat(32)}`; +const A3 = `0x${'33'.repeat(32)}`; + +describe('BCS round-trips', () => { + it('preserves every policy field', () => { + const parsed = PolicyBcs.parse(PolicyBcs.serialize(policy).toBytes()); + expect(parsed).toEqual(policy); + }); + + it('is fixed width for a policy: five u8, a bool, and eleven u64', () => { + // 5 + 1 + 11 * 8 = 94. A changed width shows up here before it shows up as a wrong number. + expect(PolicyBcs.serialize(policy).toBytes()).toHaveLength(94); + }); + + it('preserves the asset limits', () => { + const parsed = AssetLimitsBcs.parse(AssetLimitsBcs.serialize(limits).toBytes()); + expect(parsed).toEqual(limits); + expect(AssetLimitsBcs.serialize(limits).toBytes()).toHaveLength(1 + 4 * 8); + }); + + it('preserves the velocity windows, which are all the same width and so the easiest to transpose', () => { + const velocity = { + day_anchor: '1', + day_spent: '2', + envelope_anchor: '3', + envelope_spent: '4', + envelope_basis: '5', + }; + expect(VelocityBcs.parse(VelocityBcs.serialize(velocity).toBytes())).toEqual(velocity); + }); + + it('preserves a recipient, including its label', () => { + const recipient = { + trust: 2, + registered_at: '1700000000000', + activates_at: '1700043200000', + paid_count: '7', + last_paid: '1700086400000', + label: 'Payroll — ACME GmbH', + }; + expect(RecipientBcs.parse(RecipientBcs.serialize(recipient).toBytes())).toEqual(recipient); + }); + + it('preserves a transfer proposal with both payload options empty', () => { + const proposal = { + id: '9', + kind: 0, + status: 1, + proposer: A1, + created_at: '1700000000000', + executable_at: '1700003600000', + expires_at: '1702592000000', + req_approvals: 2, + req_guardians: 1, + tier: 2, + reasons: 321, + exposure_bps: '2500', + policy_version: '3', + reduction_mask: 70000, + approvals: { contents: [A1, A2] }, + confirmations: { contents: [A3] }, + asset: { name: '0000000000000000000000000000000000000000000000000000000000000002::sui::SUI' }, + amount: '1234567890', + recipient: A2, + memo: 'invoice 1182', + new_policy: null, + new_limits: null, + member: A3, + member_prev: A1, + member_roles: 7, + trust_level: 3, + target_mode: 1, + }; + expect(ProposalBcs.parse(ProposalBcs.serialize(proposal).toBytes())).toEqual(proposal); + }); + + it('preserves a governance proposal carrying a policy and limits', () => { + const proposal = { + id: '10', + kind: 1, + status: 1, + proposer: A1, + created_at: '1', + executable_at: '2', + expires_at: '3', + req_approvals: 2, + req_guardians: 0, + tier: 0, + reasons: 0, + exposure_bps: '0', + policy_version: '1', + reduction_mask: 2048, + approvals: { contents: [] }, + confirmations: { contents: [] }, + asset: null, + amount: '0', + recipient: `0x${'00'.repeat(32)}`, + memo: 'policy', + new_policy: policy, + new_limits: limits, + member: `0x${'00'.repeat(32)}`, + member_prev: `0x${'00'.repeat(32)}`, + member_roles: 0, + trust_level: 0, + target_mode: 0, + }; + const parsed = ProposalBcs.parse(ProposalBcs.serialize(proposal).toBytes()); + expect(parsed).toEqual(proposal); + expect(parsed.new_policy?.envelope_bps).toBe('3000'); + }); + + it('preserves a vault, keeping the six table handles distinct and in order', () => { + const handle = (n: string, size: string) => ({ id: `0x${n.repeat(32)}`, size }); + const vault = { + id: `0x${'ab'.repeat(32)}`, + name: 'Skur Demo Treasury', + policy, + policy_version: '4', + mode: 1, + posture_reasons: 576, + members: handle('01', '6'), + owner_count: '2', + approver_count: '4', + executor_count: '2', + guardian_count: '1', + limits: handle('02', '2'), + funds: handle('03', '2'), + velocity: handle('04', '2'), + recipients: handle('05', '9'), + proposals: handle('06', '40'), + next_proposal: '41', + pending_count: '3', + created_at: '1700000000000', + }; + const parsed = VaultBcs.parse(VaultBcs.serialize(vault).toBytes()); + expect(parsed).toEqual(vault); + // The handles are the part a transposition would quietly swap, and reading the wrong table is + // the kind of bug that looks like missing data rather than a crash. + expect(parsed.members.id).toBe(`0x${'01'.repeat(32)}`); + expect(parsed.proposals.id).toBe(`0x${'06'.repeat(32)}`); + expect(parsed.proposals.size).toBe('40'); + }); + + it('reads a Balance as a bare u64, which is how it is stored in the bag', () => { + expect(bcs.u64().parse(bcs.u64().serialize('250000000000').toBytes())).toBe('250000000000'); + }); +}); diff --git a/server/src/advisory.ts b/server/src/advisory.ts index 781f609..e2f59b0 100644 --- a/server/src/advisory.ts +++ b/server/src/advisory.ts @@ -1,6 +1,7 @@ import { DAY, Mode, + Status, Trust, computeMaxLoss, fmtDuration, @@ -138,13 +139,13 @@ export async function outflow( a.daily_max, (SELECT sum(p.amount) FROM proposals p WHERE p.network = a.network AND p.vault_id = a.vault_id - AND p.coin_type = a.coin_type AND p.status = 2 AND p.settled_at >= $3) AS in_window, + AND p.coin_type = a.coin_type AND p.status = $5 AND p.settled_at >= $3) AS in_window, (SELECT sum(p.amount) FROM proposals p WHERE p.network = a.network AND p.vault_id = a.vault_id - AND p.coin_type = a.coin_type AND p.status = 2 AND p.settled_at >= $4) AS today + AND p.coin_type = a.coin_type AND p.status = $5 AND p.settled_at >= $4) AS today FROM assets a WHERE a.network = $1 AND a.vault_id = $2 AND a.approved`, - [network, vaultId, windowStart, dayStart], + [network, vaultId, windowStart, dayStart, Status.EXECUTED], ); return rows.map((row) => { From ae89909bece523c9d5311602eb00bbabc5a8df93 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:56:06 +0100 Subject: [PATCH 20/44] feat(sui): a proposal can be rejected, not only cancelled or left to expire MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lifecycle had approve, veto and cancel but no way for the signers who were asked to simply say no. Without it a bad proposal sits in the queue until an owner cancels it or its lifetime runs out. Rejecting takes the same role approving would, and it takes as many rejections as the proposal needed approvals — counted against live roles, like approvals. So rejecting is exactly as hard as approving: one signer cannot block the queue, and a proposal the team has turned down is settled the same day. Threaded through the BCS layout, the SDK, the indexer projections, the notification rules (which stay quiet until the rejection actually carries), the queue UI and the docs. Five Move tests, two TypeScript tests, and a migration that widens the vote-kind constraint. --- README.md | 8 +- app/src/app/(marketing)/page.tsx | 4 +- app/src/app/(marketing)/security/page.tsx | 5 +- app/src/components/Queue.tsx | 17 ++++ app/src/marketing/docs.tsx | 14 +++- docs/SUI_POSITIONING.md | 2 +- docs/SUI_SECURITY_MODEL.md | 7 +- sdk/dist/bcs.d.ts | 5 ++ sdk/dist/bcs.d.ts.map | 2 +- sdk/dist/bcs.js | 1 + sdk/dist/bcs.js.map | 2 +- sdk/dist/events.d.ts | 11 ++- sdk/dist/events.d.ts.map | 2 +- sdk/dist/events.js | 14 ++++ sdk/dist/events.js.map | 2 +- sdk/dist/tx.d.ts | 1 + sdk/dist/tx.d.ts.map | 2 +- sdk/dist/tx.js | 3 +- sdk/dist/tx.js.map | 2 +- sdk/dist/types.d.ts | 3 + sdk/dist/types.d.ts.map | 2 +- sdk/dist/types.js | 3 + sdk/dist/types.js.map | 2 +- sdk/dist/vault.d.ts.map | 2 +- sdk/dist/vault.js | 1 + sdk/dist/vault.js.map | 2 +- sdk/src/bcs.ts | 1 + sdk/src/events.ts | 25 ++++++ sdk/src/tx.ts | 4 +- sdk/src/types.ts | 4 + sdk/src/vault.ts | 1 + sdk/test/bcs.test.ts | 2 + server/migrations/002_rejections.sql | 10 +++ server/src/project.ts | 14 ++++ server/src/rules.ts | 13 +++ server/test/notify.test.ts | 25 ++++++ sui/README.md | 2 +- sui/sources/types.move | 4 + sui/sources/vault.move | 58 ++++++++++++++ sui/tests/vault_tests.move | 97 +++++++++++++++++++++++ 40 files changed, 352 insertions(+), 27 deletions(-) create mode 100644 server/migrations/002_rejections.sql diff --git a/README.md b/README.md index 255cdc9..f31369e 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Details, with the test that proves each invariant, in | [sdk/](sdk/) | TypeScript SDK on `@mysten/sui` v2 — reads, PTB builders, event decoding, and the chain-agnostic engines (risk, policy rules, templates, maximum loss, posture, attack simulator) | | [app/](app/) | The interface: Next.js, React, `@mysten/dapp-kit-react` | | [server/](server/) | Node and PostgreSQL: the event indexer, the notification service and the advisory API | -| [docs/SUI_SECURITY_MODEL.md](docs/SUI_SECURITY_MODEL.md) | Roles, lifecycle, the fifteen invariants, the threat map and the known limitations | +| [docs/SUI_SECURITY_MODEL.md](docs/SUI_SECURITY_MODEL.md) | Roles, lifecycle, the sixteen invariants, the threat map and the known limitations | | [docs/SUI_LANDSCAPE.md](docs/SUI_LANDSCAPE.md) | What exists on Sui today and what it does not do | | [docs/SUI_POSITIONING.md](docs/SUI_POSITIONING.md) | The positioning and funding narrative | | [docs/MIGRATION_EVM_TO_SUI.md](docs/MIGRATION_EVM_TO_SUI.md) | What moved, what changed shape, and why | @@ -102,8 +102,10 @@ app, the SDK or the backend hardcodes one. 1. **Opened.** The vault classifies it routine, high risk or critical from the amount, the share of holdings, the recipient's standing, the day's outflow and the security mode, and pins the approvals, the guardian confirmations and the delay. -2. **Approved.** Approvers approve; guardians confirm when the tier demands it. A guardian can veto - any critical payment, any weakening of the vault, any recovery and any relaxation. +2. **Approved, or turned down.** Approvers approve; guardians confirm when the tier demands it. + Rejecting takes as many signers as approving, so a bad proposal can be cleared rather than left + to expire — and one signer cannot block the queue. A guardian can veto any critical payment, any + weakening of the vault, any recovery and any relaxation. 3. **Executed.** The vault re-checks everything against live state: the approval set is recounted against the current roster, the payment is reclassified and the *stricter* of the pinned and live requirements applies, the recipient's standing and activation are re-read, and the caps and diff --git a/app/src/app/(marketing)/page.tsx b/app/src/app/(marketing)/page.tsx index c590617..90bd5c4 100644 --- a/app/src/app/(marketing)/page.tsx +++ b/app/src/app/(marketing)/page.tsx @@ -98,7 +98,7 @@ export default function Landing() { ))}
      - 15 invariants enforced by the vault, not by a server + 16 invariants enforced by the vault, not by a server

      {words.map((w, i) => ( @@ -441,7 +441,7 @@ export default function Landing() { The Skur thesis
      - +
      diff --git a/app/src/app/(marketing)/security/page.tsx b/app/src/app/(marketing)/security/page.tsx index 4199142..7156999 100644 --- a/app/src/app/(marketing)/security/page.tsx +++ b/app/src/app/(marketing)/security/page.tsx @@ -5,7 +5,7 @@ import { Reveal } from '@/marketing/Reveal'; import { IconCheck } from '@/marketing/icons'; import { NETWORK, PACKAGE_ID, CONFIGURED } from '@/config'; -/** The fifteen invariants, each with the control that enforces it. */ +/** The sixteen invariants, each with the control that enforces it. */ const INVARIANTS: [string, string][] = [ ['Nothing executes before every active condition is met', 'ordered assertions in execute_transfer'], ['A guardian cannot move treasury assets through guardian authority', 'types::roles_valid · role gates'], @@ -22,6 +22,7 @@ const INVARIANTS: [string, string][] = [ ['The breaker’s latch survives the attempt', 'execute_transfer returns without aborting'], ['Leaving a raised posture is never unilateral', 'owners + guardians + delay'], ['An automation key cannot authorize itself', 'PROPOSER satisfies only can_propose'], + ['Rejecting takes as many signers as approving', 'reject · counted against live roles'], ]; export default function SecurityPage() { @@ -101,7 +102,7 @@ export default function SecurityPage() {
      -

      Fifteen invariants, each with a test

      +

      Sixteen invariants, each with a test

      Every control is enforced by the Move code and proven by a test named after the attack it defends against. The mapping is public in the security model. diff --git a/app/src/components/Queue.tsx b/app/src/components/Queue.tsx index 2064aaa..b13ff94 100644 --- a/app/src/components/Queue.tsx +++ b/app/src/components/Queue.tsx @@ -128,6 +128,10 @@ function ProposalCard({ const voteRole = isTransfer ? Role.APPROVER : Role.OWNER; const alreadyApproved = me ? p.approvals.includes(me) : false; const alreadyConfirmed = me ? p.confirmations.includes(me) : false; + const alreadyRejected = me ? p.rejections.includes(me) : false; + const liveRejections = p.rejections.filter((a) => + hasRole(view.members.find((m) => m.address === a)?.roles ?? 0, voteRole), + ).length; const approvalsMet = liveApprovals >= p.reqApprovals; const guardiansMet = liveConfirmations >= p.reqGuardians; @@ -267,6 +271,19 @@ function ProposalCard({ {alreadyApproved ? 'Approved' : 'Approve'} + + {p.reqGuardians > 0 || vetoable ? (

      Xe6^d|m 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 z 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

      H>RU+%S^xBr)_VlSn!5#iUb>eyq;-Jl^%T#Blk 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 z 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

      6mr1R5SGaoe?+rz4~K?v}--NN0lz9n54cOpZ( z`+v4|=c1YhzE-x3bklIn-8UC<&lwlj1X{hE^*a%B04X41q|0xt|GFui_s?iMZ4^Nb z6`DFz-71v4{C=cQ+RsV)O={8sWMw`a+K%t49%W=`Jn5r8wzJ@=ZjGdM5n<%&z3#Er zy|dak-*IDqJct!M6)rSz_^OUF`8dx|!>3cPVNhvUY`wqeD8bVXo+lT3ejtOod#oeF z>4R1NXw$$5+35)iIs%gSYpEhvzbfU-fuc{Ip|ALB+Nq}RpAC|BV%~TEy4=(9dG`M5 zS1ET5g^NqvHy6+MV1X15?QIdA^m!S!tMwiR6tY1xWlHSUfArXI&Hvc9^2zM{R%yb8 z>8#sV!>-mi=yh8OFT22bMm%PDyd=_e;8^LssMX)GTPq1`V;?`A58E=k7?u#?)_zbo zE;J@Je)YiC*KGHT8`BC+?P_}yR=DxstN6Tv6Un^5qSY!1fdY_VOW5&}Uwg+wswcz2~DcgrFCKg!g+Xj}i@c)$GByZH0* zLuZ~wZgDCMXFIx@N^ctd`8m2VDplH%G*a`f>~s>JEnJ-Eb;6^iUy!}8{^Pp za|6_87tcS;j>B)v#Y*|llngA~)4v8nDJzqwI+v}n9?})I-=?}Uo<1(ri#J@IF&Im@ zB4o*RuKBVSd~kDpbX+M?&O2^);E=NaTU6*a>V-;7Uhjl@!!d>-<7%REKMkXHk7msO z;S0pLB^SU++t{nga*)n9G8ymiG!%s%6)j1VzrXVRh17(ZNxiUl$<$p1_SX8{^1*PE z>glt8IB`2v^Yx#g8HI&BYYdl?PNiXpVAi-pOWdo4sSwAw?#R*0vl8BQi!}|M4WH)7`yA<64(r&HmPRDewpX|F z!Zo8s!mHk)4bmB9BDyQH{ZDmt)eCEop-BrVP{Q~h!W_eTI0hQ&IzR8$?={WvF+PBu5ETZ)4K&v%_f(fCNLFctq>o~q({ zw(T2zeNuxpQ|%jvWimxA=3!V)`dLVe8MD)Cu&N-G(9S`{Jr`IfbuZ8}LCF M)zXe!Ywkh+KkSt`a{vGU literal 0 HcmV?d00001 diff --git a/mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-#ffffff/App-Icon-1024x1024@1x.png b/mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-#ffffff/App-Icon-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..ed858557aab88e3cba0ff06536ad2c3a218118b8 GIT binary patch literal 28686 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�k+si*!9!J=8KakBl8H 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 F{V& - - - {() => } - {() => } - - - ); - if (error && !vault) return ( - } />}> - {describeError(error).split("\n")[0]} - - - - - ); - if (isLoading || !vault) return Reading the vault from the chain…; - const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; - const TabsScreen = () => ( - - }}>{() => } - , tabBarBadge: pending || undefined, tabBarBadgeStyle: { backgroundColor: C.accent, color: C.onAccent, fontFamily: F.bodyBold, fontSize: 11 } }}>{() => } - }}>{() => } - - ); - return ( - - - {() => } - {() => } - {() => } - {() => } - {() => } - {() => } - {() => } - {() => } - - {() => } - {() => } - - - ); -} - -export const navigationRef = createNavigationContainerRef(); -const ROUTES: Record = { - home: ["Main", "Home"], transactions: ["Main", "Transactions"], settings: ["Main", "Settings"], - send: "Send", receive: "Receive", security: "Security", addressbook: "AddressBook", members: "Members", - policy: "Policy", simulator: "Simulator", create: "CreateVault", signers: "Signers", updates: "Notifications", scan: "Scan", -}; - -/** - * Deep links, including the ones notifications carry: skur://tx/, skur://vault/
      , and one per screen. - * Links that arrive before the navigator is mounted (cold start, vault still loading) are queued, not dropped. - */ -function useDeepLinks(ready: boolean) { - const { setVaultAddress, importSigner, setOnboarded } = useStore(); - const { setScheme } = useScheme(); - const queued = useRef(null); - const go = useCallback((target: keyof RootParams | [keyof RootParams, string], params?: object) => { - if (!navigationRef.isReady()) return false; - const names = navigationRef.getRootState()?.routeNames ?? []; - const wanted = Array.isArray(target) ? target[0] : target; - if (!names.includes(wanted as string)) return false; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const nav = navigationRef.navigate as unknown as (name: string, params?: object) => void; - // Going to a tab means leaving whatever was pushed on top of it. - if (Array.isArray(target)) { if ((navigationRef.getRootState()?.routes.length ?? 0) > 1) navigationRef.dispatch(StackActions.popToTop()); nav(target[0], { screen: target[1], ...(params ?? {}) }); } - else nav(target, params); - return true; - }, []); - const handle = useCallback((url: string | null): void => { - if (!url) return; - const { hostname, path } = Linking.parse(url); - const segs = [hostname ?? "", ...(path ?? "").split("/")].filter(Boolean); - const [head, ...rest] = segs; - // Opening a different vault returns to Home: a pushed screen belongs to the vault you left. - if (head === "vault" && rest[0] && isAddress(rest[0])) { void setVaultAddress(rest[0] as `0x${string}`); go(["Main", "Home"]); return; } - if (__DEV__ && head === "dev" && rest[0] === "signer" && rest[1]) { void importSigner(rest[1]).catch(() => undefined); return; } - if (__DEV__ && head === "dev" && rest[0] === "onboarding") { void setOnboarded(false); void setVaultAddress(null); return; } - if (__DEV__ && head === "dev" && rest[0] === "theme" && rest[1]) { setScheme(rest[1] as "light" | "dark" | "system"); return; } - if (head === "tx" && rest[0]) { if (!go("TxDetail", { id: rest[0] })) queued.current = url; return; } - const route = ROUTES[head ?? ""]; - if (route && !go(route)) queued.current = url; - }, [setVaultAddress, importSigner, setOnboarded, setScheme, go]); - useEffect(() => { - void Linking.getInitialURL().then(handle); - const sub = Linking.addEventListener("url", (e) => handle(e.url)); - const nsub = Notifications.addNotificationResponseReceivedListener((r) => { - const u = (r.notification.request.content.data as { url?: string } | undefined)?.url; - if (u) handle(u); - }); - return () => { sub.remove(); nsub.remove(); }; - }, [handle]); - // Replay a link that arrived before the navigator existed. - useEffect(() => { if (ready && queued.current) { const u = queued.current; queued.current = null; setTimeout(() => handle(u), 60); } }, [ready, handle]); -} - -function Gate() { - const { ready, onboarded, setOnboarded, vaultAddress } = useStore(); - const [navReady, setNavReady] = useState(false); - useDeepLinks(navReady); - useEffect(() => { const t = setInterval(() => { if (navigationRef.isReady()) { setNavReady(true); clearInterval(t); } }, 120); return () => clearInterval(t); }, []); - if (!ready) return ; - if (!onboarded && !vaultAddress) return void setOnboarded()} />; - return ; -} - -type TabParams = { Home: undefined; Transactions: undefined; Settings: undefined }; -type RootParams = { Main: NavigatorScreenParams; TxDetail: { id: string }; Send: undefined; Receive: undefined; Security: undefined; AddressBook: undefined; Members: undefined; Policy: undefined; Simulator: undefined; CreateVault: undefined; Signers: undefined; Notifications: undefined; Scan: undefined }; - -function Root() { - const { C, dark } = useScheme(); - const base = dark ? DarkTheme : DefaultTheme; - const navTheme = { ...base, colors: { ...base.colors, background: C.canvas, card: C.card, border: C.border, primary: C.accent, text: C.text } }; - return ( - - - - - ); -} - -export default function App() { - const [fontsLoaded] = useFonts({ SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold, DMSans_400Regular, DMSans_500Medium, DMSans_700Bold, DMMono_400Regular, DMMono_500Medium }); - if (!fontsLoaded) return ; - return ( - - - - - - - - - - ); -} diff --git a/mobile/LICENSE b/mobile/LICENSE deleted file mode 100644 index 30b20e3..0000000 --- a/mobile/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-present 650 Industries, Inc. (aka Expo) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/mobile/README.md b/mobile/README.md deleted file mode 100644 index 0743699..0000000 --- a/mobile/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Skur mobile - -The phone companion to the Skur web interface, built after Safe{Mobile}'s structure in Skur's own pattern: a splash with the logo, a three-page onboarding carousel, a Home with the vault switcher, chain row, big balance and Tokens, Policy and Members tabs, Transactions grouped by date, a Confirm-transaction screen with a sticky sign bar, Send with the vault's own review, Security, and Settings as grouped rows. Charcoal ground, #FFD000 as hazard tape and highlighter, Space Grotesk for display, the same identicons as the web. Built with Expo and React Native for iOS and Android. - -## Screens - -Onboarding carousel and splash, Home (vault switcher sheet, balance, Tokens/Policy/Members tabs), Transactions (queue, history, type filter), Confirm transaction, Send, Receive, Security (posture, mode, guardians, recovery, maximum loss, mode history), Policy editor (templates, every control, per-asset limits), Members (roles, thresholds), Address book (register, trust), Simulator (attack scenarios), Updates (what needs you, recent activity, notification switch), Signers (several keys on one phone), Create vault, and a QR scanner for vault and recipient addresses. - -## What it shares with the web app - -Everything that decides something is imported from `web/src` through the `@web/*` alias configured in `metro.config.js` and `tsconfig.json`: the contract ABI, chain configuration, types, the risk engine, policy rules, the max-loss and posture calculators, the contract reads (`lib/vaultReads.ts`) and the error texts. The mobile code holds only screens, navigation, storage and signing. - -## Signing - -There is no wallet connection. A signer key is created on the phone or imported, stored in the device keychain through `expo-secure-store`, and used to sign after a Face ID or Touch ID prompt (`expo-local-authentication`, switchable in Settings). Add that address as a member of a vault to act for it; without a role the app is read-only. Every write is simulated against the vault first, so a policy refusal reads as plain language before anything is signed. - -## Run it - -```sh -cd mobile -npm install -npx expo start # then press i for the iOS simulator or a for Android, or scan with Expo Go -npx tsc --noEmit # type-check, including the shared web modules -``` - -The app reads the Ark Constellation devnet (chain 9000) through the endpoints in `web/src/config/chain.ts`. It ships no key and no backend. - -Deep links: `skur://vault/
      `, `skur://tx/`, and one per screen (`home`, `transactions`, `settings`, `send`, `receive`, `security`, `addressbook`, `members`, `policy`, `simulator`, `create`, `signers`, `updates`, `scan`). Notifications carry the transaction link. - -## Notifications - -Local, not push. While the app reads the vault it raises a notification for any proposal that newly needs the active signer, and the Updates screen lists those alongside recent activity. Nothing is sent to a server. - -## Building natively - -`npx expo run:ios` needs CocoaPods and `cmake` on PATH (hermes builds from source). This project sets `ios.usePrecompiledModules: false` in `app.json`: the precompiled Expo module frameworks link against a prebuilt `React.framework` that is not always fetchable, and mixing the two crashes the app at launch with `Library not loaded: @rpath/React.framework/React`. diff --git a/mobile/android/.gitignore b/mobile/android/.gitignore new file mode 100644 index 0000000..1ea9b64 --- /dev/null +++ b/mobile/android/.gitignore @@ -0,0 +1,19 @@ +# OSX +# +.DS_Store + +# Android/IntelliJ +# +build/ +.idea +.gradle +local.properties +*.iml +*.hprof +.cxx/ + +# generated inline modules +app/src/main/java/inline/ + +# Bundle artifacts +*.jsbundle diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle new file mode 100644 index 0000000..b71d9c8 --- /dev/null +++ b/mobile/android/app/build.gradle @@ -0,0 +1,182 @@ +apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" +apply plugin: "com.facebook.react" + +def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath() + +/** + * This is the configuration block to customize your React Native Android app. + * By default you don't need to apply any configuration, just uncomment the lines you need. + */ +react { + entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim()) + reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() + hermesCommand = new File(["node", "--print", "require.resolve('hermes-compiler/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/hermesc/%OS-BIN%/hermesc" + codegenDir = new File(["node", "--print", "require.resolve('@react-native/codegen/package.json', { paths: [require.resolve('react-native/package.json')] })"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile() + + enableBundleCompression = (findProperty('android.enableBundleCompression') ?: false).toBoolean() + // Use Expo CLI to bundle the app, this ensures the Metro config + // works correctly with Expo projects. + cliFile = new File(["node", "--print", "require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim()) + bundleCommand = "export:embed" + + /* Folders */ + // The root of your project, i.e. where "package.json" lives. Default is '../..' + // root = file("../../") + // The folder where the react-native NPM package is. Default is ../../node_modules/react-native + // reactNativeDir = file("../../node_modules/react-native") + // The folder where the react-native Codegen package is. Default is ../../node_modules/@react-native/codegen + // codegenDir = file("../../node_modules/@react-native/codegen") + + /* Variants */ + // The list of variants to that are debuggable. For those we're going to + // skip the bundling of the JS bundle and the assets. By default is just 'debug'. + // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. + // debuggableVariants = ["liteDebug", "prodDebug"] + + /* Bundling */ + // A list containing the node command and its flags. Default is just 'node'. + // nodeExecutableAndArgs = ["node"] + + // + // The path to the CLI configuration file. Default is empty. + // bundleConfig = file(../rn-cli.config.js) + // + // The name of the generated asset file containing your JS bundle + // bundleAssetName = "MyApplication.android.bundle" + // + // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' + // entryFile = file("../js/MyApplication.android.js") + // + // A list of extra flags to pass to the 'bundle' commands. + // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle + // extraPackagerArgs = [] + + /* Hermes Commands */ + // The hermes compiler command to run. By default it is 'hermesc' + // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" + // + // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" + // hermesFlags = ["-O", "-output-source-map"] + + /* Autolinking */ + autolinkLibrariesWithApp() +} + +/** + * Set this to true in release builds to optimize the app using [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization). + */ +def enableMinifyInReleaseBuilds = (findProperty('android.enableMinifyInReleaseBuilds') ?: false).toBoolean() + +/** + * The preferred build flavor of JavaScriptCore (JSC) + * + * For example, to use the international variant, you can use: + * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` + * + * The international variant includes ICU i18n library and necessary data + * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that + * give correct results when using with locales other than en-US. Note that + * this variant is about 6MiB larger per architecture than default. + */ +def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+' + +android { + ndkVersion rootProject.ext.ndkVersion + + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdk rootProject.ext.compileSdkVersion + + namespace 'io.skur.vault' + defaultConfig { + applicationId 'io.skur.vault' + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "0.1.0" + + buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\"" + } + signingConfigs { + debug { + storeFile file('debug.keystore') + storePassword 'android' + keyAlias 'androiddebugkey' + keyPassword 'android' + } + } + buildTypes { + debug { + signingConfig signingConfigs.debug + } + release { + // Caution! In production, you need to generate your own keystore file. + // see https://reactnative.dev/docs/signed-apk-android. + signingConfig signingConfigs.debug + def enableShrinkResources = findProperty('android.enableShrinkResourcesInReleaseBuilds') ?: 'false' + shrinkResources enableShrinkResources.toBoolean() + minifyEnabled enableMinifyInReleaseBuilds + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" + def enablePngCrunchInRelease = findProperty('android.enablePngCrunchInReleaseBuilds') ?: 'true' + crunchPngs enablePngCrunchInRelease.toBoolean() + } + } + packagingOptions { + jniLibs { + def enableLegacyPackaging = findProperty('expo.useLegacyPackaging') ?: 'false' + useLegacyPackaging enableLegacyPackaging.toBoolean() + } + } + androidResources { + ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~' + } +} + +// Apply static values from `gradle.properties` to the `android.packagingOptions` +// Accepts values in comma delimited lists, example: +// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini +["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop -> + // Split option: 'foo,bar' -> ['foo', 'bar'] + def options = (findProperty("android.packagingOptions.$prop") ?: "").split(","); + // Trim all elements in place. + for (i in 0.. 0) { + println "android.packagingOptions.$prop += $options ($options.length)" + // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**' + options.each { + android.packagingOptions[prop] += it + } + } +} + +dependencies { + // The version of react-native is set by the React Native Gradle Plugin + implementation("com.facebook.react:react-android") + + def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; + def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; + def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; + + if (isGifEnabled) { + // For animated gif support + implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}") + } + + if (isWebpEnabled) { + // For webp support + implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}") + if (isWebpAnimatedEnabled) { + // Animated webp support + implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}") + } + } + + if (hermesEnabled.toBoolean()) { + implementation("com.facebook.react:hermes-android") + } else { + implementation jscFlavor + } +} diff --git a/mobile/android/app/debug.keystore b/mobile/android/app/debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..364e105ed39fbfd62001429a68140672b06ec0de GIT binary patch literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc + + + + + diff --git a/mobile/android/app/src/debugOptimized/AndroidManifest.xml b/mobile/android/app/src/debugOptimized/AndroidManifest.xml new file mode 100644 index 0000000..3ec2507 --- /dev/null +++ b/mobile/android/app/src/debugOptimized/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..650fa75 --- /dev/null +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt b/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt new file mode 100644 index 0000000..8a4d784 --- /dev/null +++ b/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt @@ -0,0 +1,61 @@ +package io.skur.vault + +import android.os.Build +import android.os.Bundle + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +import expo.modules.ReactActivityDelegateWrapper + +class MainActivity : ReactActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + // Set the theme to AppTheme BEFORE onCreate to support + // coloring the background, status bar, and navigation bar. + // This is required for expo-splash-screen. + setTheme(R.style.AppTheme); + super.onCreate(null) + } + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "main" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate { + return ReactActivityDelegateWrapper( + this, + BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, + object : DefaultReactActivityDelegate( + this, + mainComponentName, + fabricEnabled + ){}) + } + + /** + * Align the back button behavior with Android S + * where moving root activities to background instead of finishing activities. + * @see onBackPressed + */ + override fun invokeDefaultOnBackPressed() { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { + if (!moveTaskToBack(false)) { + // For non-root activities, use the default implementation to finish them. + super.invokeDefaultOnBackPressed() + } + return + } + + // Use the default back button implementation on Android S + // because it's doing more than [Activity.moveTaskToBack] in fact. + super.invokeDefaultOnBackPressed() + } +} diff --git a/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt b/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt new file mode 100644 index 0000000..9914534 --- /dev/null +++ b/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt @@ -0,0 +1,45 @@ +package io.skur.vault + +import android.app.Application +import android.content.res.Configuration + +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative +import com.facebook.react.ReactPackage +import com.facebook.react.ReactHost +import com.facebook.react.common.ReleaseLevel +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint + +import expo.modules.ApplicationLifecycleDispatcher +import expo.modules.ExpoReactHostFactory + +class MainApplication : Application(), ReactApplication { + + override val reactHost: ReactHost by lazy { + ExpoReactHostFactory.getDefaultReactHost( + context = applicationContext, + packageList = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + ) + } + + override fun onCreate() { + super.onCreate() + DefaultNewArchitectureEntryPoint.releaseLevel = try { + ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) + } catch (e: IllegalArgumentException) { + ReleaseLevel.STABLE + } + loadReactNative(this) + ApplicationLifecycleDispatcher.onApplicationCreate(this) + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig) + } +} diff --git a/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..831332d475a1dc4884bf11820ce65e7743108ea7 GIT binary patch literal 572 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..761e9dfbc8e2c7eb5b50a52091f0f6e52e242900 GIT binary patch literal 370 zcmV-&0ge8NP)Jj+?}~> zuQe!~%u#(E$A-efgrhmSjx!bV2?l%w5O6d$6c(bBJudcNxVnwe^WivOXLj1dhQd-d z)h3&2Gc1Xj%kW$bBqoX?P{LjbNf86V0Q!kAnjDY>1ZEm=5fsHTEk^#QAIscWq4h#m Q+5i9m07*qoM6N<$g0cIOlmGw# literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ef243aab6c07672628b98d8eb239605edfb97c5c GIT binary patch literal 12863 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 F{}05A4LSe- literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6b21888a01f7f82d9e68c237edde38ba4eef1202 GIT binary patch literal 827 zcmV-B1H}A^P)N&G020m4*|g~K6yka(o75(c(V zeVuBEFdj*~QY3%~)fd4ffk!4@2@E`XGHr1FkEPttg)t0hZ7Q;PZ2>E+@I+wXk%?x% z569^Gayd_@4gPI;Lzz<_|3!1sMkk3zt_!^<8hJWx@MimSK7W6bPxn2fwW-L&qYxh+ zPokTNM!BgFxv3CRKws|!QOjk{=CuXhIIxQA_aZ!cV$u+=po>JKB~ce4z*X?;ML}1Jmc*R1zd$zCK}Z(b=cbRj2|!5(sMM)%EkuPy*k6j^mD%Go+N6y=w_nXk)9ka zsS;;?u46P8W;7S3e=tsct;6B{lWf^gKqnK8DvrQ$1qa^yo1X1c+!~AU=gk;rf2-xn zNR)%ek_;Rfr8#M%i$tSu2ji^SwVJ)3r4RyIn~Ln&`k3zyKOo&aOT`gfys-qGBpRg> zHgj%_MtEE>nCG~HnUZ8qEaIY*iAEi-&Crr6F*0uPPVY+IT3;X>Qe3zm(l6DqLFDRPJT4b2VXUE=~j$y&ebt*#WI^?2Xn-09CR|#tnsBX{hy36GH!8u%))U6 zO)uNDHP0d?+L=^IOR7XmszkL(yiz#)R}>B&NxTx|fg;sc#2}AH5|2bXHgJyW8xU!1 zJd*ffkO4|mkBuaY4+cJD`^aayxC3kh4D_;*>=tPT@xj2S?AHuuy7(SJ0(b>5S)3w* z9}w&mZTx~yf<;i*2;q_dOcthsBrnpG2?PRxKp^lx^bgtQ=z_RRdHetX002ovPDHLk FV1kGEa+3f6 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e9d5474519c701b4b518f2f0a24d7d8742e93416 GIT binary patch literal 29081 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≠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 PMTS3g4RtcK&inljbZB-$ literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..9968354e371eae97478c178604989903df882762 GIT binary patch literal 1162 zcmV;51aC))Yy??3g@o!`*djl;D6&3ePN}|VX+fEp zK}3}1TWW|R4re7TZAzq~ncJGvnVa|ScDK8G?{ne`H&CiC&)v=go!<|`Fbu;m48t%C z!!Qive?>3^)JgnUJV=5X6t^SrGZYkq2rgpNM3O^d3WH>rAcNFN1QySd;B}yk;njsr zBS|)iDJU{TkRj?ESw#5^#UgYP>>!7y#RU4v0E-Mz9SFi~Ls5r*mBgu9wSujU8*ojM z3BA;#cpR@#EF?@l86a^ z2tL?3g0$+%fAaEE-Hb0EB%TnooXKL%C!^@-_Tf12)~BWHTl*V2NHn-`$o-lxIDblX=_|U;d zgE6IXqy)zS$AQ;A8b#wXSIEyvl4eQ8^L5uqI^0lFm_P>`4T|!T)ZW|2{$qKh>~1dL zU`rmetD;Q5E6U8uex}~hPs5U{=w_qIoAq6E_u8B|n?*`=Kyv7KE{Bfil2V+Xq;77A zrH@^sv?zft5={zolYH6O#@c0?fr!Dp|I!oc(WKU`%P8;bx=3o^SIxc`l2T8I@5Up4CTb zQGx~4VHQ+}Q9#p)T$ZmdC(A6+MJ&>?gAO`KGQ!h((&? z!1ksBzB!gh+RVx*I@oA1u_DIen(KUZxR8`>hYQ)&T)?>72JzX7j&2{Jh(+3j(J>yG z9YzNmP1Y>E%s@=C_q%*j;t9do_5imUS3bz*S32w67VVBeW8=ZH6cDfSV+t1 zY_3NvQi1`8Nfj|3tq!wfelJ14LKhp&=1q$*Z(0PUAR3b-l7hUfBvRrDHXb1aOYiF+};D~3xF_uBEUc3hIU*Nk^H8MR|s~a*hB_cWI*FPu7f?5AE*F=42=Px4LC|M2gFzgF$}{n48t%C!!QiP cFbo&|0!3k7)F^01u>b%707*qoM6N<$f}>Iz#sB~S literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d61da15d2410dd60355d0d9ca34bb2aa741267f0 GIT binary patch literal 47123 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b0f2a7f8d12dad3b4b1601448dfc1ca8bdb17b2b GIT binary patch literal 1555 zcmV+u2JHEXP)G8vJ7ciXEL#^4I-cTtp*@Mrx2+QXB;;@t;aE zyrRxgi$)Tik{kqX!N2NBaS)9pny5aSP;AHV6x&rFO=u#~MX?Kz_@6|v3r!^YY^8W? zMH7hzs+T&Tk>b&)dZ|MLi5^PoOv9oy z`GkN?8=`bRdYODfBS9`r1~8e#U{g_td;wR{SeN2@Hf@+eNy_-_ZE2$RhUa&B9e z#AGf8tE$Mdxow6&y|;jzi{k+v>}+J^l3Ci<##nc2g3qmrbMwLs*KEBbf}gk;Zr{$! z^!>Apv55frhDL)7jRwhC(J;&Awi&*5*EGu;Quu|$aCOxge*e7-w6BeEBj?A096DOV z=4V&1`^SqJn+V_sEn8U6Ei+SyZVQQ;0n99Xqk(fi) z;}c~;kJ1uFNkDOXbBx=YV_cI=N#5!$r|Z=k&YmwNXFBTe(x0pO=7STM%Ee&!?`z~A zqd{`^J#v|yTR!GLm6mvXrEP{UuaENZcb9VNT!@_a`pba{OeHZ`NkEY=o|N23z*TI! zGeW+}X%~}847PYtntZ1Q%J^TVqYn8(K@XEj47PDijC}9(Rq*=BO0MVXj6?Tds>ru` zSrU`E7_8&Y2rnF|WhO4UMk(0y{9+!s=PDiT5kAu}OTbl3Ou3vo7vj*-Pcb$TAYVs& z1e3WKtg150zDGXdxvqM0JP*3xsHXdkYOWCilwwYIuZwb5YZQ}74EOafP4nDC<4D1r zlwwZnZcT9T=`ccIG#4Lu{N5|Hu1xU#U)OQ=d?`1wAe80NuYSz#`>qgh6{d6Xi7%{) zbL90_t|+9910+*IN5>045)Ulr$zYh#2;J^aGOM+DHkB1!X#B*j8v z%`1sDuOxaXijP7Ai5@YEPYewtdW-^!;-Qd?pn*gK(aL4uLyE_TqJ?oZkmz%qVj(z= zCK6o)hXD`&^AH?H6Nx5bE&T|N;CF%}qJ@4mk?2&)ULcHL2`(Yni$)F_?SGM2=Tp3c z$95oyzsyj=7SY5Y8aZgTzl(6^9!{Xx0#xD;VI*5b6DQHkp#b(DVyyEqeud;_pb3ze zDU0A`%D7LgVTb|{6qq{0Z76o3*aj>E1oKM)7ZCgr#bMFP`xKC19;q|b;IRZ)00;_8 z0TCplqJ>E;%d#xXvMkH8EX%Si%d#xXvMkH8EXyh`{{lin(SP!0(O>`o002ovPDHLk FV1ju{-e>>- literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4aeed11d00badbb02d5b40a3d24fcf97dbabbd5a GIT binary patch literal 66529 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

      ^;WArDFIvK1}FmU%q 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 N_G%kxm1)=q{|~x=+3WxS literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..883b2a0 --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml b/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml new file mode 100644 index 0000000..5c25e72 --- /dev/null +++ b/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..9764d2a --- /dev/null +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..9764d2a --- /dev/null +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..31c9395a71bf4ce7e372e4ac4f2e1efad02ca2a5 GIT binary patch literal 1900 zcmV-y2b1`TP)s7BJg@L2<2UfRG7fWFMR?WL6y?Cd@@8?9@oY zht10<0#%3c$nTp&gAa zq*EtG(?UN4eNd;-fi)=B0xlj;K?J`9-V{@bVL)I&ouPmPJAl~?4M&hH6J^{WiAEB2 zfw4sRCs4-FF%rd6?`l4%{S7{P(db2;p^ylNfKd!RSwvavtzmoZCIZ}}agVA;NAV9} z3PV>G@RYZPZMB<7&_nWtHNY$^vkXPZ6*d%V!j8)me(@A^FT|z=h>=F5;}F zhfoa+BhEFzgQYhgc8Vm5YQTdfSvC=>C5kF6#st+8#dIuvnJ$4+EXEXLB#?upFF6vh zVd;xaV(FL8AZco`v*%wKocv!Jjo0k7cIbq{5=|t2$>qHxZhrsTRYny?NEJznY}@U@ySad9Oz>r0Xm;@Yx)QG3w2>;3 z6!_$_gY{eU`6{$_=)Cf)Vq$SYD(IxZuXp4UjR}mDjp=6LEI(t0M{v91M52EEN zG&@N4=e-`5S9M@EiOJ43If=vs$)=4D@ye1mgrH9&@}m6VCs(oSie&$}^rowE1<+CNWuNdIBQ{Po<+2 z1Cr)UU?dV1m`%rI`VY(-r-hSQ2L0ybh9$DvV$@9g~$5L>OBf zrtzwSWLtM-bLezBFMiv{{3pA}_rx$#SrMSJBEVqKyft_+Sw>odJ;yUJ($S@H@Kic) z@62J>$8H)fI`MVtxSR<*8F2=iP6{lZBeFF^}{Uo9(Ut%CKx{=j1Z)Z z=B>d?3P=gxm>!^Fe2B(t4sNyUJd8HK&Yt5L9BD{r=Hwu5SAtZ~yft`9p^}0q%d0z> zIr$DkLQ9*C?ucZduHUxt{!urT6+v<`$Rs=921WXtiX2QrY-(P&2BWGN^zOj(&w{0Z* z`=Lx$Ep5Y0IwtB2N?zYsNV2CV-(hY=fPt7@7G&$%W)`d&O*Ag(?b3BS?Oht4j5ubI zm`K+ZM!F+{hcUJ|%#2BQFmkJ1$4n9vWx5jRnj+cd8+H{TnQ_b{G1;uLAVzApMm3W^v`Fon%E%M9I#KVJ3;m zmd*1c1ovsY>R{>5OE`8ejlM)`+g}_`oCYv;>n}stwdH<-JWR2Gx zyx=XNv?#)iiFX*D8^vx@1VfUG*X$fS=c2t!!-&(aSh2u|*>qCijhAk4^87Hawc0S! z)MBTp#m>Wc?S)$u=SDG`Bn7hFakj3#LSasnufj_UeXLmEBNZemQd$(@-3^zRH!Z-I z<#Hxi|MGR#zIc;V(Mh4)tQebr+RVXI>Adw`4#&==p%f3~$%wP0($C68x5@LwNF|*? zP+1Y6vLe7upUy{TU7Y*W$<L%xtTFaiy}-N7h?K^5H?*g7<2|ves+xK z=Jh_4Zr+@(*kVnFZ!s)-`HSdHR)KsJvDAA)ztpiY$1LO%opr0Q`Xs7CNj5=;Y1fhPbPkG3e# m1~ef#iDEB`eWIK&1Mq*GU29gOB>;c`0000K3Qu2Ui?QSGqaS$g#!(2Y$gT^8X0+cG7=m{h3FO%eAgB*ZR+jMc?yg% N22WQ%mvv4FO#rmpet!S} literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..edc4d67cf3e801c9237ff18aac8fef0a66e177e2 GIT binary patch literal 2599 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 D5XD<4 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..edaae30ba394cb0e8d3cac2667d4ac481d88ef36 GIT binary patch literal 304 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 Ef=)PrOV6yUbaSW+oe0$K4vB7|WdBZwC zi?Rpt3M*bre`53fFO!eS0Uzcwqr_+!pr?Z~{N)+Ua=g!~PXQAXgQu&X%Q~loCIC}3 B_(=c& literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..03a8cf238a9e7a9837c44b1e06ca54afc5865e19 GIT binary patch literal 3620 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp new file mode 100644 index 0000000000000000000000000000000000000000..03a8cf238a9e7a9837c44b1e06ca54afc5865e19 GIT binary patch literal 3620 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..95c4b6e6637c36b6613a762b623f687d235fb2f4 GIT binary patch literal 3108 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..1dadd8d78b2f86c71f5bc4734ee71a239b45d696 GIT binary patch literal 897 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 LNkvXXu0mjfd~+vT literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..60c519d816a2d3b5ef4155cb405f9f255fab99d7 GIT binary patch literal 5345 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 LYlf*pJ4gQ);``&l literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp new file mode 100644 index 0000000000000000000000000000000000000000..5f09067779e27c5cf96f544d64274f80780eb3a6 GIT binary patch literal 1545 zcmeAS@N?(olHy`uVBq!ia0y~yVB7%09Be?56MhC-3=FInJY5_^Dj44$+{oKtz`(r0 zWWGVkga6DA`#iRtFTStOV6cp_!I77NCyOB=fSI9Lib3KE!+`~C3~Z(h1}jFTMnhvX kZH#7z(ZXTSl!t!{rC81dcKtgFEaDkFUHx3vIVCg!0Mox-kpKVy literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp new file mode 100644 index 0000000000000000000000000000000000000000..eebcfe7fe3b126026e7d2dd28cf16c4d6010da79 GIT binary patch literal 8123 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp new file mode 100644 index 0000000000000000000000000000000000000000..eebcfe7fe3b126026e7d2dd28cf16c4d6010da79 GIT binary patch literal 8123 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 literal 0 HcmV?d00001 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..84a79e444b25f788166c3631db06aaaa5a9f174f GIT binary patch literal 6553 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 + #FFFFFF + #212529 + #023c69 + #ffffff + #ffd000 + \ No newline at end of file diff --git a/mobile/android/app/src/main/res/values/strings.xml b/mobile/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..3583dc6 --- /dev/null +++ b/mobile/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Skur + \ No newline at end of file diff --git a/mobile/android/app/src/main/res/values/styles.xml b/mobile/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..1e7eb74 --- /dev/null +++ b/mobile/android/app/src/main/res/values/styles.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle new file mode 100644 index 0000000..0554dd1 --- /dev/null +++ b/mobile/android/build.gradle @@ -0,0 +1,24 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath('com.android.tools.build:gradle') + classpath('com.facebook.react:react-native-gradle-plugin') + classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') + } +} + +allprojects { + repositories { + google() + mavenCentral() + maven { url 'https://www.jitpack.io' } + } +} + +apply plugin: "expo-root-project" +apply plugin: "com.facebook.react.rootproject" diff --git a/mobile/android/gradle.properties b/mobile/android/gradle.properties new file mode 100644 index 0000000..cd98214 --- /dev/null +++ b/mobile/android/gradle.properties @@ -0,0 +1,68 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Enable AAPT2 PNG crunching +android.enablePngCrunchInReleaseBuilds=true + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true + +# Use this property to enable edge-to-edge display support. +# This allows your app to draw behind system bars for an immersive UI. +# Note: Only works with ReactActivity and should not be used with custom Activity. +edgeToEdgeEnabled=true + +# Enable GIF support in React Native images (~200 B increase) +expo.gif.enabled=true +# Enable webp support in React Native images (~85 KB increase) +expo.webp.enabled=true +# Enable animated webp support (~3.4 MB increase) +# Disabled by default because iOS doesn't support animated webp +expo.webp.animated=false + +# Enable network inspector +EX_DEV_CLIENT_NETWORK_INSPECTOR=true + +# Use legacy packaging to compress native libraries in the resulting APK. +expo.useLegacyPackaging=false + +expo.inlineModules.watchedDirectories=[] +# Local workaround for a slow/flaky network: give HTTP fetches room before failing. +systemProp.org.gradle.internal.http.connectionTimeout=120000 +systemProp.org.gradle.internal.http.socketTimeout=120000 +systemProp.sun.net.inetaddr.negative.ttl=0 +systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle.properties.bak2 b/mobile/android/gradle.properties.bak2 new file mode 100644 index 0000000..87f01ab --- /dev/null +++ b/mobile/android/gradle.properties.bak2 @@ -0,0 +1,68 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Enable AAPT2 PNG crunching +android.enablePngCrunchInReleaseBuilds=true + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true + +# Use this property to enable edge-to-edge display support. +# This allows your app to draw behind system bars for an immersive UI. +# Note: Only works with ReactActivity and should not be used with custom Activity. +edgeToEdgeEnabled=true + +# Enable GIF support in React Native images (~200 B increase) +expo.gif.enabled=true +# Enable webp support in React Native images (~85 KB increase) +expo.webp.enabled=true +# Enable animated webp support (~3.4 MB increase) +# Disabled by default because iOS doesn't support animated webp +expo.webp.animated=false + +# Enable network inspector +EX_DEV_CLIENT_NETWORK_INSPECTOR=true + +# Use legacy packaging to compress native libraries in the resulting APK. +expo.useLegacyPackaging=false + +expo.inlineModules.watchedDirectories=[] +# Local workaround for a slow/flaky network: give HTTP fetches room before failing. +systemProp.org.gradle.internal.http.connectionTimeout=120000 +systemProp.org.gradle.internal.http.socketTimeout=120000 +systemProp.sun.net.inetaddr.negative.ttl=0 +systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle.properties.bak3 b/mobile/android/gradle.properties.bak3 new file mode 100644 index 0000000..b6e3114 --- /dev/null +++ b/mobile/android/gradle.properties.bak3 @@ -0,0 +1,68 @@ +# Project-wide Gradle settings. + +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. + +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html + +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m +org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m --enable-native-access=ALL-UNNAMED --sun-misc-unsafe-memory-access=allow + +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true + +# Enable AAPT2 PNG crunching +android.enablePngCrunchInReleaseBuilds=true + +# Use this property to specify which architecture you want to build. +# You can also override it from the CLI using +# ./gradlew -PreactNativeArchitectures=x86_64 +reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 + +# Use this property to enable support to the new architecture. +# This will allow you to use TurboModules and the Fabric render in +# your application. You should enable this flag either if you want +# to write custom TurboModules/Fabric components OR use libraries that +# are providing them. +newArchEnabled=true + +# Use this property to enable or disable the Hermes JS engine. +# If set to false, you will be using JSC instead. +hermesEnabled=true + +# Use this property to enable edge-to-edge display support. +# This allows your app to draw behind system bars for an immersive UI. +# Note: Only works with ReactActivity and should not be used with custom Activity. +edgeToEdgeEnabled=true + +# Enable GIF support in React Native images (~200 B increase) +expo.gif.enabled=true +# Enable webp support in React Native images (~85 KB increase) +expo.webp.enabled=true +# Enable animated webp support (~3.4 MB increase) +# Disabled by default because iOS doesn't support animated webp +expo.webp.animated=false + +# Enable network inspector +EX_DEV_CLIENT_NETWORK_INSPECTOR=true + +# Use legacy packaging to compress native libraries in the resulting APK. +expo.useLegacyPackaging=false + +expo.inlineModules.watchedDirectories=[] +# Local workaround for a slow/flaky network: give HTTP fetches room before failing. +systemProp.org.gradle.internal.http.connectionTimeout=120000 +systemProp.org.gradle.internal.http.socketTimeout=120000 +systemProp.sun.net.inetaddr.negative.ttl=0 +systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.jar b/mobile/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..61285a659d17295f1de7c53e24fdf13ad755c379 GIT binary patch literal 46175 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

      pVX@HRij*jw$g4?}Pn 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 literal 0 HcmV?d00001 diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.properties b/mobile/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..d9a9aec --- /dev/null +++ b/mobile/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://github.com/gradle/gradle-distributions/releases/download/v9.3.1/gradle-9.3.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak b/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak new file mode 100644 index 0000000..37f78a6 --- /dev/null +++ b/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/mobile/android/gradlew b/mobile/android/gradlew new file mode 100755 index 0000000..adff685 --- /dev/null +++ b/mobile/android/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/mobile/android/gradlew.bat b/mobile/android/gradlew.bat new file mode 100644 index 0000000..39baf4d --- /dev/null +++ b/mobile/android/gradlew.bat @@ -0,0 +1,98 @@ +@REM Copyright (c) Meta Platforms, Inc. and affiliates. +@REM +@REM This source code is licensed under the MIT license found in the +@REM LICENSE file in the root directory of this source tree. + +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/mobile/android/settings.gradle b/mobile/android/settings.gradle new file mode 100644 index 0000000..a1d366e --- /dev/null +++ b/mobile/android/settings.gradle @@ -0,0 +1,39 @@ +pluginManagement { + def reactNativeGradlePlugin = new File( + providers.exec { + workingDir(rootDir) + commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })") + }.standardOutput.asText.get().trim() + ).getParentFile().absolutePath + includeBuild(reactNativeGradlePlugin) + + def expoPluginsPath = new File( + providers.exec { + workingDir(rootDir) + commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })") + }.standardOutput.asText.get().trim(), + "../android/expo-gradle-plugin" + ).absolutePath + includeBuild(expoPluginsPath) +} + +plugins { + id("com.facebook.react.settings") + id("expo-autolinking-settings") +} + +extensions.configure(com.facebook.react.ReactSettingsExtension) { ex -> + if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') { + ex.autolinkLibrariesFromCommand() + } else { + ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand) + } +} +expoAutolinking.useExpoModules() + +rootProject.name = 'Skur' + +expoAutolinking.useExpoVersionCatalog() + +include ':app' +includeBuild(expoAutolinking.reactNativeGradlePlugin) diff --git a/mobile/app.json b/mobile/app.json deleted file mode 100644 index bab9179..0000000 --- a/mobile/app.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "expo": { - "name": "Skur", - "slug": "skur", - "scheme": "skur", - "version": "0.1.0", - "orientation": "portrait", - "icon": "./assets/icon.png", - "userInterfaceStyle": "dark", - "backgroundColor": "#ffffff", - "splash": { - "image": "./assets/splash-icon.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff", - "imageWidth": 120 - }, - "ios": { - "supportsTablet": false, - "bundleIdentifier": "io.skur.vault", - "infoPlist": { - "NSFaceIDUsageDescription": "Skur uses Face ID to approve signatures from this device.", - "NSCameraUsageDescription": "Skur uses the camera only to read a vault or recipient address from a QR code." - }, - "usePrecompiledModules": false - }, - "android": { - "package": "io.skur.vault", - "adaptiveIcon": { - "backgroundColor": "#212529", - "foregroundImage": "./assets/android-icon-foreground.png", - "backgroundImage": "./assets/android-icon-background.png", - "monochromeImage": "./assets/android-icon-monochrome.png" - }, - "predictiveBackGestureEnabled": false - }, - "plugins": [ - "expo-secure-store", - "expo-local-authentication", - "expo-font", - [ - "expo-camera", - { - "cameraPermission": "Skur uses the camera only to read a vault or recipient address from a QR code." - } - ], - [ - "expo-notifications", - { - "icon": "./assets/android-icon-monochrome.png", - "color": "#ffd000" - } - ] - ] - } -} \ No newline at end of file diff --git a/mobile/assets/android-icon-background.png b/mobile/assets/android-icon-background.png deleted file mode 100644 index f1d3b7dc929c0dbb72bcdc6b0c9048e0dec8af45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5236 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7&w@K)Q9>#R~Q%s7(87ZLn`LHxo*hIpdi4o zk^dkEGxI-Qr6*D1cc1TLWMGiG22?Bw(xEs?jE2EzIvC9cqea1JNjO>(j+TU@CE;jE zI9d{pmV~1v;b=)XS`rT7lCYK|Di$~}APX7`7>&pw9Fe1uHyU{~YLCb>F#P|2QLC&0 fSlhFK3JPY103VK`BHOM4pa_GftDnm{r-UW|vsSAn diff --git a/mobile/assets/android-icon-foreground.png b/mobile/assets/android-icon-foreground.png deleted file mode 100644 index 52502da10fb26ece6096647d7d7ccf54a8783fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19781 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 diff --git a/mobile/assets/icon.png b/mobile/assets/icon.png deleted file mode 100644 index 14e4967fca6fc76747beeb9dc4111da1d1fb90c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28809 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 diff --git a/mobile/assets/splash-icon.png b/mobile/assets/splash-icon.png deleted file mode 100644 index 52502da10fb26ece6096647d7d7ccf54a8783fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19781 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 podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] + use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] + + use_react_native!( + :path => config[:reactNativePath], + :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', + # An absolute path to your application root. + :app_path => "#{Pod::Config.instance.installation_root}/..", + :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false', + ) + + post_install do |installer| + react_native_post_install( + installer, + config[:reactNativePath], + :mac_catalyst_enabled => false, + :ccache_enabled => ccache_enabled?(podfile_properties), + ) + end +end diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock new file mode 100644 index 0000000..d03c2ae --- /dev/null +++ b/mobile/ios/Podfile.lock @@ -0,0 +1,2472 @@ +PODS: + - EXApplication (57.0.3): + - ExpoModulesCore + - EXConstants (57.0.18): + - ExpoModulesCore + - Expo (57.0.23): + - ExpoModulesCore + - ExpoModulesJSI + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTAppDelegate + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactAppDependencyProvider + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - ExpoAsset (57.0.17): + - ExpoModulesCore + - ExpoCamera (57.0.5): + - ExpoModulesCore + - ExpoCameraBarcodeScanning (57.0.5): + - ExpoCamera + - ZXingObjC/OneD + - ZXingObjC/PDF417 + - ExpoClipboard (57.0.2): + - ExpoModulesCore + - ExpoDomWebView (57.0.1): + - ExpoModulesCore + - ExpoFileSystem (57.0.7): + - ExpoModulesCore + - ExpoFont (57.0.4): + - ExpoModulesCore + - ExpoKeepAwake (57.0.2): + - ExpoModulesCore + - ExpoLinking (57.0.10): + - ExpoModulesCore + - ExpoLocalAuthentication (57.0.3): + - ExpoModulesCore + - ExpoLogBox (57.0.4): + - React-Core + - ExpoModulesCore (57.0.18): + - ExpoModulesJSI + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - ExpoModulesJSI (57.1.0): + - React-Core + - ReactCommon + - ExpoModulesWorklets (57.0.18): + - ExpoModulesCore + - ExpoModulesJSI + - ExpoNotifications (57.0.19): + - ExpoModulesCore + - ExpoSecureStore (57.0.4): + - ExpoModulesCore + - FBLazyVector (0.86.3) + - hermes-engine (250829098.0.17): + - hermes-engine/cdp (= 250829098.0.17) + - hermes-engine/Hermes (= 250829098.0.17) + - hermes-engine/Public (= 250829098.0.17) + - hermes-engine/cdp (250829098.0.17) + - hermes-engine/Hermes (250829098.0.17) + - hermes-engine/Public (250829098.0.17) + - RCTDeprecation (0.86.3) + - RCTRequired (0.86.3) + - RCTSwiftUI (0.86.3) + - RCTSwiftUIWrapper (0.86.3): + - RCTSwiftUI + - RCTTypeSafety (0.86.3): + - FBLazyVector (= 0.86.3) + - RCTRequired (= 0.86.3) + - React-Core (= 0.86.3) + - React (0.86.3): + - React-Core (= 0.86.3) + - React-Core/DevSupport (= 0.86.3) + - React-Core/RCTWebSocket (= 0.86.3) + - React-RCTActionSheet (= 0.86.3) + - React-RCTAnimation (= 0.86.3) + - React-RCTBlob (= 0.86.3) + - React-RCTImage (= 0.86.3) + - React-RCTLinking (= 0.86.3) + - React-RCTNetwork (= 0.86.3) + - React-RCTSettings (= 0.86.3) + - React-RCTText (= 0.86.3) + - React-RCTVibration (= 0.86.3) + - React-callinvoker (0.86.3) + - React-Core (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.86.3) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core-prebuilt (0.86.3): + - ReactNativeDependencies + - React-Core/CoreModulesHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/Default (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/DevSupport (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.86.3) + - React-Core/RCTWebSocket (= 0.86.3) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTActionSheetHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTAnimationHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTBlobHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTImageHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTLinkingHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTNetworkHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTSettingsHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTTextHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTVibrationHeaders (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-Core/RCTWebSocket (0.86.3): + - hermes-engine + - RCTDeprecation + - React-Core-prebuilt + - React-Core/Default (= 0.86.3) + - React-cxxreact + - React-featureflags + - React-hermes + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsinspectorcdp + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-CoreModules (0.86.3): + - RCTTypeSafety (= 0.86.3) + - React-Core-prebuilt + - React-Core/CoreModulesHeaders (= 0.86.3) + - React-debug + - React-featureflags + - React-jsi (= 0.86.3) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-NativeModulesApple + - React-RCTBlob + - React-RCTFBReactNativeSpec + - React-RCTImage (= 0.86.3) + - React-runtimeexecutor + - React-utils + - ReactCommon + - ReactNativeDependencies + - React-cxxreact (0.86.3): + - hermes-engine + - React-callinvoker (= 0.86.3) + - React-Core-prebuilt + - React-debug (= 0.86.3) + - React-jsi (= 0.86.3) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-logger (= 0.86.3) + - React-perflogger (= 0.86.3) + - React-runtimeexecutor + - React-timing (= 0.86.3) + - React-utils + - ReactNativeDependencies + - React-debug (0.86.3): + - React-debug/redbox (= 0.86.3) + - React-debug/redbox (0.86.3) + - React-defaultsnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-domnativemodule + - React-Fabric/animated + - React-featureflags + - React-featureflagsnativemodule + - React-idlecallbacksnativemodule + - React-intersectionobservernativemodule + - React-jsi + - React-jsiexecutor + - React-microtasksnativemodule + - React-mutationobservernativemodule + - React-RCTFBReactNativeSpec + - React-viewtransitionnativemodule + - React-webperformancenativemodule + - ReactNativeDependencies + - Yoga + - React-domnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-Fabric + - React-Fabric/bridging + - React-FabricComponents + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-Fabric (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animated (= 0.86.3) + - React-Fabric/animationbackend (= 0.86.3) + - React-Fabric/animations (= 0.86.3) + - React-Fabric/attributedstring (= 0.86.3) + - React-Fabric/bridging (= 0.86.3) + - React-Fabric/componentregistry (= 0.86.3) + - React-Fabric/componentregistrynative (= 0.86.3) + - React-Fabric/components (= 0.86.3) + - React-Fabric/consistency (= 0.86.3) + - React-Fabric/core (= 0.86.3) + - React-Fabric/dom (= 0.86.3) + - React-Fabric/imagemanager (= 0.86.3) + - React-Fabric/leakchecker (= 0.86.3) + - React-Fabric/mounting (= 0.86.3) + - React-Fabric/observers (= 0.86.3) + - React-Fabric/scheduler (= 0.86.3) + - React-Fabric/telemetry (= 0.86.3) + - React-Fabric/uimanager (= 0.86.3) + - React-Fabric/viewtransition (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animated (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animationbackend + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animationbackend (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/animations (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/attributedstring (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/bridging (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/componentregistry (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/componentregistrynative (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/components/legacyviewmanagerinterop (= 0.86.3) + - React-Fabric/components/root (= 0.86.3) + - React-Fabric/components/scrollview (= 0.86.3) + - React-Fabric/components/view (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/legacyviewmanagerinterop (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/root (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/scrollview (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/components/view (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-Fabric/consistency (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/core (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/dom (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/imagemanager (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/leakchecker (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/mounting (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-jsinspectortracing + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/observers/events (= 0.86.3) + - React-Fabric/observers/intersection (= 0.86.3) + - React-Fabric/observers/mutation (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers/events (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers/intersection (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/observers/mutation (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/scheduler (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/animationbackend + - React-Fabric/observers/events + - React-Fabric/viewtransition + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-performancecdpmetrics + - React-performancetimeline + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/telemetry (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/uimanager (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric/uimanager/consistency (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/uimanager/consistency (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-Fabric/viewtransition (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-FabricComponents (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components (= 0.86.3) + - React-FabricComponents/textlayoutmanager (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-FabricComponents/components/inputaccessory (= 0.86.3) + - React-FabricComponents/components/iostextinput (= 0.86.3) + - React-FabricComponents/components/modal (= 0.86.3) + - React-FabricComponents/components/rncore (= 0.86.3) + - React-FabricComponents/components/safeareaview (= 0.86.3) + - React-FabricComponents/components/scrollview (= 0.86.3) + - React-FabricComponents/components/switch (= 0.86.3) + - React-FabricComponents/components/text (= 0.86.3) + - React-FabricComponents/components/textinput (= 0.86.3) + - React-FabricComponents/components/unimplementedview (= 0.86.3) + - React-FabricComponents/components/virtualview (= 0.86.3) + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/inputaccessory (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/iostextinput (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/modal (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/rncore (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/safeareaview (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/scrollview (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/switch (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/text (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/textinput (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/unimplementedview (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/components/virtualview (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricComponents/textlayoutmanager (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-RCTFBReactNativeSpec + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-FabricImage (0.86.3): + - hermes-engine + - RCTRequired (= 0.86.3) + - RCTTypeSafety (= 0.86.3) + - React-Core-prebuilt + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsiexecutor (= 0.86.3) + - React-logger + - React-rendererdebug + - React-utils + - ReactCommon + - ReactNativeDependencies + - Yoga + - React-featureflags (0.86.3): + - React-Core-prebuilt + - ReactNativeDependencies + - React-featureflagsnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-graphics (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-rendererdebug + - React-utils + - ReactNativeDependencies + - React-hermes (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact (= 0.86.3) + - React-jsi + - React-jsiexecutor (= 0.86.3) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-oscompat + - React-perflogger (= 0.86.3) + - React-runtimeexecutor + - ReactNativeDependencies + - React-idlecallbacksnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-ImageManager (0.86.3): + - React-Core-prebuilt + - React-Core/Default + - React-debug + - React-Fabric + - React-graphics + - React-rendererdebug + - React-utils + - ReactNativeDependencies + - React-intersectionobservernativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-Fabric + - React-Fabric/bridging + - React-graphics + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - React-runtimescheduler + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-jserrorhandler (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - ReactCommon/turbomodule/bridging + - ReactNativeDependencies + - React-jsi (0.86.3): + - hermes-engine + - React-Core-prebuilt + - ReactNativeDependencies + - React-jsiexecutor (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-jserrorhandler + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-perflogger + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsinspector (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-jsinspectortracing + - React-oscompat + - React-perflogger (= 0.86.3) + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsinspectorcdp (0.86.3): + - React-Core-prebuilt + - ReactNativeDependencies + - React-jsinspectornetwork (0.86.3): + - React-Core-prebuilt + - React-jsinspectorcdp + - ReactNativeDependencies + - React-jsinspectortracing (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsinspectornetwork + - React-oscompat + - React-timing + - React-utils + - ReactNativeDependencies + - React-jsitooling (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact (= 0.86.3) + - React-debug + - React-jsi (= 0.86.3) + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-jsitracing (0.86.3): + - React-jsi + - React-logger (0.86.3): + - React-Core-prebuilt + - ReactNativeDependencies + - React-Mapbuffer (0.86.3): + - React-Core-prebuilt + - React-debug + - ReactNativeDependencies + - React-microtasksnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-mutationobservernativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-Fabric + - React-Fabric/bridging + - React-Fabric/observers/mutation + - React-featureflags + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-get-random-values (1.11.0): + - React-Core + - react-native-safe-area-context (5.7.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common (= 5.7.0) + - react-native-safe-area-context/fabric (= 5.7.0) + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-safe-area-context/common (5.7.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - react-native-safe-area-context/fabric (5.7.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - react-native-safe-area-context/common + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-NativeModulesApple (0.86.3): + - hermes-engine + - React-callinvoker + - React-Core + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - React-networking (0.86.3): + - React-Core-prebuilt + - React-jsinspectornetwork + - React-jsinspectortracing + - React-performancetimeline + - React-timing + - ReactNativeDependencies + - React-oscompat (0.86.3) + - React-perflogger (0.86.3): + - React-Core-prebuilt + - ReactNativeDependencies + - React-performancecdpmetrics (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-jsi + - React-performancetimeline + - React-runtimeexecutor + - React-timing + - ReactNativeDependencies + - React-performancetimeline (0.86.3): + - React-Core-prebuilt + - React-featureflags + - React-jsinspector + - React-jsinspectortracing + - React-perflogger + - React-timing + - ReactNativeDependencies + - React-RCTActionSheet (0.86.3): + - React-Core/RCTActionSheetHeaders (= 0.86.3) + - React-RCTAnimation (0.86.3): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTAnimationHeaders + - React-debug + - React-featureflags + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTAppDelegate (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-CoreModules + - React-debug + - React-defaultsnativemodule + - React-Fabric + - React-featureflags + - React-graphics + - React-hermes + - React-jsitooling + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTNetwork + - React-RCTRuntime + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactCommon + - ReactNativeDependencies + - React-RCTBlob (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-Core/RCTBlobHeaders + - React-Core/RCTWebSocket + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - ReactNativeDependencies + - React-RCTFabric (0.86.3): + - hermes-engine + - RCTSwiftUIWrapper + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-FabricComponents + - React-FabricImage + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-networking + - React-performancecdpmetrics + - React-performancetimeline + - React-RCTAnimation + - React-RCTFBReactNativeSpec + - React-RCTImage + - React-RCTText + - React-rendererconsistency + - React-renderercss + - React-rendererdebug + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - Yoga + - React-RCTFBReactNativeSpec (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec/components (= 0.86.3) + - ReactCommon + - ReactNativeDependencies + - React-RCTFBReactNativeSpec/components (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-jsi + - React-NativeModulesApple + - React-rendererdebug + - React-utils + - ReactCommon + - ReactNativeDependencies + - Yoga + - React-RCTImage (0.86.3): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTImageHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - React-RCTNetwork + - ReactCommon + - ReactNativeDependencies + - React-RCTLinking (0.86.3): + - React-Core/RCTLinkingHeaders (= 0.86.3) + - React-jsi (= 0.86.3) + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactCommon/turbomodule/core (= 0.86.3) + - React-RCTNetwork (0.86.3): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTNetworkHeaders + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectorcdp + - React-jsinspectornetwork + - React-NativeModulesApple + - React-networking + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTRuntime (0.86.3): + - hermes-engine + - React-Core + - React-Core-prebuilt + - React-debug + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-RuntimeApple + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-utils + - ReactNativeDependencies + - React-RCTSettings (0.86.3): + - RCTTypeSafety + - React-Core-prebuilt + - React-Core/RCTSettingsHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-RCTText (0.86.3): + - React-Core/RCTTextHeaders (= 0.86.3) + - Yoga + - React-RCTVibration (0.86.3): + - React-Core-prebuilt + - React-Core/RCTVibrationHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTFBReactNativeSpec + - ReactCommon + - ReactNativeDependencies + - React-rendererconsistency (0.86.3) + - React-renderercss (0.86.3): + - React-debug + - React-utils + - React-rendererdebug (0.86.3): + - React-Core-prebuilt + - React-debug + - ReactNativeDependencies + - React-RuntimeApple (0.86.3): + - hermes-engine + - React-callinvoker + - React-Core-prebuilt + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RCTFBReactNativeSpec + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - React-RuntimeCore (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-Fabric + - React-featureflags + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-jsinspector + - React-jsitooling + - React-performancetimeline + - React-runtimeexecutor + - React-runtimescheduler + - React-utils + - ReactNativeDependencies + - React-runtimeexecutor (0.86.3): + - React-Core-prebuilt + - React-debug + - React-featureflags + - React-jsi (= 0.86.3) + - React-utils + - ReactNativeDependencies + - React-RuntimeHermes (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-featureflags + - React-hermes + - React-jsi + - React-jsinspector + - React-jsinspectorcdp + - React-jsinspectortracing + - React-jsitooling + - React-jsitracing + - React-RuntimeCore + - React-runtimeexecutor + - React-utils + - ReactNativeDependencies + - React-runtimescheduler (0.86.3): + - hermes-engine + - React-callinvoker + - React-Core-prebuilt + - React-cxxreact + - React-debug + - React-featureflags + - React-jsi + - React-jsinspectortracing + - React-performancetimeline + - React-rendererconsistency + - React-rendererdebug + - React-runtimeexecutor + - React-timing + - React-utils + - ReactNativeDependencies + - React-timing (0.86.3): + - React-debug + - React-utils (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-debug + - React-jsi (= 0.86.3) + - ReactNativeDependencies + - React-viewtransitionnativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-Fabric + - React-Fabric/bridging + - React-jsi + - React-jsiexecutor + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - React-webperformancenativemodule (0.86.3): + - hermes-engine + - React-Core-prebuilt + - React-cxxreact + - React-jsi + - React-jsiexecutor + - React-performancetimeline + - React-RCTFBReactNativeSpec + - React-runtimeexecutor + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - ReactAppDependencyProvider (0.86.3): + - ReactCodegen + - ReactCodegen (0.86.3): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-FabricImage + - React-featureflags + - React-graphics + - React-jsi + - React-jsiexecutor + - React-NativeModulesApple + - React-RCTAppDelegate + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - ReactCommon (0.86.3): + - React-Core-prebuilt + - ReactCommon/turbomodule (= 0.86.3) + - ReactNativeDependencies + - ReactCommon/turbomodule (0.86.3): + - hermes-engine + - React-callinvoker (= 0.86.3) + - React-Core-prebuilt + - React-cxxreact (= 0.86.3) + - React-jsi (= 0.86.3) + - React-logger (= 0.86.3) + - React-perflogger (= 0.86.3) + - ReactCommon/turbomodule/bridging (= 0.86.3) + - ReactCommon/turbomodule/core (= 0.86.3) + - ReactNativeDependencies + - ReactCommon/turbomodule/bridging (0.86.3): + - hermes-engine + - React-callinvoker (= 0.86.3) + - React-Core-prebuilt + - React-cxxreact (= 0.86.3) + - React-jsi (= 0.86.3) + - React-logger (= 0.86.3) + - React-perflogger (= 0.86.3) + - ReactNativeDependencies + - ReactCommon/turbomodule/core (0.86.3): + - hermes-engine + - React-callinvoker (= 0.86.3) + - React-Core-prebuilt + - React-cxxreact (= 0.86.3) + - React-debug (= 0.86.3) + - React-featureflags (= 0.86.3) + - React-jsi (= 0.86.3) + - React-logger (= 0.86.3) + - React-perflogger (= 0.86.3) + - React-utils (= 0.86.3) + - ReactNativeDependencies + - ReactNativeDependencies (0.86.3) + - RNCAsyncStorage (2.2.0): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - RNScreens (4.26.2): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - RNScreens/common (= 4.26.2) + - Yoga + - RNScreens/common (4.26.2): + - hermes-engine + - RCTRequired + - RCTTypeSafety + - React-Core + - React-Core-prebuilt + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-jsi + - React-NativeModulesApple + - React-RCTFabric + - React-RCTImage + - React-renderercss + - React-rendererdebug + - React-utils + - ReactCodegen + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - ReactNativeDependencies + - Yoga + - Yoga (0.0.0) + - ZXingObjC/Core (3.6.9) + - ZXingObjC/OneD (3.6.9): + - ZXingObjC/Core + - ZXingObjC/PDF417 (3.6.9): + - ZXingObjC/Core + +DEPENDENCIES: + - EXApplication (from `../node_modules/expo-application/ios`) + - EXConstants (from `../node_modules/expo-constants/ios`) + - Expo (from `../node_modules/expo`) + - ExpoAsset (from `../node_modules/expo/node_modules/expo-asset/ios`) + - ExpoCamera (from `../node_modules/expo-camera/ios`) + - ExpoCameraBarcodeScanning (from `../node_modules/expo-camera/ios`) + - ExpoClipboard (from `../node_modules/expo-clipboard/ios`) + - "ExpoDomWebView (from `../node_modules/expo/node_modules/@expo/dom-webview/ios`)" + - ExpoFileSystem (from `../node_modules/expo/node_modules/expo-file-system/ios`) + - ExpoFont (from `../node_modules/expo-font/ios`) + - ExpoKeepAwake (from `../node_modules/expo/node_modules/expo-keep-awake/ios`) + - ExpoLinking (from `../node_modules/expo-linking/ios`) + - ExpoLocalAuthentication (from `../node_modules/expo-local-authentication/ios`) + - "ExpoLogBox (from `../node_modules/expo/node_modules/@expo/log-box`)" + - ExpoModulesCore (from `../node_modules/expo-modules-core`) + - ExpoModulesJSI (from `../node_modules/expo-modules-jsi/apple`) + - ExpoModulesWorklets (from `../node_modules/expo-modules-core`) + - ExpoNotifications (from `../node_modules/expo-notifications/ios`) + - ExpoSecureStore (from `../node_modules/expo-secure-store/ios`) + - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) + - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) + - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) + - RCTRequired (from `../node_modules/react-native/Libraries/Required`) + - RCTSwiftUI (from `../node_modules/react-native/ReactApple/RCTSwiftUI`) + - RCTSwiftUIWrapper (from `../node_modules/react-native/ReactApple/RCTSwiftUIWrapper`) + - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) + - React (from `../node_modules/react-native/`) + - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) + - React-Core (from `../node_modules/react-native/`) + - React-Core-prebuilt (from `../node_modules/react-native/React-Core-prebuilt.podspec`) + - React-Core/RCTWebSocket (from `../node_modules/react-native/`) + - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) + - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) + - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) + - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) + - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) + - React-FabricImage (from `../node_modules/react-native/ReactCommon`) + - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) + - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) + - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) + - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) + - React-intersectionobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver`) + - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) + - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) + - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`) + - React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`) + - React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`) + - React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) + - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) + - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) + - React-mutationobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver`) + - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) + - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) + - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`) + - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) + - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) + - React-performancecdpmetrics (from `../node_modules/react-native/ReactCommon/react/performance/cdpmetrics`) + - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) + - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) + - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) + - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) + - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) + - React-RCTFabric (from `../node_modules/react-native/React`) + - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) + - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) + - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) + - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) + - React-RCTRuntime (from `../node_modules/react-native/React/Runtime`) + - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) + - React-RCTText (from `../node_modules/react-native/Libraries/Text`) + - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) + - React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`) + - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) + - React-viewtransitionnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition`) + - React-webperformancenativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/webperformance`) + - ReactAppDependencyProvider (from `build/generated/ios/ReactAppDependencyProvider`) + - ReactCodegen (from `build/generated/ios/ReactCodegen`) + - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`) + - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" + - RNScreens (from `../node_modules/react-native-screens`) + - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) + +SPEC REPOS: + trunk: + - ZXingObjC + +EXTERNAL SOURCES: + EXApplication: + :path: "../node_modules/expo-application/ios" + EXConstants: + :path: "../node_modules/expo-constants/ios" + Expo: + :path: "../node_modules/expo" + ExpoAsset: + :path: "../node_modules/expo/node_modules/expo-asset/ios" + ExpoCamera: + :path: "../node_modules/expo-camera/ios" + ExpoCameraBarcodeScanning: + :path: "../node_modules/expo-camera/ios" + ExpoClipboard: + :path: "../node_modules/expo-clipboard/ios" + ExpoDomWebView: + :path: "../node_modules/expo/node_modules/@expo/dom-webview/ios" + ExpoFileSystem: + :path: "../node_modules/expo/node_modules/expo-file-system/ios" + ExpoFont: + :path: "../node_modules/expo-font/ios" + ExpoKeepAwake: + :path: "../node_modules/expo/node_modules/expo-keep-awake/ios" + ExpoLinking: + :path: "../node_modules/expo-linking/ios" + ExpoLocalAuthentication: + :path: "../node_modules/expo-local-authentication/ios" + ExpoLogBox: + :path: "../node_modules/expo/node_modules/@expo/log-box" + ExpoModulesCore: + :path: "../node_modules/expo-modules-core" + ExpoModulesJSI: + :path: "../node_modules/expo-modules-jsi/apple" + ExpoModulesWorklets: + :path: "../node_modules/expo-modules-core" + ExpoNotifications: + :path: "../node_modules/expo-notifications/ios" + ExpoSecureStore: + :path: "../node_modules/expo-secure-store/ios" + FBLazyVector: + :path: "../node_modules/react-native/Libraries/FBLazyVector" + hermes-engine: + :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-v250829098.0.17 + RCTDeprecation: + :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" + RCTRequired: + :path: "../node_modules/react-native/Libraries/Required" + RCTSwiftUI: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUI" + RCTSwiftUIWrapper: + :path: "../node_modules/react-native/ReactApple/RCTSwiftUIWrapper" + RCTTypeSafety: + :path: "../node_modules/react-native/Libraries/TypeSafety" + React: + :path: "../node_modules/react-native/" + React-callinvoker: + :path: "../node_modules/react-native/ReactCommon/callinvoker" + React-Core: + :path: "../node_modules/react-native/" + React-Core-prebuilt: + :podspec: "../node_modules/react-native/React-Core-prebuilt.podspec" + React-CoreModules: + :path: "../node_modules/react-native/React/CoreModules" + React-cxxreact: + :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" + React-defaultsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" + React-domnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" + React-Fabric: + :path: "../node_modules/react-native/ReactCommon" + React-FabricComponents: + :path: "../node_modules/react-native/ReactCommon" + React-FabricImage: + :path: "../node_modules/react-native/ReactCommon" + React-featureflags: + :path: "../node_modules/react-native/ReactCommon/react/featureflags" + React-featureflagsnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" + React-graphics: + :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" + React-hermes: + :path: "../node_modules/react-native/ReactCommon/hermes" + React-idlecallbacksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + React-intersectionobservernativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver" + React-jserrorhandler: + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" + React-jsi: + :path: "../node_modules/react-native/ReactCommon/jsi" + React-jsiexecutor: + :path: "../node_modules/react-native/ReactCommon/jsiexecutor" + React-jsinspector: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsinspectorcdp: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp" + React-jsinspectornetwork: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network" + React-jsinspectortracing: + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing" + React-jsitooling: + :path: "../node_modules/react-native/ReactCommon/jsitooling" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" + React-logger: + :path: "../node_modules/react-native/ReactCommon/logger" + React-Mapbuffer: + :path: "../node_modules/react-native/ReactCommon" + React-microtasksnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" + React-mutationobservernativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver" + react-native-get-random-values: + :path: "../node_modules/react-native-get-random-values" + react-native-safe-area-context: + :path: "../node_modules/react-native-safe-area-context" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" + React-networking: + :path: "../node_modules/react-native/ReactCommon/react/networking" + React-oscompat: + :path: "../node_modules/react-native/ReactCommon/oscompat" + React-perflogger: + :path: "../node_modules/react-native/ReactCommon/reactperflogger" + React-performancecdpmetrics: + :path: "../node_modules/react-native/ReactCommon/react/performance/cdpmetrics" + React-performancetimeline: + :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" + React-RCTActionSheet: + :path: "../node_modules/react-native/Libraries/ActionSheetIOS" + React-RCTAnimation: + :path: "../node_modules/react-native/Libraries/NativeAnimation" + React-RCTAppDelegate: + :path: "../node_modules/react-native/Libraries/AppDelegate" + React-RCTBlob: + :path: "../node_modules/react-native/Libraries/Blob" + React-RCTFabric: + :path: "../node_modules/react-native/React" + React-RCTFBReactNativeSpec: + :path: "../node_modules/react-native/React" + React-RCTImage: + :path: "../node_modules/react-native/Libraries/Image" + React-RCTLinking: + :path: "../node_modules/react-native/Libraries/LinkingIOS" + React-RCTNetwork: + :path: "../node_modules/react-native/Libraries/Network" + React-RCTRuntime: + :path: "../node_modules/react-native/React/Runtime" + React-RCTSettings: + :path: "../node_modules/react-native/Libraries/Settings" + React-RCTText: + :path: "../node_modules/react-native/Libraries/Text" + React-RCTVibration: + :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererconsistency: + :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" + React-renderercss: + :path: "../node_modules/react-native/ReactCommon/react/renderer/css" + React-rendererdebug: + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimeexecutor: + :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-timing: + :path: "../node_modules/react-native/ReactCommon/react/timing" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" + React-viewtransitionnativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition" + React-webperformancenativemodule: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/webperformance" + ReactAppDependencyProvider: + :path: build/generated/ios/ReactAppDependencyProvider + ReactCodegen: + :path: build/generated/ios/ReactCodegen + ReactCommon: + :path: "../node_modules/react-native/ReactCommon" + ReactNativeDependencies: + :podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec" + RNCAsyncStorage: + :path: "../node_modules/@react-native-async-storage/async-storage" + RNScreens: + :path: "../node_modules/react-native-screens" + Yoga: + :path: "../node_modules/react-native/ReactCommon/yoga" + +SPEC CHECKSUMS: + EXApplication: a727f05eb8592f0bc764f6ab8d51eacc158652ec + EXConstants: 8948a340eb14bf2bdaaa0e21a63cb9343860b87a + Expo: d06878ab7512dbcb2deec84c4d56f07af8a8b765 + ExpoAsset: b3999ffb3d4049b6c870708c60ea2209ace9f170 + ExpoCamera: c4c16b83b6db376e5a0e538fe2a04deafbb5b6d8 + ExpoCameraBarcodeScanning: 69275ab8ecd76f338da22df825c59405bcf36472 + ExpoClipboard: 15b8cc88075d7c50af165ed8fca0a76915903bba + ExpoDomWebView: beaec034e51bd028428b98bb1f2633ab79c6d095 + ExpoFileSystem: 28778f942725170102f7c6cf4dee05a526ddacd0 + ExpoFont: f8198a952ba2ff53c9b393b5269ea435f232cfc3 + ExpoKeepAwake: 72af0b3be3615e59bc819d26061ff4e06b155ee0 + ExpoLinking: 15c8ddb0eb4a778950712ea4a6feedf021778852 + ExpoLocalAuthentication: 1e4aef156a3a1f953f8278b8d8309f6118919640 + ExpoLogBox: 80957303325cd4439137765c90a87d7f22aaf2ff + ExpoModulesCore: 859b593d784f53f2a55224dd0b21e7c80556465e + ExpoModulesJSI: 9df8e7c9719f59e8c001ec33611774137fc1484a + ExpoModulesWorklets: 986cf72c18400743869b4642d243115f831e404d + ExpoNotifications: 098f80e610228da37ee98c0828931337cf5b1106 + ExpoSecureStore: ff1fd5e073957417ba8f9dec0bebcbd55a60e747 + FBLazyVector: 2138c6c2ab66c31bf5754dc18097fbc498a49c7f + hermes-engine: a1e4a1fbfc2f5de70c9a5c1454992f977a6337c6 + RCTDeprecation: 96f68ebf33f8762466b01d57d6e873c4f30efb07 + RCTRequired: 166eed8ad6d8440e73e56d09a9090366609823d2 + RCTSwiftUI: e818198d11928a78c2b2afe281d072171dab617f + RCTSwiftUIWrapper: b9457f8613a1d0c8146c08844a04154702ff8809 + RCTTypeSafety: efc19e6b92931abf0b68b064212323a258a5f019 + React: 52dce66f71097ed7a4968673d95eeb8095ded74e + React-callinvoker: afa0525ab27f4ffbb4c377f855fe9368edb099bc + React-Core: fdb67992e049f2526ade3e258c21b8404e7943a3 + React-Core-prebuilt: 9abc518a8aa7aa4fa3bbbe52bc825bcd9fb3c3ce + React-CoreModules: 456d91152aa283ddc6ae8abfcec3292af88912f6 + React-cxxreact: 73a20c0dde5ec221f98d5e4da0e71349ab48353d + React-debug: d06757ac6c78b84af0c31e513a83662d6b8d0ac7 + React-defaultsnativemodule: ad832e8ce045ef01ea586834b1732c3d4d4d5d86 + React-domnativemodule: 7d1bd200df2d58c2f61d416cf16838c0c9fbb06c + React-Fabric: 363e0524d0724a17afbcba653da4f3398f41236e + React-FabricComponents: d41c87cd39ccf6c4c1df7f726ced22db1f90f072 + React-FabricImage: b4fb0ebc0a2e6fabfd8de8b3fa441331bda99403 + React-featureflags: 1c88b4566806604500a8a9fdf9ad0108c2e9d541 + React-featureflagsnativemodule: dab00693f49c6629f186dedcc3cdaeadd094972f + React-graphics: 991a75fa954a20d0297580dc7fd4e365982cef3b + React-hermes: 65cfbf62d8d31c1e69f3556ff6836a2890cf4a62 + React-idlecallbacksnativemodule: 492f6da9e5a2fa37e2ac0c3a7447302a342d42c2 + React-ImageManager: 02effe13f7b0ca3a7282ee364a8691cd789b9726 + React-intersectionobservernativemodule: 91b54a39a2e7187b9caf62e8b7310aa2d0026679 + React-jserrorhandler: 91985482e35b0b102febda42168ee71946db9958 + React-jsi: 69052b2d1958c9069a143f1637f382b933917b43 + React-jsiexecutor: b9b98ea432f58ee2899a60204f090d0bc8d48313 + React-jsinspector: 75119552df2413c48d33e9f0a72836b30c1ccb14 + React-jsinspectorcdp: 8e65995e9083f7bce0839d3169f6f2d304049e2e + React-jsinspectornetwork: 7e8375e27430cc7694c52fb904db2b9118194480 + React-jsinspectortracing: 643bd9d6f9dc64ea9b28b0e915b4fb0b9b0b1b90 + React-jsitooling: b7ec4b982dfc62f744587deeb1948b983f9edaa4 + React-jsitracing: 8d2f0c8d6d81324606b6d55b946cb443a0c5a425 + React-logger: b9bf04943233973fece220497f0784eaad409b3a + React-Mapbuffer: 3c805ea54675b00ef1755f23b3c1fccf34962b93 + React-microtasksnativemodule: 97a771dbbb4315c71579995b53e4e3e351a99d89 + React-mutationobservernativemodule: 530bff1bba9511a5133e3cf8170e3b2c0df49e89 + react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba + react-native-safe-area-context: 6b4966397ada0f7dd481e4486a2ef936834861a1 + React-NativeModulesApple: 2b658272ca69df0694cf5d54f9510aa7c33977bc + React-networking: 6be0b80e18e710dd30e77b04838ec46666a7bb78 + React-oscompat: cea7c66df8076bd97e95885d7f584b86afffde41 + React-perflogger: 9110ba33a4aa70c708e9d50aeca040e6f2aefaf7 + React-performancecdpmetrics: d9c07c4855c5a975cc7abc482fcb086e8a87abd1 + React-performancetimeline: 336af57802d9cdb4ac079774007677031c891fe0 + React-RCTActionSheet: aeb20277150454e9020517c6a2cb70410d4856d9 + React-RCTAnimation: 8453deeb01d0f284202c9670b5f7d827575b4967 + React-RCTAppDelegate: 5e9c748cc138decd9045683d8987700d824a99ff + React-RCTBlob: e6c01cae3eeb7e63a55b12f72b7dfcfd8236b4b2 + React-RCTFabric: deab07276af1b74b0b8d0772a9a58cac15785312 + React-RCTFBReactNativeSpec: 83d67909e5c67b460bec8851d8413a8ce1ecc6b2 + React-RCTImage: ec8488bc119d7e5d3209f85be3ebda7e4a937c61 + React-RCTLinking: b6ff56c2f206127d49d338262418c097ea306ad0 + React-RCTNetwork: 08d71b365278511a9bb07885b4a54bdc510d99bf + React-RCTRuntime: 634c58094cc601bc2a63ef38b2389cf81143fbcb + React-RCTSettings: 372551bc9f30d26890f5c5fd569dcd15243c656c + React-RCTText: 62cff7e93aeb3c06e3634f1c59984e8c5322b542 + React-RCTVibration: 2e8c1630ae80c092f437db9638a03715f616ac03 + React-rendererconsistency: e8b244c284931cac80a30ce754d77f6c64e528f9 + React-renderercss: 97791244f7ff7a2a060d07acbf240261d4a0519c + React-rendererdebug: 9d023ca26ed3daf60e7b7615729bb7ba6027a96a + React-RuntimeApple: 2daf515379135ccd5e3af5306c90f7827428f4ca + React-RuntimeCore: 637867058de3e0ae7f1ef2653cd0e01c4c850d71 + React-runtimeexecutor: a5cdf5961ec221a40e6612f35bd1e23f84fd9702 + React-RuntimeHermes: 390a5605857f207c8261c75fd4a296ead9aeee0f + React-runtimescheduler: 1be91f9ec0417bb69bd8dfabbe11b07147b24538 + React-timing: bbb861d02c9bcee3e9c08c51a38f59d27c0904ce + React-utils: 28c555b582a9607a938cc0f47b5a7600db42393a + React-viewtransitionnativemodule: 3977270cf367fd1562221047e2358a26da174f2d + React-webperformancenativemodule: fb203d77856165582e519855fc13773a2855f9a6 + ReactAppDependencyProvider: bb350d1333fd459c1aabe782088419a9b8894d3a + ReactCodegen: 828f54f35f2bc4ee3f39345144ff0ec22c9535c2 + ReactCommon: 02f6a489d5eb4ab79d7deba5cd4434e0ba351a07 + ReactNativeDependencies: 6738e602b46fd24aa453cd58267ec3bb8bf29d27 + RNCAsyncStorage: 2ad919e88b8bc2cd80e8697ce66d04d006743283 + RNScreens: 7118cd7715c226856125b5bece3c4d9abec90356 + Yoga: 18b74b3ade30bebc1904004dfaceae1dd02a330a + ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 + +PODFILE CHECKSUM: 056772c7104740b5121837f3617d58290be47fa8 + +COCOAPODS: 1.17.0 diff --git a/mobile/ios/Podfile.properties.json b/mobile/ios/Podfile.properties.json new file mode 100644 index 0000000..95e5a41 --- /dev/null +++ b/mobile/ios/Podfile.properties.json @@ -0,0 +1,7 @@ +{ + "expo.jsEngine": "hermes", + "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true", + "expo.inlineModules.watchedDirectories": "[]", + "expo.inlineModules.xcodeProjectTargets": "{\"mainTarget\":\"Skur\",\"targets\":[]}", + "EXPO_USE_PRECOMPILED_MODULES": "false" +} \ No newline at end of file diff --git a/mobile/ios/Skur.xcodeproj/project.pbxproj b/mobile/ios/Skur.xcodeproj/project.pbxproj new file mode 100644 index 0000000..0be63c7 --- /dev/null +++ b/mobile/ios/Skur.xcodeproj/project.pbxproj @@ -0,0 +1,570 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; + 242B3214F71344004775440B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */; }; + 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; + 58D12312F746D2921935B260 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */; }; + BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; + D13F2AED329DF3390FC31857 /* libPods-Skur.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B846F60806D8065C4FC1076 /* libPods-Skur.a */; }; + F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = Skur/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 0B846F60806D8065C4FC1076 /* libPods-Skur.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Skur.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07F961A680F5B00A75B9A /* Skur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Skur.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Skur/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Skur/Info.plist; sourceTree = ""; }; + 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Skur.debug.xcconfig"; path = "Target Support Files/Pods-Skur/Pods-Skur.debug.xcconfig"; sourceTree = ""; }; + 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Skur/ExpoModulesProvider.swift"; sourceTree = ""; }; + 905D895957517020C305549E /* Pods-Skur.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Skur.release.xcconfig"; path = "Target Support Files/Pods-Skur/Pods-Skur.release.xcconfig"; sourceTree = ""; }; + AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Skur/SplashScreen.storyboard; sourceTree = ""; }; + BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; + ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; + F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Skur/AppDelegate.swift; sourceTree = ""; }; + F11748442D0722820044C1D9 /* Skur-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Skur-Bridging-Header.h"; path = "Skur/Skur-Bridging-Header.h"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D13F2AED329DF3390FC31857 /* libPods-Skur.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 13B07FAE1A68108700A75B9A /* Skur */ = { + isa = PBXGroup; + children = ( + F11748412D0307B40044C1D9 /* AppDelegate.swift */, + F11748442D0722820044C1D9 /* Skur-Bridging-Header.h */, + BB2F792B24A3F905000567C9 /* Supporting */, + 13B07FB51A68108700A75B9A /* Images.xcassets */, + 13B07FB61A68108700A75B9A /* Info.plist */, + AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */, + 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */, + ); + name = Skur; + sourceTree = ""; + }; + 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { + isa = PBXGroup; + children = ( + ED297162215061F000B7C4FE /* JavaScriptCore.framework */, + 0B846F60806D8065C4FC1076 /* libPods-Skur.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 832341AE1AAA6A7D00B99B32 /* Libraries */ = { + isa = PBXGroup; + children = ( + ); + name = Libraries; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* Skur */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 83CBBA001A601CBA00E9B192 /* Products */, + 2D16E6871FA4F8E400B85C8A /* Frameworks */, + DFB825BCD9BC0E07AB6AFF87 /* Pods */, + 87DCFAAEFA5DB25BC6833BB1 /* ExpoModulesProviders */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + usesTabs = 0; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* Skur.app */, + ); + name = Products; + sourceTree = ""; + }; + 87DCFAAEFA5DB25BC6833BB1 /* ExpoModulesProviders */ = { + isa = PBXGroup; + children = ( + AA51DD12C9A244FE59F73DAC /* Skur */, + ); + name = ExpoModulesProviders; + sourceTree = ""; + }; + AA51DD12C9A244FE59F73DAC /* Skur */ = { + isa = PBXGroup; + children = ( + 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */, + ); + name = Skur; + sourceTree = ""; + }; + BB2F792B24A3F905000567C9 /* Supporting */ = { + isa = PBXGroup; + children = ( + BB2F792C24A3F905000567C9 /* Expo.plist */, + ); + name = Supporting; + path = Skur/Supporting; + sourceTree = ""; + }; + DFB825BCD9BC0E07AB6AFF87 /* Pods */ = { + isa = PBXGroup; + children = ( + 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */, + 905D895957517020C305549E /* Pods-Skur.release.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 13B07F861A680F5B00A75B9A /* Skur */ = { + isa = PBXNativeTarget; + buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Skur" */; + buildPhases = ( + 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, + 4F45F064C519C0B967E3A074 /* [Expo] Configure project */, + 13B07F871A680F5B00A75B9A /* Sources */, + 13B07F8C1A680F5B00A75B9A /* Frameworks */, + 13B07F8E1A680F5B00A75B9A /* Resources */, + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, + 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, + D348159AE2F81BAF644E4C43 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Skur; + productName = Skur; + productReference = 13B07F961A680F5B00A75B9A /* Skur.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 83CBB9F71A601CBA00E9B192 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1130; + TargetAttributes = { + 13B07F861A680F5B00A75B9A = { + LastSwiftMigration = 1250; + }; + }; + }; + buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Skur" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 83CBB9F61A601CBA00E9B192; + productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 13B07F861A680F5B00A75B9A /* Skur */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 13B07F8E1A680F5B00A75B9A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BB2F792D24A3F905000567C9 /* Expo.plist in Resources */, + 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, + 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, + 242B3214F71344004775440B /* PrivacyInfo.xcprivacy in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env", + "$(SRCROOT)/.xcode.env.local", + ); + name = "Bundle React Native code and images"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n"; + }; + 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Skur-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 4F45F064C519C0B967E3A074 /* [Expo] Configure project */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/.xcode.env", + "$(SRCROOT)/.xcode.env.local", + "$(SRCROOT)/Skur/Skur.entitlements", + "$(SRCROOT)/Pods/Target Support Files/Pods-Skur/expo-configure-project.sh", + ); + name = "[Expo] Configure project"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/Pods/Target Support Files/Pods-Skur/ExpoModulesProvider.swift", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-Skur/expo-configure-project.sh\"\n"; + }; + 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/EXApplication/ExpoApplication_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/ExpoNotifications/ExpoNotifications_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/React-timing/React-timing_privacy.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoApplication_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoNotifications_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-timing_privacy.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + D348159AE2F81BAF644E4C43 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-frameworks.sh", + "${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/ios/hermesvm.framework", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesJSI/ExpoModulesJSI.framework/ExpoModulesJSI", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", + "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermesvm.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesJSI.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 13B07F871A680F5B00A75B9A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */, + 58D12312F746D2921935B260 /* ExpoModulesProvider.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 13B07F941A680F5B00A75B9A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Skur/Skur.entitlements; + CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "FB_SONARKIT_ENABLED=1", + ); + INFOPLIST_FILE = Skur/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.4; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; + PRODUCT_BUNDLE_IDENTIFIER = io.skur.vault; + PRODUCT_NAME = Skur; + SWIFT_OBJC_BRIDGING_HEADER = "Skur/Skur-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 13B07F951A680F5B00A75B9A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 905D895957517020C305549E /* Pods-Skur.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Skur/Skur.entitlements; + CURRENT_PROJECT_VERSION = 1; + INFOPLIST_FILE = Skur/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 13.4; + MARKETING_VERSION = 1.0; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + "-lc++", + ); + OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; + PRODUCT_BUNDLE_IDENTIFIER = io.skur.vault; + PRODUCT_NAME = Skur; + SWIFT_OBJC_BRIDGING_HEADER = "Skur/Skur-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 1; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + 83CBBA201A601CBA00E9B192 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); + OTHER_CPLUSPLUSFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); + PODFILE_DIR = "$(SRCROOT)"; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; + SWIFT_ENABLE_EXPLICIT_MODULES = NO; + USE_HERMES = true; + }; + name = Debug; + }; + 83CBBA211A601CBA00E9B192 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.4; + LD_RUNPATH_SEARCH_PATHS = ( + /usr/lib/swift, + "$(inherited)", + ); + LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); + OTHER_CPLUSPLUSFLAGS = ( + "$(inherited)", + "-DRCT_REMOVE_LEGACY_ARCH=1", + ); + PODFILE_DIR = "$(SRCROOT)"; + REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; + SDKROOT = iphoneos; + SWIFT_ENABLE_EXPLICIT_MODULES = NO; + USE_HERMES = true; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Skur" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 13B07F941A680F5B00A75B9A /* Debug */, + 13B07F951A680F5B00A75B9A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Skur" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 83CBBA201A601CBA00E9B192 /* Debug */, + 83CBBA211A601CBA00E9B192 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; +} diff --git a/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme b/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme new file mode 100644 index 0000000..465753e --- /dev/null +++ b/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata b/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..7fc9b19 --- /dev/null +++ b/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/mobile/ios/Skur/AppDelegate.swift b/mobile/ios/Skur/AppDelegate.swift new file mode 100644 index 0000000..9670a1f --- /dev/null +++ b/mobile/ios/Skur/AppDelegate.swift @@ -0,0 +1,69 @@ +internal import Expo +import React +import ReactAppDependencyProvider + +@main +class AppDelegate: ExpoAppDelegate { + var window: UIWindow? + + var reactNativeDelegate: ExpoReactNativeFactoryDelegate? + var reactNativeFactory: RCTReactNativeFactory? + + public override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + let delegate = ReactNativeDelegate() + let factory = ExpoReactNativeFactory(delegate: delegate) + delegate.dependencyProvider = RCTAppDependencyProvider() + + reactNativeDelegate = delegate + reactNativeFactory = factory + +#if os(iOS) || os(tvOS) + window = UIWindow(frame: UIScreen.main.bounds) + factory.startReactNative( + withModuleName: "main", + in: window, + launchOptions: launchOptions) +#endif + + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } + + // Linking API + public override func application( + _ app: UIApplication, + open url: URL, + options: [UIApplication.OpenURLOptionsKey: Any] = [:] + ) -> Bool { + return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options) + } + + // Universal Links + public override func application( + _ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void + ) -> Bool { + let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler) + return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result + } +} + +class ReactNativeDelegate: ExpoReactNativeFactoryDelegate { + // Extension point for config-plugins + + override func sourceURL(for bridge: RCTBridge) -> URL? { + // needed to return the correct URL for expo-dev-client. + bridge.bundleURL ?? bundleURL() + } + + override func bundleURL() -> URL? { +#if DEBUG + return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry") +#else + return Bundle.main.url(forResource: "main", withExtension: "jsbundle") +#endif + } +} diff --git a/mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png b/mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..ed858557aab88e3cba0ff06536ad2c3a218118b8 GIT binary patch literal 28686 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�k+si*!9!J=8KakBl8H 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 F{V& + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Skur + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 0.1.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLSchemes + + skur + io.skur.vault + + + + CFBundleVersion + 1 + LSMinimumSystemVersion + 12.0 + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + + + NSCameraUsageDescription + Skur uses the camera only to read a vault or recipient address from a QR code. + NSFaceIDUsageDescription + Skur uses Face ID to approve signatures from this device. + NSMicrophoneUsageDescription + Allow $(PRODUCT_NAME) to access your microphone + RCTMetroPort + $(RCT_METRO_PORT) + RCTNewArchEnabled + + UILaunchStoryboardName + SplashScreen + UIRequiredDeviceCapabilities + + arm64 + + UIRequiresFullScreen + + UIStatusBarStyle + UIStatusBarStyleDefault + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + + UIUserInterfaceStyle + Dark + UIViewControllerBasedStatusBarAppearance + + + diff --git a/mobile/ios/Skur/PrivacyInfo.xcprivacy b/mobile/ios/Skur/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..49b8ded --- /dev/null +++ b/mobile/ios/Skur/PrivacyInfo.xcprivacy @@ -0,0 +1,48 @@ + + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + 0A2A.1 + 3B52.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryDiskSpace + NSPrivacyAccessedAPITypeReasons + + E174.1 + 85F4.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/mobile/ios/Skur/Skur-Bridging-Header.h b/mobile/ios/Skur/Skur-Bridging-Header.h new file mode 100644 index 0000000..8361941 --- /dev/null +++ b/mobile/ios/Skur/Skur-Bridging-Header.h @@ -0,0 +1,3 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// diff --git a/mobile/ios/Skur/Skur.entitlements b/mobile/ios/Skur/Skur.entitlements new file mode 100644 index 0000000..018a6e2 --- /dev/null +++ b/mobile/ios/Skur/Skur.entitlements @@ -0,0 +1,8 @@ + + + + + aps-environment + development + + \ No newline at end of file diff --git a/mobile/ios/Skur/SplashScreen.storyboard b/mobile/ios/Skur/SplashScreen.storyboard new file mode 100644 index 0000000..58d2179 --- /dev/null +++ b/mobile/ios/Skur/SplashScreen.storyboard @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/ios/Skur/Supporting/Expo.plist b/mobile/ios/Skur/Supporting/Expo.plist new file mode 100644 index 0000000..2324695 --- /dev/null +++ b/mobile/ios/Skur/Supporting/Expo.plist @@ -0,0 +1,14 @@ + + + + + EXUpdatesCheckOnLaunch + ALWAYS + EXUpdatesEnableBsdiffPatchSupport + + EXUpdatesEnabled + + EXUpdatesLaunchWaitMs + 0 + + \ No newline at end of file diff --git a/mobile/metro.config.js b/mobile/metro.config.js deleted file mode 100644 index c4e7253..0000000 --- a/mobile/metro.config.js +++ /dev/null @@ -1,20 +0,0 @@ -// Shares the web app's pure library (types, risk engine, policy rules, contract reads, ABI, chain config) -// with the mobile app without publishing a package: ../web/src is watched and resolved as "@web/*". -// Bare imports made from those shared files (viem, ...) resolve from mobile/node_modules so the app holds -// one copy of each dependency; everything else resolves normally. -const { getDefaultConfig } = require("expo/metro-config"); -const path = require("path"); - -const root = __dirname; -const webSrc = path.resolve(root, "../web/src"); -const config = getDefaultConfig(root); -config.watchFolders = [webSrc]; -config.resolver.extraNodeModules = { "@web": webSrc }; -const defaultResolve = config.resolver.resolveRequest; -config.resolver.resolveRequest = (context, moduleName, platform) => { - const fromShared = context.originModulePath.startsWith(webSrc); - const bare = !moduleName.startsWith(".") && !moduleName.startsWith("/") && !moduleName.startsWith("@web"); - const ctx = fromShared && bare ? { ...context, originModulePath: path.join(root, "index.ts") } : context; - return (defaultResolve ?? ctx.resolveRequest)(ctx, moduleName, platform); -}; -module.exports = config; diff --git a/mobile/package-lock.json b/mobile/package-lock.json deleted file mode 100644 index d7ff9bd..0000000 --- a/mobile/package-lock.json +++ /dev/null @@ -1,6729 +0,0 @@ -{ - "name": "mobile", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "mobile", - "version": "1.0.0", - "dependencies": { - "@expo-google-fonts/dm-mono": "^0.4.2", - "@expo-google-fonts/dm-sans": "^0.4.2", - "@expo-google-fonts/space-grotesk": "^0.4.1", - "@expo/vector-icons": "^15.0.2", - "@react-native-async-storage/async-storage": "2.2.0", - "@react-navigation/bottom-tabs": "^7.19.1", - "@react-navigation/native": "^7.4.1", - "@react-navigation/native-stack": "^7.19.1", - "@tanstack/react-query": "^5.102.8", - "expo": "~57.0.23", - "expo-camera": "~57.0.5", - "expo-clipboard": "~57.0.2", - "expo-font": "~57.0.4", - "expo-linking": "~57.0.10", - "expo-local-authentication": "~57.0.3", - "expo-notifications": "~57.0.19", - "expo-secure-store": "~57.0.4", - "expo-status-bar": "~57.0.1", - "react": "19.2.3", - "react-native": "0.86.3", - "react-native-get-random-values": "~1.11.0", - "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "~4.26.0", - "viem": "^2.56.5" - }, - "devDependencies": { - "@types/react": "~19.2.2", - "typescript": "~6.0.3" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", - "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", - "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.8", - "@babel/types": "^7.29.8", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", - "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", - "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/traverse": "^7.29.7", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", - "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", - "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-plugin-utils": "^7.28.6", - "debug": "^4.4.3", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.11" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", - "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", - "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", - "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-wrap-function": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", - "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.29.7", - "@babel/helper-optimise-call-expression": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", - "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", - "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", - "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.8" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz", - "integrity": "sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-decorators": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.29.7.tgz", - "integrity": "sha512-p+G5BNXDcy3bOXplhY4HybQ1GxH3i2Tppmdm/3epyRu2VgJJZuUlZ61MqRTg582Q7ZLBdP7fePYvsumSEkMxcQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz", - "integrity": "sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.29.7.tgz", - "integrity": "sha512-foag0BB37ROhdeIX9O8G0jX7hw0UekJc04cHMrYLOnrErsnBKqJGHJ8eDRpoCFZBvEPPygmmtw4qyU97qa4oOw==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.29.7.tgz", - "integrity": "sha512-ajMX6QPcyomotqwpzhkYGxcK2i/us0rs1Qo9QvUpa+Fca0FTmqrzKrctoIYLMxcOhGZldGT/BAVkRGTWBiR8gQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", - "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", - "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", - "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", - "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-remap-async-to-generator": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", - "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", - "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", - "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", - "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-replace-supers": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", - "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", - "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.29.7.tgz", - "integrity": "sha512-wRHeUjUjCZnMHmiO5bRgjFLcoEh7JyTdByOW11ahhwNa4V0bmeGEaIvt51yq0zQp2yWIpqfxXXPyUP6GFJZHOQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-flow": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", - "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", - "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", - "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", - "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", - "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", - "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-transform-destructuring": "^7.29.7", - "@babel/plugin-transform-parameters": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", - "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", - "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", - "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", - "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", - "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", - "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", - "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", - "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", - "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.7.tgz", - "integrity": "sha512-xmAscdE/AsqRW7vutbPNoUmu/nF5SrLKPs7aoJgEjo35lLKA/Bc0i2rMv/hr1+Y0o1bQCiVtith3u2vdgRL39Q==", - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", - "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.29.7", - "@babel/helper-create-class-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", - "@babel/plugin-syntax-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", - "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.29.7", - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", - "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "@babel/plugin-syntax-jsx": "^7.29.7", - "@babel/plugin-transform-modules-commonjs": "^7.29.7", - "@babel/plugin-transform-typescript": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", - "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.8", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.8", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.8", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@expo-google-fonts/dm-mono": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/dm-mono/-/dm-mono-0.4.2.tgz", - "integrity": "sha512-loMaZOkQRs1r7yt4rN39zcr9e0J+smwnSx929yuODkuiPfsY4PaW18C9SEZ0BvXfcBKoRhatGoIBl8V2MOYVPQ==", - "license": "MIT AND OFL-1.1" - }, - "node_modules/@expo-google-fonts/dm-sans": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/dm-sans/-/dm-sans-0.4.2.tgz", - "integrity": "sha512-e/fLH5aCJzkEenz7axvEn8N7IJAKhUwNjIxS75h9j+Ip1M9S7d22M19gJN3A7QW4egVkBJRyQh1hQFhngQn9yA==", - "license": "MIT AND OFL-1.1" - }, - "node_modules/@expo-google-fonts/space-grotesk": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@expo-google-fonts/space-grotesk/-/space-grotesk-0.4.1.tgz", - "integrity": "sha512-ZVQYw4Ok/pgcSJiufP8oRZE3AVxS9xtmKEUfsurbHkHNdMc/GA1gDXP9G4Cr7KL4KqSc0haexR2TuMigotCn4Q==", - "license": "MIT AND OFL-1.1" - }, - "node_modules/@expo/code-signing-certificates": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz", - "integrity": "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==", - "license": "MIT", - "dependencies": { - "node-forge": "^1.3.3" - } - }, - "node_modules/@expo/config": { - "version": "57.0.9", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.9.tgz", - "integrity": "sha512-dmzlKraIFxa7wLwV6K7WzI8jp6QZpW6Mc5mGjLimJUFjzh4uQdYaT3m3plEutM5yxBoBEwqzks7l+I/ljCbxAQ==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "~57.0.9", - "@expo/config-types": "^57.0.2", - "@expo/json-file": "^11.0.1", - "@expo/require-utils": "^57.0.5", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4" - } - }, - "node_modules/@expo/config-plugins": { - "version": "57.0.9", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.9.tgz", - "integrity": "sha512-hHgfL1avkCdEvDSw7IwlKwRYYNgcxzbNNMIk6W6lTkJpY0MajinAfeJUS0J+wPCsjUfGbVqOJM+XhPaO5ulUxg==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "^57.0.2", - "@expo/json-file": "~11.0.1", - "@expo/plist": "^0.8.1", - "@expo/require-utils": "^57.0.5", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "semver": "^7.5.4", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/@expo/config-types": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", - "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", - "license": "MIT" - }, - "node_modules/@expo/devcert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", - "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==", - "license": "MIT", - "dependencies": { - "@expo/sudo-prompt": "^9.3.1", - "debug": "^3.1.0" - } - }, - "node_modules/@expo/devcert/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@expo/devtools": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-57.0.1.tgz", - "integrity": "sha512-GyUf+wFNkbttaX0jR7MZa9bm77U0IrLg6d2AjpxdyoXw/w4abHoXG0oFufwLMgP9zLTd5+Ct4X/ffNUTnlzZgg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/@expo/env": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.4.3.tgz", - "integrity": "sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==", - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "debug": "^4.3.4", - "getenv": "^2.0.0" - }, - "engines": { - "node": ">=20.12.0" - } - }, - "node_modules/@expo/expo-modules-macros-plugin": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@expo/expo-modules-macros-plugin/-/expo-modules-macros-plugin-0.6.1.tgz", - "integrity": "sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==", - "license": "MIT" - }, - "node_modules/@expo/fingerprint": { - "version": "0.20.13", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.13.tgz", - "integrity": "sha512-h1x+w+JpNRu88a/5SMZRzJs9YDGR/f7R8ApCr7OdenhqmJ00hFxQMzvxajDLL+1P2Y2g/ND0xksusqvBqWSW5Q==", - "license": "MIT", - "dependencies": { - "@expo/env": "^2.4.3", - "@expo/spawn-async": "^1.8.0", - "arg": "^5.0.2", - "chalk": "^4.1.2", - "debug": "^4.3.4", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "ignore": "^5.3.1", - "minimatch": "^10.2.2", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - }, - "bin": { - "fingerprint": "bin/cli.js" - } - }, - "node_modules/@expo/image-utils": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.11.5.tgz", - "integrity": "sha512-KPQBTpmpAfy/Vu9y4wPW808/qtZxjYmyJg8cm2QCPAupp+qEWA3b5zmk0ulOwQ9OgeHxuCPgUqWgkwHFo7UsrQ==", - "license": "MIT", - "dependencies": { - "@expo/require-utils": "^57.0.5", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.0.0", - "getenv": "^2.0.0", - "jimp-compact": "0.16.1", - "parse-png": "^2.1.0", - "semver": "^7.6.0" - } - }, - "node_modules/@expo/inline-modules": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@expo/inline-modules/-/inline-modules-0.1.7.tgz", - "integrity": "sha512-Bz/khd1gIJqDkje7t5ejD5e9jFbm4xEJzWSwRKadRo6gruepbw1xJ3Eb+e58OS8fY1ZNQYjzZbspnuph67sN0g==", - "license": "MIT", - "dependencies": { - "@expo/config-plugins": "~57.0.9" - } - }, - "node_modules/@expo/json-file": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", - "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/@expo/local-build-cache-provider": { - "version": "57.0.8", - "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-57.0.8.tgz", - "integrity": "sha512-SEdE0pAQrr90bRh3MNR0ZuwoIBw390cYdFgbn7Vk0Mtm9EHaBfP7kYj+2hXnXZJgOEm3/JMtfoD3rV7rWA9FGg==", - "license": "MIT", - "dependencies": { - "@expo/config": "~57.0.9", - "chalk": "^4.1.2" - } - }, - "node_modules/@expo/metro": { - "version": "56.0.2", - "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-56.0.2.tgz", - "integrity": "sha512-Ld5AeYMCCDa8bLeWhfuLbZFFjlV3f6ORqyPz2glGh6RltIngMuLf9BTC2yvHFjkKuGxL5SynijmA8xmNNWn5iA==", - "license": "MIT", - "dependencies": { - "metro": "0.84.5", - "metro-babel-transformer": "0.84.5", - "metro-cache": "0.84.5", - "metro-cache-key": "0.84.5", - "metro-config": "0.84.5", - "metro-core": "0.84.5", - "metro-file-map": "0.84.5", - "metro-minify-terser": "0.84.5", - "metro-resolver": "0.84.5", - "metro-runtime": "0.84.5", - "metro-source-map": "0.84.5", - "metro-symbolicate": "0.84.5", - "metro-transform-plugins": "0.84.5", - "metro-transform-worker": "0.84.5" - } - }, - "node_modules/@expo/metro-file-map": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-57.0.3.tgz", - "integrity": "sha512-1OXy+uPYY5uc7Tm4VBsd2NRn+3wHhqeqNuEO/Xo4kmYgv8FjYgUAc+bUXON9FpC2ikcLn4EVlGM9ce2exx9Mlg==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "fb-watchman": "^2.0.2", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "node_modules/@expo/osascript": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.7.1.tgz", - "integrity": "sha512-Zn03EX6In7ts2lPUW2ESUSkEhEWQN1qqsiXjadtZMJOuZRkMiAg1ZQHuvz9DjByDWNJ2pBwAGyrts9lj9k389g==", - "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@expo/package-manager": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.13.1.tgz", - "integrity": "sha512-y/K+CaYYpZpNGZhSX4HyLT/vyIunFjNfyoxNysPBCefeLKI/VCx6f9LNPzrxayr3rCYO5bl9O8H+HRQK265Nkg==", - "license": "MIT", - "dependencies": { - "@expo/json-file": "^11.0.1", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.0.0", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "resolve-workspace-root": "^2.0.0" - } - }, - "node_modules/@expo/plist": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", - "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/@expo/prebuild-config": { - "version": "57.0.16", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-57.0.16.tgz", - "integrity": "sha512-QA8oMZ7y70kjOzw+abhRl9uYC8Nu/abeUTHr0YVxb3pgIC14gc7w543bYtI+5gEDI3q55jKUViIauC76QvZN1w==", - "license": "MIT", - "dependencies": { - "@expo/config": "~57.0.9", - "@expo/config-plugins": "~57.0.9", - "@expo/config-types": "^57.0.2", - "@expo/image-utils": "^0.11.5", - "@expo/json-file": "^11.0.1", - "@react-native/normalize-colors": "0.86.3", - "debug": "^4.3.1", - "expo-modules-autolinking": "~57.0.13", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - } - }, - "node_modules/@expo/require-utils": { - "version": "57.0.5", - "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-57.0.5.tgz", - "integrity": "sha512-kTAXj9lDFEIPMsbAOGCGbjBbMF0oi7CqkYM79KOX0DDD9wSwXmlKL1z2h8OwsrBf7mbOo2DjlRvZu4BEjrIxGw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.25.2", - "@babel/plugin-transform-modules-commonjs": "^7.24.8" - }, - "peerDependencies": { - "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@expo/schema-utils": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-57.0.2.tgz", - "integrity": "sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw==", - "license": "MIT" - }, - "node_modules/@expo/sdk-runtime-versions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz", - "integrity": "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==", - "license": "MIT" - }, - "node_modules/@expo/spawn-async": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", - "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@expo/sudo-prompt": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/@expo/sudo-prompt/-/sudo-prompt-9.3.2.tgz", - "integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==", - "license": "MIT" - }, - "node_modules/@expo/vector-icons": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", - "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", - "license": "MIT", - "peerDependencies": { - "expo-font": ">=14.0.4", - "react": "*", - "react-native": "*" - } - }, - "node_modules/@expo/xcpretty": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.5.tgz", - "integrity": "sha512-J3eL4n4h5QTwfD0SIz8OIk6/+sOL/hFZAMacgCM07UNlxBQfJipEpIC2AQxvGkbYeStByJ0TVhQAJo+DeNgaSQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "chalk": "^4.1.0", - "js-yaml": "^4.1.0" - }, - "bin": { - "excpretty": "build/cli.js" - } - }, - "node_modules/@isaacs/ttlcache": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", - "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@react-native-async-storage/async-storage": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz", - "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==", - "license": "MIT", - "dependencies": { - "merge-options": "^3.0.4" - }, - "peerDependencies": { - "react-native": "^0.0.0-0 || >=0.65 <1.0" - } - }, - "node_modules/@react-native/assets-registry": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.86.3.tgz", - "integrity": "sha512-TDhgCZA4wjJg84d5A9swiOQYPIWSKEEVdg9IwMFZDupQzW/F3QoLUrfAJOcalgqTDA9/buTB8awhE3Whwg6u9Q==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.86.3.tgz", - "integrity": "sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.0", - "@react-native/codegen": "0.86.3" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/codegen": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", - "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.29.0", - "hermes-parser": "0.36.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "tinyglobby": "^0.2.15", - "yargs": "^17.6.2" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/@react-native/codegen/node_modules/hermes-estree": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", - "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", - "license": "MIT" - }, - "node_modules/@react-native/codegen/node_modules/hermes-parser": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", - "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.36.0" - } - }, - "node_modules/@react-native/community-cli-plugin": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.86.3.tgz", - "integrity": "sha512-qSDL9LQc5mZSZPNczT95WU9YQuPzxBklgON9vLhhqfI0yWIwKInqFx88dQ/uiEXBtf0yossthaQIqA4Ml6bF6g==", - "license": "MIT", - "dependencies": { - "@react-native/dev-middleware": "0.86.3", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "metro": "^0.84.3", - "metro-config": "^0.84.3", - "metro-core": "^0.84.3", - "semver": "^7.1.3" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@react-native-community/cli": "*", - "@react-native/metro-config": "0.86.3" - }, - "peerDependenciesMeta": { - "@react-native-community/cli": { - "optional": true - }, - "@react-native/metro-config": { - "optional": true - } - } - }, - "node_modules/@react-native/debugger-frontend": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.86.3.tgz", - "integrity": "sha512-TQmeofQ0PcuylhhlleOeuzHYZfbrgm3gayXzowqUEzgRisTm1D40/J3ggqs7XkQi5HP5ZA3n8dHmKL9vIzPcsw==", - "license": "BSD-3-Clause", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/debugger-shell": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.86.3.tgz", - "integrity": "sha512-O4ds+J7xZfxkbih9T+cAGegBdvKSPKYJm/lDgC9CpEjFMkmzWTpVLU3Qsv9sqZuo58z+sGhIcJfPsCFFWHpqbQ==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.6", - "debug": "^4.4.0", - "fb-dotslash": "0.5.8" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/dev-middleware": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.86.3.tgz", - "integrity": "sha512-LiEPTqTg/63bYUnrPyHLfjTDCNhA/+CUqI1+DsA9tYyewtSbULd5awsva6SgE10I+2iMhgKXS3ymkhU/kSCrGA==", - "license": "MIT", - "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.86.3", - "@react-native/debugger-shell": "0.86.3", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.3.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "serve-static": "^1.16.2", - "ws": "^7.5.10" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/gradle-plugin": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.86.3.tgz", - "integrity": "sha512-lxmx0GqLEWRIpZfpYFXlYVIs3ENQwaW6Vmp6oi29l2GoQJ1wZfFZRdMimDWlGEk8LKfHar3QH3iaPMkTcK9lEQ==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/js-polyfills": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.86.3.tgz", - "integrity": "sha512-eYIJ0es967+tePBFQDnl/gidVFxLns3fnbiK6rxscQrGodvuUO6hwxpQnfNynJ8MjbbndImXihXjcnJdc7SzJg==", - "license": "MIT", - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/normalize-colors": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.3.tgz", - "integrity": "sha512-Cv3CDkprb67GrzuaS9BGbBJC/6G4lIw3nyKOHRKTqTTum4bn37y5+R0Z04L8mcbQN85eEohNrRwb7IOM4j6uvg==", - "license": "MIT" - }, - "node_modules/@react-native/virtualized-lists": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.86.3.tgz", - "integrity": "sha512-1j44NEyNn05Ut40vHAmoSWbsIcybFkMAOBTwQt1PrESyfSS+qBoyU1LGIogNva0VIa0rQyEC5PzbA7R4/7Nhyw==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@types/react": "^19.2.0", - "react": "*", - "react-native": "0.86.3" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@react-navigation/bottom-tabs": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.19.1.tgz", - "integrity": "sha512-LE4CFDkwVQ1H+0CMTdanFJkXlgy4xaYoZMFrwS65iyMPDGfNBnGrqrNcn7nCiYWbodG2bYSbFmXlEyRE+Qh2xw==", - "license": "MIT", - "dependencies": { - "@react-navigation/elements": "^2.9.42", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0" - }, - "peerDependencies": { - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" - } - }, - "node_modules/@react-navigation/core": { - "version": "7.22.1", - "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.22.1.tgz", - "integrity": "sha512-6JAaYM4u6RPtVMUjN5ovX5DNBdBZtDqebk7kEwlncUP6fP4P94+qEYv1bRmtxSFs7UxiZwQQs+jzTsBaW2WeyA==", - "license": "MIT", - "dependencies": { - "@react-navigation/routers": "^7.6.4", - "escape-string-regexp": "^4.0.0", - "fast-deep-equal": "^3.1.3", - "nanoid": "^3.3.11", - "react-is": "^19.1.0", - "use-latest-callback": "^0.2.4", - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "react": ">= 18.2.0" - } - }, - "node_modules/@react-navigation/core/node_modules/react-is": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", - "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", - "license": "MIT" - }, - "node_modules/@react-navigation/elements": { - "version": "2.9.42", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.42.tgz", - "integrity": "sha512-3U1ZmXXoSrJEex+f8I4sRAzVL0OwLpgTEzORgjQGExWLjGrvn7QofK8cjNgBQHjRiTTQXAl8QMZvrdejg7yJAA==", - "license": "MIT", - "dependencies": { - "color": "^4.2.3", - "use-latest-callback": "^0.2.4", - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@react-native-masked-view/masked-view": ">= 0.2.0", - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0" - }, - "peerDependenciesMeta": { - "@react-native-masked-view/masked-view": { - "optional": true - } - } - }, - "node_modules/@react-navigation/native": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.4.1.tgz", - "integrity": "sha512-pEnu5XzAXV6RWr6A6pmZ7qLB+O6TJWMhBO25AjckMdr596UWulMPHQCtBcnOUfg6K+2h9ZUctHF2E5Xu4vcOrQ==", - "license": "MIT", - "dependencies": { - "@react-navigation/core": "^7.22.1", - "escape-string-regexp": "^4.0.0", - "fast-deep-equal": "^3.1.3", - "nanoid": "^3.3.11", - "standard-navigation": "^0.0.8", - "use-latest-callback": "^0.2.4" - }, - "peerDependencies": { - "react": ">= 18.2.0", - "react-native": "*" - } - }, - "node_modules/@react-navigation/native-stack": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.19.1.tgz", - "integrity": "sha512-YB3DLKXe1CLZAtJWgH/F3M5fWRALm1VbgVm91FppGYqPYfVZrD7mJaINaif2RIC4sZW7BziCE57IZ68vlINdkg==", - "license": "MIT", - "dependencies": { - "@react-navigation/elements": "^2.9.42", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0", - "warn-once": "^0.1.1" - }, - "peerDependencies": { - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" - } - }, - "node_modules/@react-navigation/routers": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.6.4.tgz", - "integrity": "sha512-GI7eJm8/KsZUQaYcXvEExikKurRZRgEsSzyZ7faENfi65yqJBCXjDMwyN1pF6pNW1MoLH1ErDwDivFxY6BzD3w==", - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11" - } - }, - "node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.12", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", - "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", - "license": "MIT" - }, - "node_modules/@tanstack/query-core": { - "version": "5.102.8", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.8.tgz", - "integrity": "sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.102.8", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.8.tgz", - "integrity": "sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.102.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@types/emscripten": { - "version": "1.41.6", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.6.tgz", - "integrity": "sha512-uN+9i8bFT5CUcZfyIEYDrSueACEyKGbUs5kC/72DGlZZoinh84sJfVV0i8UOJD1asdzkvLPBRrKs41kZ8MdEXg==", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/node": { - "version": "22.20.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.3.tgz", - "integrity": "sha512-DZmzkmwHzXrLPAXPyKNDzlIwMMUZCVacoD25ywdy5YTKGbOx/2ld+Q38Im2zJ0vBuZP5Prd3VZutKZyXwkOS8A==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", - "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.35", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", - "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", - "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", - "license": "ISC" - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.15", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", - "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/abitype": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", - "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3.22.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", - "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/agent-cli-detector": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.7.tgz", - "integrity": "sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==", - "license": "MIT", - "bin": { - "agent-cli-detector": "dist/cli.js" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/anser": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", - "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "license": "MIT" - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", - "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", - "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-react-compiler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz", - "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.0" - } - }, - "node_modules/babel-plugin-react-native-web": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.2.tgz", - "integrity": "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==", - "license": "MIT" - }, - "node_modules/babel-plugin-syntax-hermes-parser": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.0.tgz", - "integrity": "sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==", - "license": "MIT", - "dependencies": { - "hermes-parser": "0.36.0" - } - }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", - "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", - "license": "MIT" - }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", - "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.36.0" - } - }, - "node_modules/babel-plugin-transform-flow-enums": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-enums/-/babel-plugin-transform-flow-enums-0.0.2.tgz", - "integrity": "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==", - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-flow": "^7.12.1" - } - }, - "node_modules/badgin": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz", - "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/barcode-detector": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.2.2.tgz", - "integrity": "sha512-/4QOrrNrCRmDSBWiiP4aC72dnkuXUEdcFRidHgbPRXUpy82XcCMvJssI6fEs6JT42LS7DvBVZO70qasJbYKyrA==", - "license": "MIT", - "dependencies": { - "zxing-wasm": "3.1.3" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.24", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.24.tgz", - "integrity": "sha512-hYrgxie335U08WqICoGqKRzV1HFXv6zdxwJE4ekCb80CM9a0SVVsN4QPwT67RraRo+9h8IATk6uxHJw7QSkdOg==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/bplist-creator": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", - "integrity": "sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==", - "license": "MIT", - "dependencies": { - "stream-buffers": "2.2.x" - } - }, - "node_modules/bplist-parser": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.3.1.tgz", - "integrity": "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA==", - "license": "MIT", - "dependencies": { - "big-integer": "1.6.x" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.29.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", - "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.11.23", - "caniuse-lite": "^1.0.30001810", - "electron-to-chromium": "^1.5.427", - "node-releases": "^2.0.55", - "update-browserslist-db": "^1.3.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001810", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", - "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chrome-launcher": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", - "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/node": "*", - "escape-string-regexp": "^4.0.0", - "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0" - }, - "bin": { - "print-chrome-path": "bin/print-chrome-path.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/chromium-edge-launcher": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", - "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", - "license": "Apache-2.0", - "dependencies": { - "@types/node": "*", - "escape-string-regexp": "^4.0.0", - "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0", - "mkdirp": "^1.0.4" - } - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT" - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "license": "MIT", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz", - "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==", - "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "destroy": "1.2.0", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/connect": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", - "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/core-js-compat": { - "version": "3.50.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz", - "integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==", - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.7" - }, - "engines": { - "node": ">=6.4.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dnssd-advertise": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/dnssd-advertise/-/dnssd-advertise-1.1.6.tgz", - "integrity": "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==", - "license": "MIT" - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.429", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.429.tgz", - "integrity": "sha512-/1ENIE3cx4HTIx4IfPZFaOunJmsrSVTnj6coXoRVbiJUbkeTyFkJvBeWGkdgh08OhFbxYLMT1kbkwFVSarq6Ow==", - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/error-stack-parser": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", - "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "license": "MIT", - "dependencies": { - "stackframe": "^1.3.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" - }, - "node_modules/expo": { - "version": "57.0.23", - "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.23.tgz", - "integrity": "sha512-/aBLZFTD7+BNHWV/q5XbNRFqMhW/CrHsYeq8CcS/iGz6lJHYwEMm4XFcdoaeliuMdo6ZjNrsTHkBIdGB8VMHTg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.20.0", - "@expo/cli": "^57.0.25", - "@expo/config": "~57.0.9", - "@expo/config-plugins": "~57.0.9", - "@expo/devtools": "~57.0.1", - "@expo/dom-webview": "~57.0.1", - "@expo/fingerprint": "^0.20.13", - "@expo/local-build-cache-provider": "^57.0.8", - "@expo/log-box": "^57.0.4", - "@expo/metro": "~56.0.2", - "@expo/metro-config": "~57.0.12", - "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~57.0.12", - "expo-asset": "~57.0.17", - "expo-constants": "~57.0.18", - "expo-file-system": "~57.0.7", - "expo-font": "~57.0.4", - "expo-keep-awake": "~57.0.2", - "expo-modules-autolinking": "~57.0.13", - "expo-modules-core": "~57.0.18", - "pretty-format": "^29.7.0", - "react-refresh": "^0.14.2", - "whatwg-url-minimum": "^0.1.2" - }, - "bin": { - "expo": "bin/cli", - "expo-modules-autolinking": "bin/autolinking", - "fingerprint": "bin/fingerprint" - }, - "peerDependencies": { - "@expo/dom-webview": "*", - "@expo/metro-runtime": "*", - "react": "*", - "react-dom": "*", - "react-native": "*", - "react-native-web": "*", - "react-native-webview": "*" - }, - "peerDependenciesMeta": { - "@expo/dom-webview": { - "optional": true - }, - "@expo/metro-runtime": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native-web": { - "optional": true - }, - "react-native-webview": { - "optional": true - } - } - }, - "node_modules/expo-application": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-57.0.3.tgz", - "integrity": "sha512-t/CxeLio0NjY9/cOak1tQp62/hAUjzJxmhR4rVUR7K5bb9YoEtfl1ZekTn+Iuh+dYOMYzF0l72ODMSmY3CR1NA==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-camera": { - "version": "57.0.5", - "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-57.0.5.tgz", - "integrity": "sha512-0JaUXfDWMytmqm4pVKesZfLTSjAumfS2UGhnc1M4tqJ0qATCS0jxc7KjaoyKEzWJY+FEc8GlPCAGprS/7tNWZQ==", - "license": "MIT", - "dependencies": { - "barcode-detector": "^3.0.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } - } - }, - "node_modules/expo-clipboard": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.2.tgz", - "integrity": "sha512-VB4Au8X/RbvJKUtJk+87vdtveWSNEa5RzY3ooeO6VNF7Rd49RbQXZOu3/TfEW9p7mU8TCfyTvjyCiAUwSoSJ4w==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-constants": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.18.tgz", - "integrity": "sha512-cLDwDOniPfuCZPHNY++cAY2ZkK97u5aobbBvilPK2LLmaWxR4ZpD31LWUIzUDLrwMPxLjmh1uURnbeYEf0Mivw==", - "license": "MIT", - "dependencies": { - "@expo/env": "~2.4.3" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, - "node_modules/expo-font": { - "version": "57.0.4", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.4.tgz", - "integrity": "sha512-7WOMC2oA6xCfOm8bbofqWn2bIqyWFm7YLEnpc/gA1MJH0Ll0TfT/3+CqRkoW2eNRWMS8sxrz5WukUmSvmNquHA==", - "license": "MIT", - "dependencies": { - "fontfaceobserver": "^2.1.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-linking": { - "version": "57.0.10", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.10.tgz", - "integrity": "sha512-RzRi4l4pIYzjgoCJKnqkO+lUI+M2YX6qgcMIQkIbLAXdcWrykBoKYwHGlmAkdFHQm89GaYcq329yfxG+c1hv8w==", - "license": "MIT", - "dependencies": { - "expo-constants": "~57.0.18", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-local-authentication": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/expo-local-authentication/-/expo-local-authentication-57.0.3.tgz", - "integrity": "sha512-1oQCBKz8JOpai+Zp+Z2RkBFIi2CHHWLSJk/pjvT9VEyf8nPFslo4kt1ZlQvtJ4rupbKNCmxqKfYr8Mlo8nJEug==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-modules-autolinking": { - "version": "57.0.13", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.13.tgz", - "integrity": "sha512-Hj5NjZRlfccazhKab+wK19leRVUr1Y/PUERaRvegIbUSkq4GVxKq6lU9QHlKQyC16MdD/VS4iwsiLivB4o7lvQ==", - "license": "MIT", - "dependencies": { - "@expo/require-utils": "^57.0.5", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.1.0", - "commander": "^7.2.0" - }, - "bin": { - "expo-modules-autolinking": "bin/expo-modules-autolinking.js" - } - }, - "node_modules/expo-modules-core": { - "version": "57.0.18", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.18.tgz", - "integrity": "sha512-ovB7C+GVQTlKAOIsOIHJVVXN9Mn0ljf2SYBS+afrRaGqq+HZEn1D3o+HReIVeH1NjCn/xDBb7I4HjldHs6luZA==", - "license": "MIT", - "dependencies": { - "@expo/expo-modules-macros-plugin": "0.6.1", - "expo-modules-jsi": "~57.1.0", - "invariant": "^2.2.4" - }, - "peerDependencies": { - "react": "*", - "react-native": "*", - "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" - }, - "peerDependenciesMeta": { - "react-native-worklets": { - "optional": true - } - } - }, - "node_modules/expo-modules-jsi": { - "version": "57.1.0", - "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.1.0.tgz", - "integrity": "sha512-a5ckeHfnbYfonhcHGkM0EU/a0Keh+/OufXy/HyFS+spr5Ib0N4Oh1ZsSYFQhp5xdOUFkVofKRhfH+VmcccIIpA==", - "license": "MIT", - "peerDependencies": { - "react-native": "*" - } - }, - "node_modules/expo-notifications": { - "version": "57.0.19", - "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-57.0.19.tgz", - "integrity": "sha512-JW/usGEwOxWzN8s0L7+j3FAoB39GtaZtpUGye2lPvcqYSkvewpZYkrC16P1JaCP09YRx0Q+qXPx5NUoUU8NsBA==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.11.5", - "abort-controller": "^3.0.0", - "badgin": "^1.1.5", - "expo-application": "~57.0.3", - "expo-constants": "~57.0.18" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-secure-store": { - "version": "57.0.4", - "resolved": "https://registry.npmjs.org/expo-secure-store/-/expo-secure-store-57.0.4.tgz", - "integrity": "sha512-7zBA1RThURTXdP4w65kBzZNbcSsfArqVd+p+ETAnPRWXO8J296Qd0YaCVyRpJ0HSwlCnGdvOnqO+NgSreHsOhA==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-server": { - "version": "57.0.3", - "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-57.0.3.tgz", - "integrity": "sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==", - "license": "MIT", - "engines": { - "node": ">=20.16.0" - } - }, - "node_modules/expo-status-bar": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/expo-status-bar/-/expo-status-bar-57.0.1.tgz", - "integrity": "sha512-Xwaq1gAoVRWx5dPG5VhT5RSbnI9OilhZnO5qoPBnUaBAa5VzRzfdS8q0/bsPt0jR2DKLtGuP0bQ6efMJ4RIMDg==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/@expo/cli": { - "version": "57.0.25", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.25.tgz", - "integrity": "sha512-G2FJfwClIPNPhH2sJlIFAkhQLYaKNGzSarIQUl6sVA8oGdrmBnhRvbtTzxDzjS6WzO2aDX8DY7y1aNbCFILodg==", - "license": "MIT", - "dependencies": { - "@expo/code-signing-certificates": "^0.0.6", - "@expo/config": "~57.0.9", - "@expo/config-plugins": "~57.0.9", - "@expo/devcert": "^1.2.1", - "@expo/env": "~2.4.3", - "@expo/image-utils": "^0.11.5", - "@expo/inline-modules": "^0.1.7", - "@expo/json-file": "^11.0.1", - "@expo/log-box": "^57.0.4", - "@expo/metro": "~56.0.2", - "@expo/metro-config": "~57.0.12", - "@expo/metro-file-map": "^57.0.3", - "@expo/osascript": "^2.7.1", - "@expo/package-manager": "^1.13.1", - "@expo/plist": "^0.8.1", - "@expo/prebuild-config": "^57.0.16", - "@expo/require-utils": "^57.0.5", - "@expo/router-server": "^57.0.10", - "@expo/schema-utils": "^57.0.2", - "@expo/spawn-async": "^1.8.0", - "@expo/ws-tunnel": "^2.0.0", - "@expo/xcpretty": "^4.4.4", - "@react-native/dev-middleware": "0.86.3", - "accepts": "^1.3.8", - "agent-cli-detector": "0.1.7", - "arg": "^5.0.2", - "bplist-creator": "0.1.0", - "bplist-parser": "^0.3.1", - "chalk": "^4.0.0", - "ci-info": "^3.3.0", - "compression": "^1.7.4", - "connect": "^3.7.0", - "debug": "^4.3.4", - "dnssd-advertise": "^1.1.4", - "expo-server": "^57.0.3", - "fetch-nodeshim": "^0.4.10", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "lan-network": "^0.2.1", - "multitars": "^1.0.2", - "node-forge": "^1.3.3", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "picomatch": "^4.0.4", - "pretty-format": "^29.7.0", - "progress": "^2.0.3", - "prompts": "^2.3.2", - "resolve-from": "^5.0.0", - "sandbox-cli-detector": "^0.2.0", - "semver": "^7.6.0", - "send": "^0.19.0", - "slugify": "^1.3.4", - "stacktrace-parser": "^0.1.10", - "structured-headers": "^0.4.1", - "terminal-link": "^2.1.1", - "toqr": "^0.1.1", - "wrap-ansi": "^7.0.0", - "ws": "^8.12.1", - "zod": "^3.25.76" - }, - "bin": { - "expo-internal": "main.js" - }, - "peerDependencies": { - "expo": "*", - "expo-router": "*", - "react-native": "*" - }, - "peerDependenciesMeta": { - "expo-router": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { - "version": "57.0.10", - "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-57.0.10.tgz", - "integrity": "sha512-8rGh6N5di7jzu7UC1SuIA1TWmVd+vBwOHwC7/1ww+FA6CcxcWyQlcPl39h2+Jpnul78CVzWpIjOcdKsZsp2zXw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "@expo/metro-runtime": "^57.0.15", - "expo": "*", - "expo-constants": "^57.0.18", - "expo-font": "^57.0.4", - "expo-router": "*", - "expo-server": "^57.0.3", - "react": "*", - "react-dom": "*", - "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" - }, - "peerDependenciesMeta": { - "@expo/metro-runtime": { - "optional": true - }, - "expo-router": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-server-dom-webpack": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/dom-webview": { - "version": "57.0.1", - "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-57.0.1.tgz", - "integrity": "sha512-lAKsME4SAq+8sf56oN0DX5TBYyruupoRxbWbD2xf9RnKY8y6x8eb9LCE5pxSN0qyWdqnp+0wmyWzDkKboThKAw==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/@expo/log-box": { - "version": "57.0.4", - "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-57.0.4.tgz", - "integrity": "sha512-IxwS9s1L2muj8mj8AQSuiy7u8OFJdc02NRFo2me/Tj6DiaeG5SREqmpBE4rQpR2cadqSg5jl8Qab8Cjie616dg==", - "license": "MIT", - "dependencies": { - "@expo/dom-webview": "^57.0.1", - "anser": "^1.4.9", - "stacktrace-parser": "^0.1.10" - }, - "peerDependencies": { - "@expo/dom-webview": "^57.0.1", - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/@expo/metro-config": { - "version": "57.0.12", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-57.0.12.tgz", - "integrity": "sha512-S62Lrq35HZqBFD55423pmWb8PjaiR/W02zQC1uECBmw1vTN8WZaFz4TJ0i21EeJzwfebMb9MLxL8JZ102Z6VbA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.5", - "@expo/config": "~57.0.9", - "@expo/env": "~2.4.3", - "@expo/json-file": "~11.0.1", - "@expo/metro": "~56.0.2", - "@expo/require-utils": "^57.0.5", - "@expo/spawn-async": "^1.8.0", - "@jridgewell/gen-mapping": "^0.3.13", - "@jridgewell/remapping": "^2.3.5", - "@jridgewell/sourcemap-codec": "^1.5.5", - "browserslist": "^4.25.0", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "hermes-parser": "^0.36.0", - "jsc-safe-url": "^0.2.4", - "lightningcss": "^1.30.1", - "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "resolve-from": "^5.0.0" - }, - "peerDependencies": { - "expo": "*" - }, - "peerDependenciesMeta": { - "expo": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/@expo/ws-tunnel": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-2.0.0.tgz", - "integrity": "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw==", - "license": "MIT", - "peerDependencies": { - "ws": "^8.0.0" - } - }, - "node_modules/expo/node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/node_modules/babel-preset-expo": { - "version": "57.0.12", - "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.12.tgz", - "integrity": "sha512-rrZqJPYbVevy7rqibJZQFd3AsleGslJ63vmB3Qs8b5poOO5AHaehUGbZHjb0HoOZO59d86BEifYbq0/ncoM2UQ==", - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.20.5", - "@babel/helper-module-imports": "^7.25.9", - "@babel/plugin-proposal-decorators": "^7.12.9", - "@babel/plugin-proposal-export-default-from": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-default-from": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.28.6", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1", - "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.25.2", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/preset-typescript": "^7.23.0", - "@react-native/babel-plugin-codegen": "0.86.3", - "babel-plugin-react-compiler": "^1.0.0", - "babel-plugin-react-native-web": "~0.21.0", - "babel-plugin-syntax-hermes-parser": "^0.36.0", - "babel-plugin-transform-flow-enums": "^0.0.2", - "debug": "^4.3.4" - }, - "peerDependencies": { - "@babel/runtime": "^7.20.0", - "expo": "*", - "expo-widgets": "^57.0.19", - "react-refresh": ">=0.14.0 <1.0.0" - }, - "peerDependenciesMeta": { - "@babel/runtime": { - "optional": true - }, - "expo": { - "optional": true - }, - "expo-widgets": { - "optional": true - } - } - }, - "node_modules/expo/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo/node_modules/expo-asset": { - "version": "57.0.17", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.17.tgz", - "integrity": "sha512-qSdWZBSfEg06o3GJMwcj36tw0vXkB6eYjqkQistWmyJkHxhUOKnsKJnev6OraXxLdoI+KOd1+qgp/ENx8gcqYA==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.11.5", - "expo-constants": "~57.0.18" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/expo-file-system": { - "version": "57.0.7", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.7.tgz", - "integrity": "sha512-1vkZRadOsIputFDBcclqBa1pO3iXOO6iIsdqJipQWw4V5TSnWgmRTuOF7ro8IzrVue+PHbum++KCG3Tawem4cg==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react-native": "*" - } - }, - "node_modules/expo/node_modules/expo-keep-awake": { - "version": "57.0.2", - "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.2.tgz", - "integrity": "sha512-GqgH746wtJImmsbyHmCQoi7cOslKuWQBbJHXr53S35Bpf5UvxCAztvnitUEd7D0QvFN2rvkOhylbZpgZZfBLlQ==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*" - } - }, - "node_modules/expo/node_modules/hermes-estree": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", - "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", - "license": "MIT" - }, - "node_modules/expo/node_modules/hermes-parser": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", - "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.36.1" - } - }, - "node_modules/expo/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/expo/node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", - "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", - "license": "Apache-2.0" - }, - "node_modules/fast-base64-decode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz", - "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fb-dotslash": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", - "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "dotslash": "bin/dotslash" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fetch-nodeshim": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/fetch-nodeshim/-/fetch-nodeshim-0.4.10.tgz", - "integrity": "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==", - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/flow-enums-runtime": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", - "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", - "license": "MIT" - }, - "node_modules/fontfaceobserver": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/fontfaceobserver/-/fontfaceobserver-2.3.0.tgz", - "integrity": "sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==", - "license": "BSD-2-Clause" - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/getenv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", - "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-compiler": { - "version": "250829098.0.17", - "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.17.tgz", - "integrity": "sha512-qG1PXzTEtriF6oQLZF3vyHhSMxOdW5h2TqqLri0rdpstPustd2fSvRZQMVAPdlhgFwBfYnj3OUZtiO6LjYsEFw==", - "license": "MIT" - }, - "node_modules/hermes-estree": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", - "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", - "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", - "license": "MIT", - "dependencies": { - "hermes-estree": "0.35.0" - } - }, - "node_modules/hosted-git-info": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", - "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/isows": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", - "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jimp-compact": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz", - "integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==", - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", - "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsc-safe-url": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", - "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", - "license": "0BSD" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lan-network": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.1.tgz", - "integrity": "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==", - "license": "MIT", - "bin": { - "lan-network": "dist/lan-network-cli.js" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lighthouse-logger": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", - "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^2.6.9", - "marky": "^1.2.2" - } - }, - "node_modules/lighthouse-logger/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/lighthouse-logger/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "license": "MIT" - }, - "node_modules/lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "license": "MIT", - "dependencies": { - "chalk": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/log-symbols/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/marky": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", - "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "license": "Apache-2.0" - }, - "node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "license": "MIT" - }, - "node_modules/merge-options": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", - "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", - "license": "MIT", - "dependencies": { - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/metro": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.5.tgz", - "integrity": "sha512-r1liLkyFZMVSEMNjU1CJU5pRzs3NdkxHqXS60O25c0rCIqAR+cGk7rPydw/g0WAIKVXojIBIF45yYBPagJGcgw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "accepts": "^2.0.0", - "ci-info": "^2.0.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "error-stack-parser": "^2.0.6", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "hermes-parser": "0.35.0", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "jsc-safe-url": "^0.2.2", - "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.84.5", - "metro-cache": "0.84.5", - "metro-cache-key": "0.84.5", - "metro-config": "0.84.5", - "metro-core": "0.84.5", - "metro-file-map": "0.84.5", - "metro-resolver": "0.84.5", - "metro-runtime": "0.84.5", - "metro-source-map": "0.84.5", - "metro-symbolicate": "0.84.5", - "metro-transform-plugins": "0.84.5", - "metro-transform-worker": "0.84.5", - "mime-types": "^3.0.1", - "nullthrows": "^1.1.1", - "serialize-error": "^2.1.0", - "source-map": "^0.5.6", - "throat": "^5.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "metro": "src/cli.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-babel-transformer": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.5.tgz", - "integrity": "sha512-2WbHILKMiJUzfdjmGOQOqU1bWi9//gqiclc/tkk/AIsrrVw3efhZ1uhkOwMTxUEPOzqoo091H0olLmVZH5FHGQ==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.35.0", - "metro-cache-key": "0.84.5", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-cache": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.5.tgz", - "integrity": "sha512-WHS0n2OxQqtwEjSeQFPePNrMvEFhmQcUQM9cRJMHByWoi/GMWFBEWOf7hVkAM/0KRutAXNbDlSu/cZB6CyxgQQ==", - "license": "MIT", - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.84.5" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-cache-key": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.5.tgz", - "integrity": "sha512-3dPB2TnvGjjf0/9O7AXVQURKXuQNauTZE7WpTGTlR017Gh/B5y0m/2wcqxfveUguHSpu89KhVxCAlr2k/H7uhQ==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-config": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.5.tgz", - "integrity": "sha512-zie+uN6oohscowi2S7ByU+wUw6CrT4ZxW9uAbONOObSxx86RGmnIAmjXHLkfmcdYoY7jzOPEbqcI6oeVmqyBQA==", - "license": "MIT", - "dependencies": { - "connect": "^3.6.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.84.5", - "metro-cache": "0.84.5", - "metro-core": "0.84.5", - "metro-runtime": "0.84.5", - "yaml": "^2.6.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-core": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.5.tgz", - "integrity": "sha512-xwm605hCi5Y6eJTTb8ZWo6pkUcoBEIyiQOfkZh5GwtDwUrP9SNhTQZhzJHrBCwwxlf3Ptl/pxWJgQ1rsNYMnrA==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.84.5" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-file-map": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.5.tgz", - "integrity": "sha512-mlm/JL8toSbSc2akpKIGmzvrVRSCgZ5vkbycI34oMLoOnLGuLyC8WTyVJ6P0hZG/usDaGwZSl/s9BCRriqjGJA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "fb-watchman": "^2.0.0", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "nullthrows": "^1.1.1", - "walker": "^1.0.7" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-minify-terser": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.5.tgz", - "integrity": "sha512-BJoFwCEDsYnagPqarayInv2+diCDNDdLlaof/p6s9w4gh+gc9HXYM+pDvsKGKKUumpZswNF3Z/ftTMqKl/5IBg==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-resolver": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.5.tgz", - "integrity": "sha512-VSSnepg1k6LyCwtb6eirWdAWlpKwBG8Rdtsr1mU38rMelFyWgh3/QuMSiZIZAIjwg/fsa8GhW5/FO54CAUPCEA==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-runtime": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.5.tgz", - "integrity": "sha512-U1m2+d1Pr+JO2/iVXBB2OfXXityz7tqwIorxfrT15IEgaHvpJBq/OHiqnOWPKJbUl3JcxjcdviZZOKk85oK4Qg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.25.0", - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-source-map": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.5.tgz", - "integrity": "sha512-2BtV5L9uPc49F13Gn5wiP6bX/EncqzqTIk2VL/0F/96Vo0YEOjluT/qktQjFODfqGFsucwnh5mPEAl/2jVEfeg==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.84.5", - "nullthrows": "^1.1.1", - "ob1": "0.84.5", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-symbolicate": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.5.tgz", - "integrity": "sha512-rQ40zYDAkaWBN9yvjUuAD0ZpzBMZSoKyGYXnb5JrfbKjun7fTvfoLHL3KXFYenBTYZkQtlp4cKSCv/1utxFyOw==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.84.5", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-transform-plugins": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.5.tgz", - "integrity": "sha512-+InaSVGaOyt0DyRo4Y/zIdPI6CZwnbNho5LAL23tgmuGwv7fyfkF7kKfPjZcfxXBcoYdTLLFnCfCH/dHSiCqNg==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/metro-transform-worker": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.5.tgz", - "integrity": "sha512-ui1Z8x4s5RL36gMmKLaMMO7O9NNDHNdthEZSCDQHAau3JcAsTaFOK6I+2q4I/kW5u8hSEjJk9L45TXSVJw6g1A==", - "license": "MIT", - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "metro": "0.84.5", - "metro-babel-transformer": "0.84.5", - "metro-cache": "0.84.5", - "metro-cache-key": "0.84.5", - "metro-minify-terser": "0.84.5", - "metro-source-map": "0.84.5", - "metro-transform-plugins": "0.84.5", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/multitars": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/multitars/-/multitars-1.0.2.tgz", - "integrity": "sha512-6GwVw5eLi9sThdtlS4PKwC7yRLaf45pYhIEzKBHdKxi+YOXGKFX8acIniH+Uh/+k9mS2lQOupTccjoe5r0/1IQ==", - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.19", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", - "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/negotiator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", - "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", - "license": "MIT", - "dependencies": { - "content-type": "^2.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/node-forge": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", - "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.55", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz", - "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm-package-arg": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", - "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", - "license": "ISC", - "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/nullthrows": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", - "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "license": "MIT" - }, - "node_modules/ob1": { - "version": "0.84.5", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.5.tgz", - "integrity": "sha512-aH9RkoZc7w/90HBamFxTw8ZLFr05wXS+iOnvmrgo53Ep8Pyrm5FieQSaPIVROkfFVQISeD/zo92fes26TOwe+A==", - "license": "MIT", - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", - "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", - "license": "MIT", - "dependencies": { - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-spinners": "^2.0.0", - "log-symbols": "^2.2.0", - "strip-ansi": "^5.2.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", - "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/ora/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ora/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ox": { - "version": "0.14.44", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.44.tgz", - "integrity": "sha512-O54qXXHEk4ySamMSyBpI0AeBegS5frxU6+LA6Jb9Sf6kMOxcTNaxYmwZfpOu22DIQsdKfgQxHq8EsAGaoBQScA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.2.3", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/parse-png": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/parse-png/-/parse-png-2.1.0.tgz", - "integrity": "sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==", - "license": "MIT", - "dependencies": { - "pngjs": "^3.3.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/plist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz", - "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.9.10", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/plist/node_modules/@xmldom/xmldom": { - "version": "0.9.12", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz", - "integrity": "sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==", - "license": "MIT", - "engines": { - "node": ">=14.6" - } - }, - "node_modules/pngjs": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss": { - "version": "8.5.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", - "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.18", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/proc-log": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", - "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", - "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "license": "MIT", - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-devtools-core": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", - "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", - "license": "MIT", - "dependencies": { - "shell-quote": "^1.6.1", - "ws": "^7" - } - }, - "node_modules/react-freeze": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.4.tgz", - "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": ">=17.0.0" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, - "node_modules/react-native": { - "version": "0.86.3", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.86.3.tgz", - "integrity": "sha512-JR5s3bM9ezud+Mw24GlNXNfthqPIKwrQgPPJcam+L97t2sKjjEavhCzBn+fyqZZRcM5+XlhYxpTxVkK7e1n38Q==", - "license": "MIT", - "dependencies": { - "@react-native/assets-registry": "0.86.3", - "@react-native/codegen": "0.86.3", - "@react-native/community-cli-plugin": "0.86.3", - "@react-native/gradle-plugin": "0.86.3", - "@react-native/js-polyfills": "0.86.3", - "@react-native/normalize-colors": "0.86.3", - "@react-native/virtualized-lists": "0.86.3", - "abort-controller": "^3.0.0", - "anser": "^1.4.9", - "ansi-regex": "^5.0.0", - "babel-plugin-syntax-hermes-parser": "0.36.0", - "base64-js": "^1.5.1", - "commander": "^12.0.0", - "flow-enums-runtime": "^0.0.6", - "hermes-compiler": "250829098.0.17", - "invariant": "^2.2.4", - "memoize-one": "^5.0.0", - "metro-runtime": "^0.84.3", - "metro-source-map": "^0.84.3", - "nullthrows": "^1.1.1", - "pretty-format": "^29.7.0", - "promise": "^8.3.0", - "react-devtools-core": "^6.1.5", - "react-refresh": "^0.14.0", - "regenerator-runtime": "^0.13.2", - "scheduler": "0.27.0", - "semver": "^7.1.3", - "stacktrace-parser": "^0.1.10", - "tinyglobby": "^0.2.15", - "whatwg-fetch": "^3.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "react-native": "cli.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@react-native/jest-preset": "0.86.3", - "@types/react": "^19.1.1", - "react": "^19.2.3" - }, - "peerDependenciesMeta": { - "@react-native/jest-preset": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-native-get-random-values": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz", - "integrity": "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==", - "license": "MIT", - "dependencies": { - "fast-base64-decode": "^1.0.0" - }, - "peerDependencies": { - "react-native": ">=0.56" - } - }, - "node_modules/react-native-safe-area-context": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz", - "integrity": "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==", - "license": "MIT", - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native-screens": { - "version": "4.26.2", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.26.2.tgz", - "integrity": "sha512-2XnWsZToKj76trGtEZzx5ELD/qOICFEprEeUntImmitQFVUkea27fiWdUSITArI356Y1qynpXZINW+Unbhky/A==", - "license": "MIT", - "dependencies": { - "react-freeze": "^1.0.0", - "warn-once": "^0.1.0" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } - }, - "node_modules/react-native/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "license": "MIT" - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.2.tgz", - "integrity": "sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==", - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-workspace-root": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve-workspace-root/-/resolve-workspace-root-2.0.1.tgz", - "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", - "license": "MIT" - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", - "license": "MIT", - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/sandbox-cli-detector": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/sandbox-cli-detector/-/sandbox-cli-detector-0.2.0.tgz", - "integrity": "sha512-4lyHX0ZU0AZKwjgZ1InxZAa3PNpyEb8rOQ+Zss1ReYmhNzW0Q+h1zE5nvniXN0HaAWZaZE1zgVNEirb0R7LmNg==", - "license": "MIT", - "bin": { - "sandbox-cli-detector": "dist/cli.js" - }, - "engines": { - "node": ">=18.18" - } - }, - "node_modules/sax": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", - "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/send/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/serialize-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", - "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", - "license": "MIT", - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/sf-symbols-typescript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/sf-symbols-typescript/-/sf-symbols-typescript-2.2.0.tgz", - "integrity": "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", - "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-plist": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.3.1.tgz", - "integrity": "sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==", - "license": "MIT", - "dependencies": { - "bplist-creator": "0.1.0", - "bplist-parser": "0.3.1", - "plist": "^3.0.5" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" - }, - "node_modules/slugify": { - "version": "1.6.9", - "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.9.tgz", - "integrity": "sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackframe": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "license": "MIT" - }, - "node_modules/stacktrace-parser": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", - "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", - "license": "MIT", - "dependencies": { - "type-fest": "^0.7.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/standard-navigation": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.8.tgz", - "integrity": "sha512-TyVbo7INUDWtsUWDFn8RR7kwR87U0S4xHfLfbbnyeC581TmmyqQ+eM+nPw8rQTSD8QitRVcYfPaSHr/QJiUy1g==", - "license": "MIT", - "peerDependencies": { - "react": "*" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stream-buffers": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz", - "integrity": "sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==", - "license": "Unlicense", - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/structured-headers": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", - "integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==", - "license": "MIT" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tagged-tag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", - "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.51.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", - "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, - "node_modules/throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/toqr": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/toqr/-/toqr-0.1.1.tgz", - "integrity": "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==", - "license": "MIT" - }, - "node_modules/type-fest": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=8" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", - "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/use-latest-callback": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.6.tgz", - "integrity": "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==", - "license": "MIT", - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.7.0.tgz", - "integrity": "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", - "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", - "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/viem": { - "version": "2.56.5", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.56.5.tgz", - "integrity": "sha512-GuEf/oee0PHgy4D6JIA8u0rY1g+sM5nF+p7HyMHO3vjlHC5G/ljfrgnUOnrES9m5Ny/P3RwWCHjDuN2T6HUWzQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.9.1", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0", - "abitype": "1.2.3", - "isows": "1.0.7", - "ox": "0.14.44", - "ws": "8.21.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/viem/node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/vlq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", - "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", - "license": "MIT" - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/warn-once": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", - "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", - "license": "MIT" - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", - "license": "MIT" - }, - "node_modules/whatwg-url-minimum": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.1.2.tgz", - "integrity": "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/ws": { - "version": "7.5.13", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", - "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xcode": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz", - "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==", - "license": "Apache-2.0", - "dependencies": { - "simple-plist": "^1.1.0", - "uuid": "^7.0.3" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/xml2js": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.0.tgz", - "integrity": "sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xml2js/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz", - "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zxing-wasm": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-3.1.3.tgz", - "integrity": "sha512-3lC9BJk4fR5ZJxcGjb0hVnDFOW7KpLXHIebiBmVd4FDRQZVeObztoTKxRUPxlWwSgxrMRONK0u50hBD1aTYEKg==", - "license": "MIT", - "dependencies": { - "@types/emscripten": "^1.41.5", - "type-fest": "^5.8.0" - }, - "peerDependencies": { - "@types/emscripten": ">=1.39.6" - } - }, - "node_modules/zxing-wasm/node_modules/type-fest": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.9.0.tgz", - "integrity": "sha512-yANm3Jr3GiJ1qgJlxGAVxTOIcEOk1rhQHamlXtnrCK7EHP4HeM9OGxtMg/W7HFdrVzw/ZWJKGVIJusVH85sLtw==", - "license": "(MIT OR CC0-1.0)", - "dependencies": { - "tagged-tag": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/mobile/package.json b/mobile/package.json deleted file mode 100644 index 6df8b1d..0000000 --- a/mobile/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "mobile", - "version": "1.0.0", - "main": "index.ts", - "dependencies": { - "@expo-google-fonts/dm-mono": "^0.4.2", - "@expo-google-fonts/dm-sans": "^0.4.2", - "@expo-google-fonts/space-grotesk": "^0.4.1", - "@expo/vector-icons": "^15.0.2", - "@react-native-async-storage/async-storage": "2.2.0", - "@react-navigation/bottom-tabs": "^7.19.1", - "@react-navigation/native": "^7.4.1", - "@react-navigation/native-stack": "^7.19.1", - "@tanstack/react-query": "^5.102.8", - "expo": "~57.0.23", - "expo-camera": "~57.0.5", - "expo-clipboard": "~57.0.2", - "expo-font": "~57.0.4", - "expo-linking": "~57.0.10", - "expo-local-authentication": "~57.0.3", - "expo-notifications": "~57.0.19", - "expo-secure-store": "~57.0.4", - "expo-status-bar": "~57.0.1", - "react": "19.2.3", - "react-native": "0.86.3", - "react-native-get-random-values": "~1.11.0", - "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "~4.26.0", - "viem": "^2.56.5" - }, - "devDependencies": { - "@types/react": "~19.2.2", - "typescript": "~6.0.3" - }, - "scripts": { - "start": "expo start", - "android": "expo run:android", - "ios": "expo run:ios", - "web": "expo start --web" - }, - "private": true -} diff --git a/mobile/src/components/Identicon.tsx b/mobile/src/components/Identicon.tsx deleted file mode 100644 index 962dfce..0000000 --- a/mobile/src/components/Identicon.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { useMemo } from "react"; -import { useTheme } from "../state/theme"; -import { Text, View } from "react-native"; -import { keccak256, stringToHex } from "viem"; -import { F } from "../theme"; - -/** Same deterministic blocky avatar as the web interface (web/src/components/Identicon.tsx), drawn with views. */ -export function Identicon({ address, size = 40, badge }: { address: string; size?: number; badge?: string }) { - const C = useTheme(); - const { cells, fg, bg } = useMemo(() => { - const hash = keccak256(stringToHex(address.toLowerCase())).slice(2); - const hue = parseInt(hash.slice(0, 4), 16) % 360; - const hue2 = (hue + 140) % 360; - const bits = hash.slice(4); - const cells: boolean[] = []; - for (let y = 0; y < 5; y++) { - const row: boolean[] = []; - for (let x = 0; x < 3; x++) row.push(parseInt(bits[(y * 3 + x) % bits.length], 16) % 3 !== 0); - cells.push(row[0], row[1], row[2], row[1], row[0]); - } - return { cells, fg: `hsl(${hue}, 70%, 45%)`, bg: `hsl(${hue2}, 60%, 88%)` }; - }, [address]); - const unit = size / 5; - return ( - - - {cells.map((on, i) => )} - - {badge ? ( - - {badge} - - ) : null} - - ); -} diff --git a/mobile/src/components/TokenMark.tsx b/mobile/src/components/TokenMark.tsx deleted file mode 100644 index 0234d83..0000000 --- a/mobile/src/components/TokenMark.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Text, View } from "react-native"; -import { tokenMark } from "@web/lib/tokens"; -import { F } from "../theme"; - -/** The asset's mark: one colour and glyph per symbol, the same in both interfaces. */ -export function TokenMark({ symbol, size = 40 }: { symbol: string; size?: number }) { - const m = tokenMark(symbol); - return ( - - {m.glyph} - - ); -} diff --git a/mobile/src/components/VaultSheet.tsx b/mobile/src/components/VaultSheet.tsx deleted file mode 100644 index 959dc0f..0000000 --- a/mobile/src/components/VaultSheet.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useEffect, useState } from "react"; -import { useTheme } from "../state/theme"; -import { Text, View } from "react-native"; -import { isAddress } from "viem"; -import { SkurFactoryAbi } from "@web/abi/SkurFactory"; -import { DEPLOYMENTS } from "@web/config/chain"; -import { short } from "@web/lib/format"; -import { publicClient } from "../lib/client"; -import { useStore } from "../state/store"; -import { Identicon } from "./Identicon"; -import { Button, CircleIcon, Icon, Input, Logo, Row, Sheet, useStyles } from "./ui"; -import { F } from "../theme"; - -/** Safe's "My accounts" switcher: the open vault, vaults the device signer belongs to, and a way to add one by address. */ -export function VaultSheet({ open, onClose }: { open: boolean; onClose: () => void }) { - const C = useTheme(); const s = useStyles(); - const { vaultAddress, setVaultAddress, labels, signer } = useStore(); - const [mine, setMine] = useState<`0x${string}`[]>([]); - const [adding, setAdding] = useState(false); - const [addr, setAddr] = useState(""); - useEffect(() => { - if (!open || !signer) return; - publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }).then((v) => setMine([...v])).catch(() => setMine([])); - }, [open, signer]); - const list = Array.from(new Set([...(vaultAddress ? [vaultAddress] : []), ...mine, DEPLOYMENTS.demoVault].map((a) => a.toLowerCase()))) as `0x${string}`[]; - const pick = (a: `0x${string}`) => { void setVaultAddress(a); onClose(); }; - return ( - }> - - {list.map((a, i) => { - const current = vaultAddress?.toLowerCase() === a; - return ( - } title={labels[a] ?? (a === DEPLOYMENTS.demoVault.toLowerCase() ? "Demo vault" : "Treasury vault")} subtitle={short(a, 6)} onPress={() => pick(a)} last={i === list.length - 1} - trailing={current ? : mine.some((m) => m.toLowerCase() === a) ? member : null} /> - ); - })} - - {adding ? ( - - setAddr(t.trim())} placeholder="0x… vault address" mono autoFocus /> - - - ) : ( - } title="Add existing vault" subtitle="Open any vault by its address" onPress={() => setAdding(true)} last /> - )} - {!signer && Add a signer key under Settings and the vaults it belongs to appear here.} - - ); -} diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx deleted file mode 100644 index 16d98b4..0000000 --- a/mobile/src/components/ui.tsx +++ /dev/null @@ -1,297 +0,0 @@ -import { Feather } from "@expo/vector-icons"; -import * as Clipboard from "expo-clipboard"; -import { forwardRef, useState, type ComponentProps, type ReactNode } from "react"; -import { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { short } from "@web/lib/format"; -import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; -import type { TxState } from "../hooks/useTx"; -import { useTheme } from "../state/theme"; -import { F, R, type Palette } from "../theme"; - -export type IconName = ComponentProps["name"]; -export function Icon({ name, size = 18, color }: { name: IconName; size?: number; color?: string }) { - const C = useTheme(); - return ; -} - -export function Screen({ children, top, footer, refreshControl, padded = true }: { children: ReactNode; top?: ReactNode; footer?: ReactNode; refreshControl?: ReactNode; padded?: boolean }) { - const C = useTheme(); const s = useStyles(); const insets = useSafeAreaInsets(); - return ( - - {top ? {top} : null} - {children} - {footer ? {footer} : null} - - ); -} - -export function TopBar({ left, center, right, title }: { left?: ReactNode; center?: ReactNode; right?: ReactNode; title?: string }) { - const s = useStyles(); - return ( - - {left}{title ? {title} : null} - {center ? {center} : null} - {right} - - ); -} - -export function IconButton({ name, onPress, dot, tone = "dark", label }: { name: IconName; onPress?: () => void; dot?: boolean; tone?: "dark" | "accent"; label?: string }) { - const C = useTheme(); const s = useStyles(); - return ( - [s.iconBtn, tone === "accent" && { backgroundColor: C.accent }, pressed && { opacity: 0.6 }]}> - - {dot ? : null} - - ); -} - -export function BackButton({ onPress }: { onPress: () => void }) { return ; } - -/** The web logo: a yellow tile with an S, then the wordmark. */ -export function Logo({ size = 28, wordmark = true }: { size?: number; wordmark?: boolean }) { - const C = useTheme(); - return ( - - - S - - {wordmark ? Skur : null} - - ); -} - -/** A card that opens on tap: the header carries the value, so a long screen reads as a short list. */ -export function Expandable({ title, summary, icon, tone = "dark", children, open, onToggle }: { title: string; summary?: string; icon?: IconName; tone?: Tone; children: ReactNode; open: boolean; onToggle: () => void }) { - const C = useTheme(); const s = useStyles(); - return ( - - [{ flexDirection: "row", alignItems: "center", gap: 12, padding: 16 }, pressed && { opacity: 0.6 }]}> - {icon ? : null} - - {title} - {summary ? {summary} : null} - - - - {open ? {children} : null} - - ); -} - -export function Card({ children, style, flush = false }: { children: ReactNode; style?: StyleProp; flush?: boolean }) { - const s = useStyles(); - return {children}; -} -export function SectionLabel({ children }: { children: ReactNode }) { const s = useStyles(); return {children}; } - -/** The list row every screen is built from: leading mark, title, value, chevron. */ -export function Row({ leading, title, subtitle, trailing, onPress, chevron = false, last = false }: { leading?: ReactNode; title: ReactNode; subtitle?: ReactNode; trailing?: ReactNode; onPress?: () => void; chevron?: boolean; last?: boolean }) { - const C = useTheme(); const s = useStyles(); - const body = ( - - {leading ? {leading} : null} - - {typeof title === "string" ? {title} : title} - {subtitle ? (typeof subtitle === "string" ? {subtitle} : subtitle) : null} - - {trailing} - {chevron ? : null} - - ); - return onPress ? pressed && { opacity: 0.6 }}>{body} : body; -} - -type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent" | "dark" | "success" | "error"; -function tones(C: Palette): Record { - return { - ok: { bg: C.successBg, fg: C.success }, success: { bg: C.successBg, fg: C.success }, - warn: { bg: C.warningBg, fg: C.warning }, bad: { bg: C.errorBg, fg: C.error }, error: { bg: C.errorBg, fg: C.error }, - info: { bg: C.infoBg, fg: C.info }, neutral: { bg: C.card2, fg: C.text2 }, dark: { bg: C.card2, fg: C.text }, - accent: { bg: C.accent, fg: C.onAccent }, - }; -} - -export function CircleIcon({ name, size = 40, tone = "dark", text }: { name?: IconName; size?: number; tone?: Tone; text?: string }) { - const C = useTheme(); const t = tones(C)[tone]; - return ( - - {text ? {text} : name ? : null} - - ); -} - -export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNode; mono?: boolean; last?: boolean }) { - const s = useStyles(); - return ( - - {k} - {typeof v === "string" || typeof v === "number" ? {v} : v} - - ); -} - -export function Badge({ tone = "neutral", children, icon }: { tone?: Tone; children: ReactNode; icon?: IconName }) { - const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; - return {icon ? : null}{children}; -} -export const TierBadge = ({ tier }: { tier: Tier }) => {TIER_LABEL[tier]}; -export const ModeBadge = ({ mode }: { mode: Mode }) => {MODE_LABEL[mode]}; -export const StatusBadge = ({ status }: { status: Status }) => {STATUS_LABEL[status]}; -export const TrustBadge = ({ trust }: { trust: Trust }) => {TRUST_LABEL[trust]}; - -export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md" }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm" }) { - const C = useTheme(); const s = useStyles(); - const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.card2 : "transparent"; - const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; - return ( - [s.btn, size === "sm" && { height: 36, paddingHorizontal: 14 }, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, style]}> - {loading ? : <>{icon ? : null}{children}} - - ); -} - -/** The sticky primary action: what you are about to sign, and with which key. */ -export function SignBar({ label, signerAddress, onPress, disabled, loading, hint }: { label: string; signerAddress?: string | null; onPress?: () => void; disabled?: boolean; loading?: boolean; hint?: string }) { - const C = useTheme(); const s = useStyles(); - return ( - - {hint ? {hint} : null} - [s.signbar, { opacity: disabled ? 0.45 : pressed ? 0.85 : 1 }]}> - {loading ? : } - {label} - {signerAddress ? {short(signerAddress)} : null} - - - - ); -} - -export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { - const s = useStyles(); - return ( - - {label} - {children} - {hint ? {hint} : null} - - ); -} - -export const Input = forwardRef(function Input(props, ref) { - const C = useTheme(); const s = useStyles(); - return ; -}); - -export function Tabs({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { - const C = useTheme(); const s = useStyles(); - return ( - - {options.map(([v, label]) => ( - onChange(v)} style={[s.tab, value === v && { borderBottomColor: C.accent }]}>{label} - ))} - - ); -} - -export function Address({ value, full = false, style }: { value: string; full?: boolean; style?: object }) { - const C = useTheme(); const s = useStyles(); - const [copied, setCopied] = useState(false); - return ( - { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8} style={{ flexDirection: "row", alignItems: "center", gap: 6 }}> - {full ? value : short(value)} - - - ); -} - -export function Notice({ tone = "info", children }: { tone?: Tone; children: ReactNode }) { - const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; - return {children}; -} - -export function TxStatus({ state }: { state: TxState }) { - if (state.phase === "idle") return null; - if (state.phase === "error") return {state.message}; - if (state.phase === "done") return Confirmed · {short(state.hash, 6)}; - const msg = state.phase === "auth" ? "Waiting for Face ID…" : state.phase === "simulating" ? "Checking against the policy…" : "Waiting for the block…"; - return {msg}; -} - -export function Empty({ icon = "inbox", children }: { icon?: IconName; children: ReactNode }) { - const C = useTheme(); - return {children}; -} - -/** Caution tape: the brand's mark, used only where the vault is not in Normal mode. */ -export function Tape({ height = 8 }: { height?: number }) { - const C = useTheme(); - return ( - - {Array.from({ length: 34 }).map((_, i) => )} - - ); -} - -export function Sheet({ open, onClose, title, children, action }: { open: boolean; onClose: () => void; title: string; children: ReactNode; action?: ReactNode }) { - const s = useStyles(); const insets = useSafeAreaInsets(); - return ( - - - - - - {title} - {action ? {action} : null} - - {children} - - - ); -} - -const makeStyles = (C: Palette) => StyleSheet.create({ - screen: { flex: 1, backgroundColor: C.canvas }, - topbar: { height: 52, paddingHorizontal: 16, flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, - topTitle: { fontFamily: F.display, fontSize: 22, color: C.text, letterSpacing: -0.3 }, - iconBtn: { width: 40, height: 40, borderRadius: 20, backgroundColor: C.card, alignItems: "center", justifyContent: "center" }, - dot: { position: "absolute", top: 8, right: 8, width: 8, height: 8, borderRadius: 4, backgroundColor: C.accent, borderWidth: 1.5, borderColor: C.canvas }, - footer: { position: "absolute", left: 0, right: 0, bottom: 0, padding: 16, backgroundColor: C.canvas, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: C.border }, - card: { backgroundColor: C.card, borderRadius: R.lg, padding: 16, marginBottom: 12 }, - sectionLabel: { fontFamily: F.mono, fontSize: 11, letterSpacing: 1.2, textTransform: "uppercase", color: C.text3, marginBottom: 8, marginTop: 8 }, - row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 13, paddingHorizontal: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, - rowTitle: { fontFamily: F.bodyBold, fontSize: 15, color: C.text }, - rowSub: { fontFamily: F.body, fontSize: 13, color: C.text2 }, - kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 11, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, - kvK: { fontFamily: F.body, fontSize: 14, color: C.text2 }, - kvV: { fontFamily: F.bodyMedium, fontSize: 14, color: C.text, textAlign: "right", flexShrink: 1 }, - badge: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 9, paddingVertical: 4, borderRadius: R.pill, alignSelf: "flex-start" }, - badgeText: { fontFamily: F.bodyBold, fontSize: 12 }, - btn: { height: 48, borderRadius: R.md, alignItems: "center", justifyContent: "center", paddingHorizontal: 18, flexDirection: "row", gap: 8 }, - btnText: { fontFamily: F.bodyBold, fontSize: 15 }, - signbar: { height: 56, borderRadius: R.lg, backgroundColor: C.accent, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 18 }, - signbarText: { fontFamily: F.bodyBold, fontSize: 16, color: C.onAccent, flex: 1 }, - signerChip: { backgroundColor: "rgba(16,20,24,0.12)", borderRadius: R.pill, paddingHorizontal: 10, height: 28, justifyContent: "center" }, - signerChipText: { fontFamily: F.monoMedium, fontSize: 12, color: C.onAccent }, - label: { fontFamily: F.bodyMedium, fontSize: 13, color: C.text2, marginBottom: 6 }, - hint: { fontFamily: F.body, fontSize: 12, color: C.text3, marginTop: 6, lineHeight: 16 }, - input: { backgroundColor: C.card2, borderRadius: R.md, paddingHorizontal: 14, height: 48, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, - tabs: { flexDirection: "row", borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border, marginBottom: 4 }, - tab: { paddingVertical: 10, paddingHorizontal: 4, marginRight: 22, borderBottomWidth: 2, borderBottomColor: "transparent" }, - tabText: { fontFamily: F.bodyBold, fontSize: 15, color: C.text3 }, - addr: { fontFamily: F.mono, fontSize: 13, color: C.text2 }, - notice: { padding: 12, borderRadius: R.md, marginTop: 10 }, - sheetBackdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)" }, - sheet: { backgroundColor: C.card, borderTopLeftRadius: 22, borderTopRightRadius: 22, paddingHorizontal: 16, paddingTop: 8 }, - grabber: { width: 40, height: 4, borderRadius: 2, backgroundColor: C.border, alignSelf: "center", marginBottom: 14 }, - sheetTitle: { fontFamily: F.display, fontSize: 18, color: C.text }, -}); - -const cache = new Map>(); -/** Styles for the ground currently in use, built once per palette. */ -export function useStyles() { - const C = useTheme(); - if (!cache.has(C.canvas)) cache.set(C.canvas, makeStyles(C)); - return cache.get(C.canvas)!; -} diff --git a/mobile/src/hooks/useAlerts.ts b/mobile/src/hooks/useAlerts.ts deleted file mode 100644 index a8e2a39..0000000 --- a/mobile/src/hooks/useAlerts.ts +++ /dev/null @@ -1,49 +0,0 @@ -import AsyncStorage from "@react-native-async-storage/async-storage"; -import * as Notifications from "expo-notifications"; -import { useEffect, useRef } from "react"; -import { Kind, ROLE_APPROVER, ROLE_GUARDIAN, ROLE_OWNER, Status } from "@web/lib/types"; -import type { ProposalView, VaultData } from "@web/lib/vaultReads"; -import { describeProposal } from "../lib/describe"; -import { useStore } from "../state/store"; -import { useMyRoles } from "./useVault"; - -Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowBanner: true, shouldShowList: true, shouldPlaySound: false, shouldSetBadge: true }) }); - -/** Proposals the active signer can still act on: not yet confirmed by them and within their role. */ -export function needsMe(vault: VaultData, roles: number, me: string | null): ProposalView[] { - if (!me || !roles) return []; - return vault.proposals.filter((p) => { - if (p.status !== Status.PENDING) return false; - const mine = p.approvers.some((a) => a.toLowerCase() === me) || p.guardianConfirmers.some((a) => a.toLowerCase() === me); - if (mine) return false; - if (roles & ROLE_GUARDIAN) return p.requiredGuardians > 0 || p.vetoable; - return Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER : ROLE_OWNER)); - }); -} - -/** - * Local notifications, as Safe's "Get personalized updates": while the app polls the vault, a proposal that newly - * needs this signer raises a notification. There is no push backend; the phone learns of it on its next read. - */ -export function useAlerts(vault: VaultData | undefined) { - const { signer, notifications } = useStore(); - const roles = useMyRoles(vault); - const seen = useRef | null>(null); - useEffect(() => { - if (!vault || !notifications) return; - const key = `skur.seen.${vault.address.toLowerCase()}`; - (async () => { - if (!seen.current) { try { seen.current = new Set(JSON.parse((await AsyncStorage.getItem(key)) ?? "[]")); } catch { seen.current = new Set(); } } - const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null).filter((p) => !seen.current!.has(String(p.id))); - if (due.length === 0) return; - const perm = await Notifications.getPermissionsAsync(); - const granted = perm.granted || (await Notifications.requestPermissionsAsync()).granted; - for (const p of due) { - seen.current!.add(String(p.id)); - if (granted) { const d = describeProposal(p, vault); await Notifications.scheduleNotificationAsync({ content: { title: "A transaction requires your confirmation", body: `${d.title} · ${d.detail}`, data: { url: `skur://tx/${String(p.id)}` } }, trigger: null }).catch(() => undefined); } - } - await AsyncStorage.setItem(key, JSON.stringify([...seen.current!])); - await Notifications.setBadgeCountAsync(due.length).catch(() => undefined); - })(); - }, [vault, vault?.address, vault?.proposalCount, roles, signer?.address, notifications]); -} diff --git a/mobile/src/hooks/useTx.ts b/mobile/src/hooks/useTx.ts deleted file mode 100644 index 3031b17..0000000 --- a/mobile/src/hooks/useTx.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as LocalAuthentication from "expo-local-authentication"; -import { useCallback, useState } from "react"; -import { createWalletClient, http, type Abi } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { arkDevnet, ARK_DEVNET_RPC } from "@web/config/chain"; -import { describeError } from "@web/lib/errors"; -import { publicClient } from "../lib/client"; -import { useStore } from "../state/store"; - -export type TxState = - | { phase: "idle" } - | { phase: "auth" } - | { phase: "simulating" } - | { phase: "mining"; hash: `0x${string}` } - | { phase: "done"; hash: `0x${string}` } - | { phase: "error"; message: string }; - -/** - * Sign with the device key. Order: biometric gate, simulation (so a policy refusal reads as plain language before - * anything is signed), sign and broadcast, wait for the receipt. - */ -export function useTx(onDone?: () => void) { - const { signer, biometrics } = useStore(); - const [state, setState] = useState({ phase: "idle" }); - - const send = useCallback( - async (args: { address: `0x${string}`; abi: Abi; functionName: string; args?: readonly unknown[]; value?: bigint }) => { - if (!signer) { - setState({ phase: "error", message: "Add a signer key under Settings to sign from this device." }); - return; - } - try { - if (biometrics) { - setState({ phase: "auth" }); - const hw = await LocalAuthentication.hasHardwareAsync(); - const enrolled = hw && (await LocalAuthentication.isEnrolledAsync()); - if (enrolled) { - const r = await LocalAuthentication.authenticateAsync({ promptMessage: "Approve with Skur", cancelLabel: "Cancel" }); - if (!r.success) { - setState({ phase: "error", message: "Authentication cancelled. Nothing was signed." }); - return; - } - } - } - setState({ phase: "simulating" }); - const account = privateKeyToAccount(signer.key); - const wallet = createWalletClient({ account, chain: arkDevnet, transport: http(ARK_DEVNET_RPC) }); - const { request } = await publicClient.simulateContract({ ...args, account, chain: arkDevnet } as Parameters[0]); - const hash = await wallet.writeContract(request); - setState({ phase: "mining", hash }); - await publicClient.waitForTransactionReceipt({ hash }); - setState({ phase: "done", hash }); - onDone?.(); - } catch (e) { - setState({ phase: "error", message: describeError(e) }); - } - }, - [signer, biometrics, onDone], - ); - - const reset = useCallback(() => setState({ phase: "idle" }), []); - return { state, send, reset, busy: state.phase === "auth" || state.phase === "simulating" || state.phase === "mining" }; -} diff --git a/mobile/src/hooks/useVault.ts b/mobile/src/hooks/useVault.ts deleted file mode 100644 index 87965ab..0000000 --- a/mobile/src/hooks/useVault.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { publicClient } from "../lib/client"; -import { fetchActivity, fetchCore, type VaultActivity, type VaultData } from "@web/lib/vaultReads"; -import { useStore } from "../state/store"; -import { ROLE_GUARDIAN } from "@web/lib/types"; - -const EMPTY: VaultActivity = { proposals: [], recipients: [], logsFailed: false, policyHistory: [], modeHistory: [] }; -const key = (a: `0x${string}` | null) => ["vault", a] as const; - -/** - * Core paints first, activity fills in. Background refetches are deliberately invisible: only a pull - * to refresh shows the spinner, and the returned object keeps its identity while the data is unchanged, - * so a screen does not re-render (or flash its loader) every time the interval fires. - */ -export function useVault(address: `0x${string}` | null) { - const core = useQuery({ queryKey: [...key(address), "core"], queryFn: () => fetchCore(publicClient, address!), enabled: Boolean(address), refetchInterval: 20_000, staleTime: 10_000 }); - const activity = useQuery({ - queryKey: [...key(address), "activity", core.data?.proposalCount ?? -1], - queryFn: () => fetchActivity(publicClient, address!, core.data?.proposalCount ?? 0, core.data?.blockNumber ?? 0n), - enabled: Boolean(address && core.data), - refetchInterval: 30_000, - staleTime: 15_000, - placeholderData: (prev) => prev, - }); - - // The queue survives a proposal count change: the new query starts empty, and swapping the list for a - // loader for a few seconds is what reads as "reloading". - const lastActivity = useRef(null); - if (activity.data) lastActivity.current = activity.data; - const shownActivity = activity.data ?? lastActivity.current; - - const data: VaultData | undefined = useMemo( - () => (core.data ? { ...core.data, ...(shownActivity ?? EMPTY), activityLoading: !shownActivity, fetchedAt: Date.now() } : undefined), - // Identity changes only when the data itself does; React Query keeps the same reference otherwise. - [core.data, shownActivity], - ); - - const [manual, setManual] = useState(false); - useEffect(() => { if (manual && !core.isFetching && !activity.isFetching) setManual(false); }, [manual, core.isFetching, activity.isFetching]); - const refetch = useCallback(() => { setManual(true); void core.refetch(); void activity.refetch(); }, [core, activity]); - - return { data, error: core.error ?? activity.error, isLoading: core.isLoading && !core.data, refetch, refreshing: manual }; -} - -export function useInvalidateVault(address: `0x${string}` | null) { - const qc = useQueryClient(); - return useCallback(() => { - const k = key(address); - void qc.invalidateQueries({ queryKey: k }); - // The devnet's replicas can lag a mined receipt by seconds; these catch up without a visible spinner. - for (const ms of [6_000, 15_000, 30_000]) setTimeout(() => void qc.invalidateQueries({ queryKey: k }), ms); - }, [qc, address]); -} - -/** Roles the device signer holds in the open vault. */ -export function useMyRoles(vault: VaultData | undefined): number { - const { signer } = useStore(); - if (!vault || !signer) return 0; - return vault.members.find((m) => m.address.toLowerCase() === signer.address.toLowerCase())?.roles ?? 0; -} - -export const isGuardianRole = (roles: number) => Boolean(roles & ROLE_GUARDIAN); diff --git a/mobile/src/lib/client.ts b/mobile/src/lib/client.ts deleted file mode 100644 index d89592b..0000000 --- a/mobile/src/lib/client.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createPublicClient, http } from "viem"; -import { arkDevnet, ARK_DEVNET_RPC } from "@web/config/chain"; - -/** One public client for the app. No JSON-RPC batching: the devnet serves batches serially (docs/DECISIONS.md D18). */ -export const publicClient = createPublicClient({ chain: arkDevnet, transport: http(ARK_DEVNET_RPC, { retryCount: 2 }) }); diff --git a/mobile/src/lib/describe.ts b/mobile/src/lib/describe.ts deleted file mode 100644 index 408ff53..0000000 --- a/mobile/src/lib/describe.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { fmtAmount, short } from "@web/lib/format"; -import { Kind, MODE_LABEL, roleNames, Status, TRUST_LABEL, type Mode, type Trust } from "@web/lib/types"; -import type { ProposalView, VaultData } from "@web/lib/vaultReads"; - -/** Title and one-line detail for a proposal row, in the same words the web interface uses. */ -export function describeProposal(p: ProposalView, vault: VaultData): { title: string; detail: string; icon: string } { - const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); - switch (p.kind) { - case Kind.TRANSFER: - return { title: "Send", detail: `${asset ? fmtAmount(p.amount, asset.decimals, asset.symbol) : String(p.amount)} to ${short(p.target)}`, icon: "↗" }; - case Kind.POLICY_UPDATE: - return { title: "Policy update", detail: p.securityReducing ? "loosens at least one control" : "tightens or keeps every control", icon: "≡" }; - case Kind.ASSET_LIMITS: - return { title: "Asset limits", detail: `${asset?.symbol ?? short(p.target)}${p.securityReducing ? " · loosens a cap" : ""}`, icon: "≡" }; - case Kind.MEMBER_SET: { - const roles = Number(p.amount); - return { title: roles === 0 ? "Remove member" : "Set roles", detail: `${short(p.target)}${roles ? ` → ${roleNames(roles).join(" + ")}` : ""}`, icon: "◎" }; - } - case Kind.RECIPIENT_TRUST: - return { title: "Recipient trust", detail: `${short(p.target)} → ${TRUST_LABEL[Number(p.amount) as Trust]}`, icon: "◎" }; - case Kind.MODE_RELAX: - return { title: "Lower security mode", detail: `to ${MODE_LABEL[Number(p.amount) as Mode]} · guardians must confirm`, icon: "⛨" }; - case Kind.RECOVERY: - return { title: "Signer recovery", detail: `${short(p.target)} replaced`, icon: "⛨" }; - default: - return { title: "Proposal", detail: "", icon: "•" }; - } -} - -export function statusText(p: ProposalView): string { - if (p.status === Status.PENDING) return `${p.liveApprovals} of ${p.requiredApprovals}${p.requiredGuardians ? ` + ${p.liveGuardians} of ${p.requiredGuardians} guardian` : ""}`; - return ["", "Pending", "Executed", "Cancelled", "Vetoed"][p.status] ?? ""; -} - -export function memoText(p: ProposalView): string { - return p.memo; -} diff --git a/mobile/src/lib/scanBus.ts b/mobile/src/lib/scanBus.ts deleted file mode 100644 index 34b645a..0000000 --- a/mobile/src/lib/scanBus.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** Hands a scanned address from the Scan screen back to whichever screen asked for it. */ -type Listener = (value: string) => void; -let listener: Listener | null = null; -export const scanBus = { - request(fn: Listener) { listener = fn; }, - deliver(value: string) { const fn = listener; listener = null; fn?.(value); }, - clear() { listener = null; }, -}; diff --git a/mobile/src/screens/AddressBook.tsx b/mobile/src/screens/AddressBook.tsx deleted file mode 100644 index 8c4d39a..0000000 --- a/mobile/src/screens/AddressBook.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { Pressable, RefreshControl, Text, View } from "react-native"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { fmtAmount, fmtDate, fmtDuration, fmtRelative, nowSec, short } from "@web/lib/format"; -import { ROLE_APPROVER, ROLE_OWNER, Trust, TRUST_LABEL } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { scanBus } from "../lib/scanBus"; -import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, Empty, Field, IconButton, Input, Notice, Row, Screen, Sheet, TopBar, TrustBadge, TxStatus, useStyles } from "../components/ui"; -import { F } from "../theme"; - -/** Recipients are security objects: register early, verify, restrict or block. */ -export function AddressBook({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); - const roles = useMyRoles(vault); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(invalidate); - const [dialog, setDialog] = useState<"register" | "trust" | null>(null); - const [target, setTarget] = useState(""); - const [trust, setTrust] = useState(Trust.VERIFIED); - const now = nowSec(); - const stable = vault.assets[0]; - const canRegister = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)); - const isOwner = Boolean(roles & ROLE_OWNER); - const scan = () => { scanBus.request((a) => setTarget(a)); nav.navigate("Scan"); }; - return ( - } - top={ nav.goBack()} />} center={Address book} right={ { setTarget(""); setDialog("register"); }} />} />}> - - {vault.activityLoading ? Reading recipients from the chain… : vault.recipients.length === 0 ? No recipients yet. Register one to start its activation clock. : ( - - {vault.recipients.map((r, i) => { - const active = Number(r.activatesAt) <= now; - return ( - } title={short(r.address, 6)} subtitle={`${r.paymentCount.toString()} payment${r.paymentCount === 1n ? "" : "s"}${stable ? ` · ${fmtAmount(r.totalPaid, stable.decimals, stable.symbol)} paid` : ""} · ${active ? "active" : `activates ${fmtRelative(r.activatesAt)}`}`} - trailing={} chevron={isOwner} onPress={isOwner ? () => { setTarget(r.address); setTrust(r.trust === Trust.VERIFIED ? Trust.TRUSTED : Trust.VERIFIED); setDialog("trust"); } : undefined} last={i === vault.recipients.length - 1} /> - ); - })} - - )} - - - - setDialog(null)} title="New entry"> - - setTarget(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> - - {!canRegister && Only an owner or approver signer can register a recipient.} - - - - setDialog(null)} title="Propose a trust change"> - setTarget(t.trim())} placeholder="0x…" mono /> - - - {[Trust.VERIFIED, Trust.TRUSTED, Trust.RESTRICTED, Trust.BLOCKED].map((t) => ( - setTrust(t)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: trust === t ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{TRUST_LABEL[t]} - ))} - - - - Recorded {fmtDate(BigInt(now))} by {short(vault.address)} - - - ); -} diff --git a/mobile/src/screens/CreateVault.tsx b/mobile/src/screens/CreateVault.tsx deleted file mode 100644 index 4e9951f..0000000 --- a/mobile/src/screens/CreateVault.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useMemo, useRef, useState } from "react"; -import { Pressable, Text, View, type TextInput } from "react-native"; -import { isAddress, keccak256, stringToHex } from "viem"; -import { SkurFactoryAbi } from "@web/abi/SkurFactory"; -import { DEPLOYMENTS, NATIVE_ASSET } from "@web/config/chain"; -import { fmtAmount, fmtDuration, short } from "@web/lib/format"; -import { policyToContract, validateCounts, validatePolicy } from "@web/lib/policy"; -import { TEMPLATES, templateById, type TemplateId } from "@web/lib/templates"; -import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER } from "@web/lib/types"; -import { publicClient } from "../lib/client"; -import { scanBus } from "../lib/scanBus"; -import { useTx } from "../hooks/useTx"; -import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { BackButton, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Screen, SectionLabel, SignBar, TopBar, TxStatus, useStyles } from "../components/ui"; -import { F } from "../theme"; - -type Row = { address: string; roles: number }; -const ROLE_CHIPS: Array<[number, string]> = [[ROLE_OWNER, "Owner"], [ROLE_APPROVER, "Approver"], [ROLE_EXECUTOR, "Executor"], [ROLE_GUARDIAN, "Guardian"]]; - -/** Create a vault from the phone: name, template, members, review, one signature. */ -export function CreateVault() { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); - const { signer, setVaultAddress, setLabel } = useStore(); - const [name, setName] = useState(""); - const [templateId, setTemplateId] = useState("startup"); - const template = templateById(templateId); - const [members, setMembers] = useState([{ address: signer?.address ?? "", roles: ROLE_OWNER | ROLE_APPROVER | ROLE_EXECUTOR }, { address: "", roles: ROLE_OWNER | ROLE_APPROVER }, { address: "", roles: ROLE_GUARDIAN }]); - // A three-row address form does not fit above the keyboard, so Return moves to the next member. - const rowRefs = useRef>([]); - const salt = useMemo(() => keccak256(stringToHex(`vault-${Date.now()}`)), []); - const counts = members.reduce((a, m) => ({ owners: a.owners + (m.roles & 1 ? 1 : 0), approvers: a.approvers + (m.roles & 2 ? 1 : 0), executors: a.executors + (m.roles & 4 ? 1 : 0), guardians: a.guardians + (m.roles & 8 ? 1 : 0) }), { owners: 0, approvers: 0, executors: 0, guardians: 0 }); - const errors = useMemo(() => { - const e = [...validatePolicy(template.policy), ...validateCounts(template.policy, counts.owners, counts.approvers, counts.executors, counts.guardians)]; - const addrs = members.map((m) => m.address.toLowerCase()); - if (members.some((m) => !isAddress(m.address))) e.push("Every member needs a valid address."); - if (new Set(addrs).size !== addrs.length) e.push("Duplicate member address."); - if (members.some((m) => m.roles === 0)) e.push("Every member needs at least one role."); - return e; - }, [template, counts, members]); - const tx = useTx(async () => { - if (!signer) return; - const v = await publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "predictVaultAddress", args: [signer.address, salt] }); - await setLabel(v, name || "Treasury vault"); - await setVaultAddress(v); - }); - const setRow = (i: number, patch: Partial) => setMembers((ms) => ms.map((m, j) => (j === i ? { ...m, ...patch } : m))); - const toggle = (i: number, b: number) => setRow(i, { roles: b === ROLE_GUARDIAN ? (members[i].roles & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((members[i].roles & b ? members[i].roles & ~b : members[i].roles | b) & ~ROLE_GUARDIAN) }); - const create = () => void tx.send({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "createVault", args: [salt, members.map((m) => m.address as `0x${string}`), members.map((m) => m.roles), policyToContract(template.policy), [DEPLOYMENTS.testUsd, NATIVE_ASSET], [template.stable, template.native]] }); - return ( - nav.goBack()} />} center={Create vault} />} - footer={ 0 || tx.busy} loading={tx.busy} hint={!signer ? "Add a signer key first; it pays for the creation" : errors[0]} />}> - - 1 · Name and template - - - - {TEMPLATES.map((t) => setTemplateId(t.id)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: templateId === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name})} - - {template.tagline} Needs {template.minSigners}+ signers and {template.minGuardians}+ guardian{template.minGuardians === 1 ? "" : "s"}. - - 2 · Signers and guardians - {members.map((m, i) => ( - - - {isAddress(m.address) ? : } - { rowRefs.current[i] = r; }} value={m.address} onChangeText={(t) => setRow(i, { address: t.trim() })} placeholder="0x…" mono style={{ flex: 1 }} returnKeyType={i < members.length - 1 ? "next" : "done"} submitBehavior={i < members.length - 1 ? "submit" : "blurAndSubmit"} onSubmitEditing={() => rowRefs.current[i + 1]?.focus()} /> - { scanBus.request((a) => setRow(i, { address: a })); nav.navigate("Scan"); }} /> - setMembers((ms) => ms.filter((_, j) => j !== i))} /> - - - {ROLE_CHIPS.map(([b, label]) => toggle(i, b)} style={{ paddingHorizontal: 12, height: 30, borderRadius: 15, backgroundColor: m.roles & b ? (b === ROLE_GUARDIAN ? C.accent : C.accentBg) : C.card2, borderWidth: 1, borderColor: m.roles & b ? C.accent : "transparent", alignItems: "center", justifyContent: "center" }}>{label})} - - - ))} - - 3 · Review - - - - - - - - - - {errors.length > 0 && {errors.join(" ")}} - - - ); -} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx deleted file mode 100644 index 7700f3a..0000000 --- a/mobile/src/screens/Home.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useState } from "react"; -import { Pressable, RefreshControl, Text, View } from "react-native"; -import { NATIVE_ASSET } from "@web/config/chain"; -import { fmtAmount } from "@web/lib/format"; -import { tokenMark } from "@web/lib/tokens"; -import { Mode, ROLE_APPROVER, ROLE_OWNER, Status } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { needsMe } from "../hooks/useAlerts"; -import { useMyRoles } from "../hooks/useVault"; -import { scanBus } from "../lib/scanBus"; -import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { TokenMark } from "../components/TokenMark"; -import { VaultSheet } from "../components/VaultSheet"; -import { Address, CircleIcon, Icon, IconButton, Row, Screen, Tape, TopBar, useStyles } from "../components/ui"; -import { F, type Palette } from "../theme"; -import { useTheme } from "../state/theme"; - -/** Home is the vault at a glance: what it holds, what is waiting, and the two things you do most. */ -export function Home({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { - const C = useTheme(); const s = useStyles(); const h = styles(C); - const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); - const { labels, signer, setVaultAddress } = useStore(); - const roles = useMyRoles(vault); - const [sheet, setSheet] = useState(false); - const label = labels[vault.address.toLowerCase()] ?? "Treasury vault"; - const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; - const pending = vault.proposals.filter((p) => p.status === Status.PENDING).length; - const canPropose = Boolean(roles & (ROLE_OWNER | ROLE_APPROVER)) && vault.mode !== Mode.LOCKDOWN; - const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null).length; - const [whole, frac] = stable ? fmtAmount(stable.balance, stable.decimals, undefined, 2).split(".") : ["—", undefined]; - const scanVault = () => { scanBus.request((a) => void setVaultAddress(a as `0x${string}`)); nav.navigate("Scan"); }; - - return ( - } - top={ - <> - setSheet(true)} style={{ flexDirection: "row", alignItems: "center", gap: 10 }}> - - {label} - - - } - right={<> 0} onPress={() => nav.navigate("Notifications")} />} - /> - {vault.mode !== Mode.NORMAL && } - - }> - - {pending > 0 && ( - nav.navigate("Main", { screen: "Transactions" })} style={h.banner}> - {pending} - Pending transactions - - - )} - {vault.mode !== Mode.NORMAL && ( - nav.navigate("Security")} style={[h.banner, { backgroundColor: vault.mode === Mode.LOCKDOWN ? C.errorBg : C.warningBg }]}> - - {vault.mode === Mode.LOCKDOWN ? "Lockdown: outgoing payments are frozen" : "Elevated: every payment scored one tier higher"} - - - )} - - - A - Ark devnet -

      - - - {whole} - {frac ? .{frac} : null} - {stable?.symbol} - - - - nav.navigate("Send")} /> - nav.navigate("Receive")} /> - - - - Tokens - {vault.assets.map((a, i) => ( - } - title={tokenMark(a.symbol).name} subtitle={`${fmtAmount(vault.velocity[a.address]?.daySpent ?? 0n, a.decimals)} of ${a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "∞"} today`} - trailing={{fmtAmount(a.balance, a.decimals)}} - onPress={canPropose ? () => nav.navigate("Send", { asset: a.address }) : undefined} last={i === vault.assets.length - 1} /> - ))} - setSheet(false)} /> - - ); -} - -function Action({ icon, label, onPress, tone = "dark", disabled }: { icon: "arrow-up-right" | "arrow-down-left"; label: string; onPress: () => void; tone?: "dark" | "accent"; disabled?: boolean }) { - const C = useTheme(); const h = styles(C); - return ( - [h.action, tone === "accent" && { backgroundColor: C.accent }, { opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }]}> - - {label} - - ); -} - -const styles = (C: Palette) => ({ - banner: { flexDirection: "row" as const, alignItems: "center" as const, gap: 10, backgroundColor: C.accentBg, borderRadius: 14, paddingHorizontal: 14, height: 48, marginBottom: 14 }, - count: { minWidth: 22, height: 22, borderRadius: 11, backgroundColor: C.accent, alignItems: "center" as const, justifyContent: "center" as const, paddingHorizontal: 6 }, - balance: { fontFamily: F.display, fontSize: 44, color: C.text, letterSpacing: -1.4 }, - action: { flex: 1, height: 48, borderRadius: 14, backgroundColor: C.card, flexDirection: "row" as const, alignItems: "center" as const, justifyContent: "center" as const, gap: 8 }, -}); diff --git a/mobile/src/screens/Members.tsx b/mobile/src/screens/Members.tsx deleted file mode 100644 index 9b15d30..0000000 --- a/mobile/src/screens/Members.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { Pressable, RefreshControl, Text, View } from "react-native"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { fmtDuration, short } from "@web/lib/format"; -import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, roleNames } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { useStore } from "../state/store"; -import { scanBus } from "../lib/scanBus"; -import { Address, BackButton, Badge, Button, Card, Field, IconButton, Input, Notice, Row, Screen, SectionLabel, Sheet, TopBar, TxStatus, useStyles } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { F } from "../theme"; - -const ROLE_BITS: Array<[number, string, string]> = [[ROLE_OWNER, "Owner", "governs"], [ROLE_APPROVER, "Approver", "confirms payments"], [ROLE_EXECUTOR, "Executor", "executes"], [ROLE_GUARDIAN, "Guardian", "freeze · veto · recover"]]; - -export function Members({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string) => void }>(); - const { signer } = useStore(); - const roles = useMyRoles(vault); - const isOwner = Boolean(roles & ROLE_OWNER); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(invalidate); - const [open, setOpen] = useState(false); - const [target, setTarget] = useState(""); - const [bits, setBits] = useState(ROLE_APPROVER); - const existing = vault.members.find((m) => m.address.toLowerCase() === target.toLowerCase()); - const adds = existing ? bits & ~existing.roles : bits; - const reducing = adds !== 0 || Boolean(existing && existing.roles & ROLE_GUARDIAN && !(bits & ROLE_GUARDIAN)); - const toggle = (b: number) => setBits((x) => (b === ROLE_GUARDIAN ? (x & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((x & b ? x & ~b : x | b) & ~ROLE_GUARDIAN))); - const edit = (address: string, r: number) => { setTarget(address); setBits(r); setOpen(true); }; - const signers = vault.members.filter((m) => !(m.roles & ROLE_GUARDIAN)); - const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); - const List = ({ items }: { items: typeof vault.members }) => ( - - {items.map((m, i) => ( - } title={m.address.toLowerCase() === signer?.address.toLowerCase() ? "This phone" : short(m.address, 6)} subtitle={
      } chevron={isOwner} onPress={isOwner ? () => edit(m.address, m.roles) : undefined} last={i === items.length - 1} - trailing={{roleNames(m.roles).map((r) => {r})}} /> - ))} - - ); - return ( - } - top={ nav.goBack()} />} center={Members} right={isOwner ? { setTarget(""); setBits(ROLE_APPROVER); setOpen(true); }} /> : undefined} />}> - - Treasury signers · {signers.length} - - Guardians · {guardians.length} - {guardians.length ? : No guardian configured. Nobody independent can veto a proposal or freeze the vault.} - Thresholds - - Routine {vault.policy.approvalsLow} · High {vault.policy.approvalsHigh} · Critical {vault.policy.approvalsCritical}{vault.policy.guardianRequiredCritical ? ` + ${vault.policy.guardianThreshold} guardian` : ""} · Governance {vault.policy.governanceThreshold} owner{vault.policy.governanceThreshold === 1 ? "" : "s"} - - - - setOpen(false)} title={existing ? (bits === 0 ? "Remove member" : "Change roles") : "Add member"}> - setTarget(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} editable={!existing} /> { scanBus.request((a) => setTarget(a)); nav.navigate("Scan"); }} /> - - - {ROLE_BITS.map(([b, name, desc]) => ( - toggle(b)} style={{ flexDirection: "row", alignItems: "center", gap: 12, padding: 12, borderRadius: 12, backgroundColor: bits & b ? C.accentBg : C.card2, borderWidth: 1, borderColor: bits & b ? C.accent : "transparent" }}> - - {name}{desc} - - ))} - - - - {existing && bits !== 0 && } - - - ); -} diff --git a/mobile/src/screens/Notifications.tsx b/mobile/src/screens/Notifications.tsx deleted file mode 100644 index 56d70da..0000000 --- a/mobile/src/screens/Notifications.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { Switch, Text, View } from "react-native"; -import { fmtRelative, short } from "@web/lib/format"; -import { Status } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { describeProposal } from "../lib/describe"; -import { needsMe } from "../hooks/useAlerts"; -import { useMyRoles } from "../hooks/useVault"; -import { useStore } from "../state/store"; -import { BackButton, Badge, Card, CircleIcon, Empty, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; - - -/** Safe's notification centre: what needs this signer, then what happened recently. */ -export function NotificationsScreen({ vault }: { vault: VaultData }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); - const { signer, notifications, setNotifications } = useStore(); - const roles = useMyRoles(vault); - const due = needsMe(vault, roles, signer?.address.toLowerCase() ?? null); - const recent = [...vault.proposals].sort((a, b) => Number(b.createdAt - a.createdAt)).slice(0, 12); - return ( - nav.goBack()} />} center={Updates} />}> - - - } title="Notify me on this phone" subtitle="When a proposal needs you" trailing={ void setNotifications(v)} trackColor={{ true: C.accent }} />} last /> - - Needs you · {due.length} - {due.length === 0 ? Nothing needs your signature right now. : ( - - {due.map((p, i) => { const d = describeProposal(p, vault); return } title={`${d.title} requires your confirmation`} subtitle={`${d.detail} · ${fmtRelative(p.createdAt)}`} chevron onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} last={i === due.length - 1} />; })} - - )} - Recent activity - {recent.length === 0 ? No proposals yet. : ( - - {recent.map((p, i) => { const d = describeProposal(p, vault); const tone = p.status === Status.EXECUTED ? "success" : p.status === Status.VETOED ? "error" : p.status === Status.PENDING ? "warn" : "dark"; return } title={`${d.title} · ${["", "pending", "executed", "cancelled", "vetoed"][p.status]}`} subtitle={`${d.detail} · by ${short(p.proposer)} · ${fmtRelative(p.createdAt)}`} trailing={p.status === Status.PENDING ? {p.liveApprovals}/{p.requiredApprovals} : undefined} chevron onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} last={i === recent.length - 1} />; })} - - )} - - - ); -} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx deleted file mode 100644 index dcd88b7..0000000 --- a/mobile/src/screens/Onboard.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useEffect, useState } from "react"; -import { Pressable, Text, View } from "react-native"; -import { isAddress } from "viem"; -import { SkurFactoryAbi } from "@web/abi/SkurFactory"; -import { DEPLOYMENTS } from "@web/config/chain"; -import { short } from "@web/lib/format"; -import { publicClient } from "../lib/client"; -import { scanBus } from "../lib/scanBus"; -import { useStore } from "../state/store"; -import { useTheme } from "../state/theme"; -import { Identicon } from "../components/Identicon"; -import { Card, CircleIcon, Icon, IconButton, Input, Logo, Row, Screen, Sheet, TopBar, useStyles } from "../components/ui"; -import { F } from "../theme"; - -/** Add an account, the way a wallet does it: a short title, then the ways in, as rows. */ -export function Onboard() { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ navigate: (n: string) => void }>(); - const { setVaultAddress, signer, createSigner, labels } = useStore(); - const [sheet, setSheet] = useState(false); - const [addr, setAddr] = useState(""); - const [mine, setMine] = useState<`0x${string}`[]>([]); - const [looking, setLooking] = useState(false); - - useEffect(() => { - if (!signer) return; - setLooking(true); - publicClient.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [signer.address] }) - .then((v) => setMine([...v].filter((a) => a.toLowerCase() !== DEPLOYMENTS.demoVault.toLowerCase()))) - .catch(() => setMine([])) - .finally(() => setLooking(false)); - }, [signer]); - - const open = (a: `0x${string}`) => { setSheet(false); void setVaultAddress(a); }; - - return ( - } right={ { scanBus.request((a) => open(a as `0x${string}`)); nav.navigate("Scan"); }} />} />}> - Add a vault - Open one you belong to, or watch any vault by address. - - {signer && ( - <> - Your vaults - - {looking && mine.length === 0 ? } title="Looking up your vaults…" subtitle={short(signer.address)} last /> - : mine.length === 0 ? } title="No vault has this signer yet" subtitle={`Add ${short(signer.address)} as a member`} last /> - : mine.map((v, i) => } title={labels[v.toLowerCase()] ?? "Treasury vault"} subtitle={short(v, 6)} onPress={() => open(v)} chevron last={i === mine.length - 1} />)} - - - )} - - Get started - - } title="Create a vault" subtitle="Name, template, members" onPress={() => nav.navigate("CreateVault")} chevron /> - } title="Watch a vault" subtitle="Read any vault by its address" onPress={() => setSheet(true)} chevron /> - } title="Demo vault" subtitle={short(DEPLOYMENTS.demoVault, 6)} onPress={() => open(DEPLOYMENTS.demoVault)} chevron /> - {!signer && } title="Create a signer key" subtitle="Kept in this phone's keychain" onPress={() => void createSigner()} chevron last />} - } title="Signers on this phone" subtitle={signer ? short(signer.address) : "None yet"} onPress={() => nav.navigate("Signers")} chevron last={Boolean(signer)} /> - - - - A - Ark Constellation devnet · chain 9000 - - - setSheet(false)} title="Watch a vault"> - - setAddr(t.trim())} placeholder="0x… vault address" mono autoFocus style={{ flex: 1 }} /> - { setSheet(false); scanBus.request((a) => setAddr(a)); nav.navigate("Scan"); }} /> - - open(addr as `0x${string}`)} - style={({ pressed }) => ({ height: 48, borderRadius: 12, backgroundColor: C.accent, alignItems: "center", justifyContent: "center", flexDirection: "row", gap: 8, opacity: !isAddress(addr) ? 0.4 : pressed ? 0.85 : 1 })}> - - Open vault - - - - ); -} diff --git a/mobile/src/screens/Policy.tsx b/mobile/src/screens/Policy.tsx deleted file mode 100644 index 12bd1c3..0000000 --- a/mobile/src/screens/Policy.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useRef, useState } from "react"; -import { Pressable, Switch, Text, View } from "react-native"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { fmtAmount, fmtDuration, parseAmount } from "@web/lib/format"; -import { limitReductions, policyReductions, policyToContract, validateLimits, validatePolicy } from "@web/lib/policy"; -import { H, POLICY_GROUPS, type PolicyField } from "@web/lib/policyFields"; -import { TEMPLATES, type TemplateId } from "@web/lib/templates"; -import { ROLE_OWNER, type AssetLimits, type Policy } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { useStore } from "../state/store"; -import { BackButton, Badge, Button, Card, Expandable, Field, Input, Notice, Screen, SignBar, Tabs, TopBar, TxStatus, type IconName, useStyles } from "../components/ui"; -import { F } from "../theme"; - -const GROUP_ICON: Record = { Approvals: "users", Delays: "clock", Exposure: "pie-chart", "Circuit breaker": "zap" }; - -/** One line per group, opened on tap: the whole policy stays readable on a phone. */ -function groupSummary(fields: PolicyField[], p: Policy): string { - return fields.slice(0, 3).map((f) => { - const v = p[f.key]; - if (f.unit === "bool") return `${f.label.split(" ")[0]} ${v ? "yes" : "no"}`; - if (f.unit === "hours") return fmtDuration(Number(v)); - if (f.unit === "bps") return `${Number(v) / 100}%`; - return String(v); - }).join(" · "); -} - -/** The policy editor: templates, every control in groups, security-reducing detection, and per-asset limits. */ -export function Policy({ vault }: { vault: VaultData }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void }>(); - const { signer } = useStore(); - const roles = useMyRoles(vault); - const isOwner = Boolean(roles & ROLE_OWNER); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(invalidate); - const [tab, setTab] = useState<"policy" | "limits">("policy"); - const [open, setOpen] = useState(null); - const toggle = (k: string) => setOpen((o) => (o === k ? null : k)); - const [draft, setDraft] = useState(vault.policy); - const [template, setTemplate] = useState(null); - const seen = useRef(vault.policyVersion); - if (seen.current !== vault.policyVersion) { seen.current = vault.policyVersion; if (JSON.stringify(draft) !== JSON.stringify(vault.policy)) setDraft(vault.policy); } - const changed = JSON.stringify(draft) !== JSON.stringify(vault.policy); - const errors = validatePolicy(draft); - const reductions = policyReductions(vault.policy, draft); - const set = (k: keyof Policy, v: number | boolean) => setDraft((d) => ({ ...d, [k]: v })); - - // asset limits - const [assetAddr, setAssetAddr] = useState(vault.assets[0]?.address); - const asset = vault.assets.find((a) => a.address === assetAddr) ?? vault.assets[0]; - const toText = (l: AssetLimits, d: number) => ({ approved: l.approved, lowMax: fmtAmount(l.lowMax, d, undefined, 6).replace(/,/g, ""), highMax: fmtAmount(l.highMax, d, undefined, 6).replace(/,/g, ""), perTxMax: fmtAmount(l.perTxMax, d, undefined, 6).replace(/,/g, ""), dailyMax: fmtAmount(l.dailyMax, d, undefined, 6).replace(/,/g, "") }); - const [text, setText] = useState(asset ? toText(asset.limits, asset.decimals) : null); - const [textFor, setTextFor] = useState(assetAddr); - if (asset && textFor !== asset.address) { setTextFor(asset.address); setText(toText(asset.limits, asset.decimals)); } - const parsed: AssetLimits | null = asset && text ? (() => { const p = (t: string) => parseAmount(t || "0", asset.decimals); const a = [p(text.lowMax), p(text.highMax), p(text.perTxMax), p(text.dailyMax)]; return a.every((x) => x !== null) ? { approved: text.approved, lowMax: a[0]!, highMax: a[1]!, perTxMax: a[2]!, dailyMax: a[3]! } : null; })() : null; - const limitErrors = parsed ? validateLimits(parsed) : ["Enter valid amounts."]; - const limitReds = asset && parsed ? limitReductions(asset.limits, parsed) : []; - const limitsChanged = asset && parsed ? JSON.stringify(parsed, (_, v) => (typeof v === "bigint" ? v.toString() : v)) !== JSON.stringify(asset.limits, (_, v) => (typeof v === "bigint" ? v.toString() : v)) : false; - - const proposePolicy = () => void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposePolicy", args: [policyToContract(draft)] }); - const proposeLimits = () => parsed && asset && void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeAssetLimits", args: [asset.address, parsed] }); - - return ( - nav.goBack()} />} center={Policy} right={v{vault.policyVersion}} />} - footer={ - - - - {tab === "policy" - ? 0 || tx.busy} loading={tx.busy} hint={!isOwner ? "Only an owner signer can propose a policy" : !changed ? "Nothing has changed yet" : errors.length ? errors[0] : reductions.length ? `Waits ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto` : "Applies as soon as owners approve"} /> - : 0 || tx.busy} loading={tx.busy} hint={!isOwner ? "Only an owner signer can propose limits" : !limitsChanged ? "Nothing has changed yet" : limitErrors.length ? limitErrors[0] : limitReds.length ? `Security-reducing: ${limitReds.join("; ")}` : "Applies as soon as owners approve"} />} - - }> - - - - {tab === "policy" && ( - - t.id === template)?.name} loaded` : `${TEMPLATES.length} profiles to start from`} icon="layers" open={open === "templates"} onToggle={() => toggle("templates")}> - - {TEMPLATES.map((t) => ( - { setTemplate(t.id); setDraft(t.policy); }} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: template === t.id ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{t.name} - ))} - - {changed && } - - - {POLICY_GROUPS.map((g) => { - const edited = g.fields.filter((f) => draft[f.key] !== vault.policy[f.key]).length; - return ( - toggle(g.title)}> - {g.fields.map((f, i) => set(f.key, v)} last={i === g.fields.length - 1} />)} - - ); - })} - - {errors.length > 0 && {errors.join(" ")}} - {changed && errors.length === 0 && {reductions.length ? `Security-reducing: ${reductions.join("; ")}. Delayed ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto.` : "Tightens or keeps every control. Applies as soon as owners approve."}} - - toggle("history")}> - {vault.policyHistory.length === 0 ? No policy versions recorded yet. : [...vault.policyHistory].reverse().map((h) => v{h.version} · activated {new Date(Number(h.activatedAt) * 1000).toLocaleString()})} - - - )} - {tab === "limits" && asset && text && ( - - - {vault.assets.map((a) => setAssetAddr(a.address)} style={{ paddingHorizontal: 14, height: 36, borderRadius: 18, backgroundColor: a.address === assetAddr ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{a.symbol})} - - - ApprovedUnapproved assets cannot be paid out. setText({ ...text, approved: v })} trackColor={{ true: C.accent }} /> - {([["lowMax", "Routine up to", "At or below this amount a payment is Low tier."], ["highMax", "High up to", "Above this a payment is Critical."], ["perTxMax", "Per-transaction cap", "0 = no cap."], ["dailyMax", "Daily cap", "Cumulative per 24h bucket. 0 = no cap."]] as Array<[keyof typeof text, string, string]>).map(([k, label, hint]) => ( - setText({ ...text, [k]: v })} keyboardType="decimal-pad" /> - ))} - - {limitErrors.length > 0 && limitsChanged && {limitErrors.join(" ")}} - Current: routine ≤ {fmtAmount(asset.limits.lowMax, asset.decimals)} · high ≤ {fmtAmount(asset.limits.highMax, asset.decimals)} · per tx ≤ {asset.limits.perTxMax ? fmtAmount(asset.limits.perTxMax, asset.decimals) : "∞"} · daily ≤ {asset.limits.dailyMax ? fmtAmount(asset.limits.dailyMax, asset.decimals) : "∞"} - - )} - - ); -} - -function Control({ f, value, live, onChange, last }: { f: PolicyField; value: number | boolean; live: number | boolean; onChange: (v: number | boolean) => void; last: boolean }) { - const C = useTheme(); const s = useStyles(); - const changed = value !== live; - const label = {f.label}{f.hint ? {f.hint} : null}; - const wrap = (control: React.ReactNode) => {label}{control}; - if (f.unit === "bool") return wrap( onChange(v)} trackColor={{ true: C.accent }} />); - const n = Number(value); - if (f.unit === "count") return wrap( onChange(Math.max(0, v))} />); - if (f.unit === "hours") return wrap( onChange(Math.round(Number(t || 0) * H))} />); - return wrap( onChange(Math.min((f.max ?? 100) * 100, Math.round(Number(t || 0) * 100)))} />); -} -function Stepper({ value, onChange }: { value: number; onChange: (v: number) => void }) { - const C = useTheme(); - const B = ({ t, onPress }: { t: string; onPress: () => void }) => {t}; - return onChange(value - 1)} />{value} onChange(value + 1)} />; -} -function Unit({ value, unit, onChange }: { value: string; unit: string; onChange: (t: string) => void }) { - const C = useTheme(); - return {unit}; -} diff --git a/mobile/src/screens/Receive.tsx b/mobile/src/screens/Receive.tsx deleted file mode 100644 index dc56d4a..0000000 --- a/mobile/src/screens/Receive.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { Text, View } from "react-native"; -import type { VaultData } from "@web/lib/vaultReads"; -import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Card, Screen, Tape, TopBar, useStyles } from "../components/ui"; -import { F } from "../theme"; - -export function Receive({ vault }: { vault: VaultData }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void }>(); - return ( - nav.goBack()} />} center={Receive} />}> - - - Vault address - Ark Constellation devnet · chain 9000 -
      - Tap to copy. Deposits are always accepted. - - - - ); -} diff --git a/mobile/src/screens/Scan.tsx b/mobile/src/screens/Scan.tsx deleted file mode 100644 index b72e999..0000000 --- a/mobile/src/screens/Scan.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { CameraView, useCameraPermissions } from "expo-camera"; -import { useRef, useState } from "react"; -import { Text, View } from "react-native"; -import { isAddress } from "viem"; -import { scanBus } from "../lib/scanBus"; -import { BackButton, Button, Notice, Screen, Tape, TopBar, useStyles } from "../components/ui"; -import { F } from "../theme"; - -/** QR scanner for vault and recipient addresses, as Safe's scan button. Accepts a bare address or an EIP-681 "ethereum:0x…" URI. */ -export function Scan() { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void }>(); - const [permission, requestPermission] = useCameraPermissions(); - const [err, setErr] = useState(null); - const done = useRef(false); - const onScanned = ({ data }: { data: string }) => { - if (done.current) return; - const m = data.match(/0x[0-9a-fA-F]{40}/); - if (!m || !isAddress(m[0])) { setErr("That code does not contain an address."); return; } - done.current = true; scanBus.deliver(m[0]); nav.goBack(); - }; - return ( - { scanBus.clear(); nav.goBack(); }} />} center={Scan} />}> - - {permission?.granted ? ( - - ) : ( - - Skur needs the camera to read a QR code. Nothing is recorded. - - - )} - - - Point at a vault or recipient address QR code. - {err ? {err} : null} - - ); -} diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx deleted file mode 100644 index f57ec71..0000000 --- a/mobile/src/screens/Security.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { RefreshControl, Text, View } from "react-native"; -import { isAddress, stringToHex } from "viem"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { NATIVE_ASSET } from "@web/config/chain"; -import { fmtAmount, fmtDuration, short } from "@web/lib/format"; -import { computeMaxLoss } from "@web/lib/maxLoss"; -import { postureItems } from "@web/lib/posture"; -import { Mode, MODE_LABEL, ROLE_GUARDIAN, ROLE_OWNER } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { Identicon } from "../components/Identicon"; -import { BackButton, Badge, Button, Card, Expandable, Field, Input, KV, ModeBadge, Notice, Row, Screen, Tape, TopBar, TxStatus, useStyles } from "../components/ui"; -import { F } from "../theme"; - -type Panel = "posture" | "mode" | "guardians" | "recovery" | "loss" | "history" | null; - -/** One card per concern, each opening on tap, so the screen reads as a short list rather than a wall. */ -export function Security({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; canGoBack: () => boolean }>(); - const roles = useMyRoles(vault); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(invalidate); - const [open, setOpen] = useState("posture"); - const [reason, setReason] = useState(""); - const [oldSigner, setOldSigner] = useState(""); - const [newSigner, setNewSigner] = useState(""); - const toggle = (p: Panel) => setOpen((o) => (o === p ? null : p)); - const r32 = stringToHex(reason.slice(0, 31), { size: 32 }); - const call = (fn: string, args: readonly unknown[]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); - const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); - const posture = postureItems(vault); - const ok = posture.filter((i) => i.ok === "ok").length; - const weakest = posture.find((i) => i.ok === "bad") ?? posture.find((i) => i.ok === "warn"); - const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; - const loss = stable ? computeMaxLoss(vault.policy, stable.limits, stable.balance, vault.mode) : null; - const canRaise = Boolean(roles & (ROLE_OWNER | ROLE_GUARDIAN)); - const isGuardian = Boolean(roles & ROLE_GUARDIAN); - - return ( - } - top={<> nav.goBack()} /> : undefined} title="Security" right={} />{vault.mode !== Mode.NORMAL && }}> - - toggle("posture")}> - {posture.map((i) => ( - - {i.ok === "ok" ? "✓" : i.ok === "warn" ? "!" : "✕"} - {i.text} - - ))} - - - toggle("mode")}> - - - {vault.mode < Mode.ELEVATED && } - {vault.mode < Mode.LOCKDOWN && } - {vault.mode > Mode.NORMAL && } - - {canRaise ? "Lowering needs owners and guardians." : "Owners and guardians only."} - - - toggle("guardians")}> - {guardians.length === 0 ? No guardian configured. Nobody independent can veto a proposal or freeze the vault. : guardians.map((g) => ( - {short(g.address, 6)}Guardian - ))} - - - - - toggle("recovery")}> - setOldSigner(t.trim())} placeholder="0x…" mono /> - setNewSigner(t.trim())} placeholder="0x…" mono /> - - {!isGuardian && Guardians only.} - - - {loss && stable && ( - toggle("loss")}> - - - - - )} - - toggle("history")}> - {vault.modeHistory.length === 0 ? The mode has never changed. : [...vault.modeHistory].reverse().slice(0, 8).map((h, i, arr) => ( - - ))} - - - - - - ); -} diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx deleted file mode 100644 index eb8e25e..0000000 --- a/mobile/src/screens/Send.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { useNavigation, useRoute } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useEffect, useState } from "react"; -import { Pressable, Text, View } from "react-native"; -import { scanBus } from "../lib/scanBus"; -import { Identicon } from "../components/Identicon"; -import { TokenMark } from "../components/TokenMark"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { fmtAmount, fmtBps, fmtDuration, parseAmount, short } from "@web/lib/format"; -import { describeError } from "@web/lib/errors"; -import { explainReasons, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { publicClient } from "../lib/client"; -import { useInvalidateVault } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { useStore } from "../state/store"; -import { BackButton, Badge, Button, Card, CircleIcon, Field, IconButton, Input, KV, Notice, Row, Screen, Sheet, SignBar, TierBadge, TopBar, TrustBadge, TxStatus, useStyles } from "../components/ui"; -import { F } from "../theme"; - -type Preview = { tier: Tier; reasons: number; exposureBps: number; requiredApprovals: number; requiredGuardians: number; delay: number; trust: Trust }; - -/** Send: big amount, asset chips, recipient and purpose; the vault's own review card; sticky sign bar to propose. */ -export function Send({ vault }: { vault: VaultData }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); - const route = useRoute<{ key: string; name: string; params?: { asset?: `0x${string}`; to?: `0x${string}` } }>(); - const { signer } = useStore(); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(() => { invalidate(); }); - const [to, setTo] = useState(route.params?.to ?? ""); - const [assetAddr, setAssetAddr] = useState(route.params?.asset ?? vault.assets[0]?.address); - const [pickRecipient, setPickRecipient] = useState(false); - const [amountText, setAmountText] = useState(""); - const [memo, setMemo] = useState(""); - const [preview, setPreview] = useState(null); - const [previewError, setPreviewError] = useState(null); - const [loading, setLoading] = useState(false); - const [showWhy, setShowWhy] = useState(true); - const asset = vault.assets.find((a) => a.address === assetAddr) ?? vault.assets[0]; - const amount = asset ? parseAmount(amountText, asset.decimals) : null; - const ok = isAddress(to) && amount !== null && amount > 0n && Boolean(asset); - - useEffect(() => { - if (!ok || !asset || amount === null) { setPreview(null); setPreviewError(null); return; } - let live = true; setLoading(true); - (async () => { - try { - const [r, rec] = await Promise.all([ - publicClient.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "previewTransfer", args: [asset.address, to as `0x${string}`, amount] }), - publicClient.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "getRecipient", args: [to as `0x${string}`] }), - ]); - if (!live) return; - setPreview({ tier: Number(r.tier) as Tier, reasons: Number(r.reasons), exposureBps: Number(r.exposureBps), requiredApprovals: Number(r.requiredApprovals), requiredGuardians: Number(r.requiredGuardians), delay: Number(r.delay), trust: Number(rec.trust) as Trust }); - setPreviewError(null); - } catch (e) { if (live) { setPreview(null); setPreviewError(describeError(e)); } } - finally { if (live) setLoading(false); } - })(); - return () => { live = false; }; - }, [ok, to, assetAddr, amountText, vault.address, asset, amount]); - - const submit = () => { if (!asset || amount === null) return; void tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [asset.address, to as `0x${string}`, amount, memo] }); }; - const remaining = asset && amount !== null ? asset.balance - amount : 0n; - const reasons = preview ? explainReasons(preview.reasons) : []; - const done = tx.state.phase === "done"; - - return ( - nav.goBack()} />} center={Send} />} - footer={ - - - - {done ? - : } - - }> - - - {vault.assets.map((a) => ( - setAssetAddr(a.address)} style={[{ flexDirection: "row", alignItems: "center", gap: 6, paddingHorizontal: 12, height: 34, borderRadius: 17, backgroundColor: C.card2 }, a.address === assetAddr && { backgroundColor: C.accent }]}> - - {a.symbol} - - ))} - - - {asset ? `Vault holds ${fmtAmount(asset.balance, asset.decimals, asset.symbol)}` : ""} - - - - - {isAddress(to) ? : } - setTo(t.trim())} placeholder="0x…" mono style={{ flex: 1 }} /> - {vault.recipients.length > 0 && setPickRecipient(true)} />} - { scanBus.request((a) => setTo(a)); nav.navigate("Scan"); }} /> - - - - - - - {loading && Asking the vault how it scores this payment…} - {previewError && {previewError}} - {preview && asset && amount !== null && ( - <> - - } title="Transaction checks" subtitle={`${TIER_LABEL[preview.tier]} · ${preview.requiredApprovals} approval${preview.requiredApprovals === 1 ? "" : "s"}${preview.requiredGuardians ? ` + ${preview.requiredGuardians} guardian` : ""}${preview.delay ? ` · after ${fmtDuration(preview.delay)}` : " · no delay"}`} trailing={} chevron onPress={() => setShowWhy((v) => !v)} last={!showWhy} /> - {showWhy && ( - - - - {TRUST_LABEL[preview.trust]}{preview.trust === Trust.UNKNOWN ? " · registered as New" : ""}} last={reasons.length === 0} /> - {reasons.length > 0 && Why this tier{reasons.map((t) => ▪ {t})}} - - )} - - - )} - setPickRecipient(false)} title="Known recipients"> - {vault.recipients.map((r, i) => ( - } title={short(r.address, 6)} subtitle={`${r.paymentCount.toString()} payment${r.paymentCount === 1n ? "" : "s"}`} trailing={} onPress={() => { setTo(r.address); setPickRecipient(false); }} last={i === vault.recipients.length - 1} /> - ))} - - - ); -} diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx deleted file mode 100644 index 0185997..0000000 --- a/mobile/src/screens/Settings.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import * as LocalAuthentication from "expo-local-authentication"; -import { useScheme, useTheme } from "../state/theme"; -import { useNavigation } from "@react-navigation/native"; -import { useEffect, useState } from "react"; -import { Linking, Switch, Text, View } from "react-native"; -import { ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC, DEPLOYMENTS } from "@web/config/chain"; -import { short } from "@web/lib/format"; -import { roleNames } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useMyRoles } from "../hooks/useVault"; -import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { Address, Badge, Button, Card, CircleIcon, Field, Icon, Input, Logo, Notice, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; - - -export function Settings({ vault }: { vault: VaultData | undefined }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); - const { vaultAddress, setVaultAddress, labels, setLabel, signer, biometrics, setBiometrics } = useStore(); - const roles = useMyRoles(vault); - const [name, setName] = useState(vaultAddress ? labels[vaultAddress.toLowerCase()] ?? "" : ""); - const [bioAvailable, setBioAvailable] = useState(false); - const { scheme, setScheme } = useScheme(); - useEffect(() => { void (async () => setBioAvailable((await LocalAuthentication.hasHardwareAsync()) && (await LocalAuthentication.isEnrolledAsync())))(); }, []); - - return ( - } />}> - - Vault - - {vaultAddress ? ( - <> - } title={ { setName(t); void setLabel(vaultAddress, t); }} placeholder="Treasury vault" maxLength={40} style={{ height: 36, paddingHorizontal: 10, backgroundColor: "transparent", borderWidth: 0, fontFamily: "DMSans_700Bold" }} />} subtitle={
      } /> - } title="Policy" subtitle={vault ? `v${vault.policyVersion} · templates, tiers, delays, caps` : "…"} onPress={() => nav.navigate("Policy")} chevron /> - } title="Members" subtitle={vault ? `${vault.members.length} members · roles and thresholds` : "…"} onPress={() => nav.navigate("Members")} chevron /> - } title="Address book" subtitle="Recipients and trust" onPress={() => nav.navigate("AddressBook")} chevron /> - } title="Simulator" subtitle="Attacks against the policy" onPress={() => nav.navigate("Simulator")} chevron /> - } title="Updates" subtitle="What needs you" onPress={() => nav.navigate("Notifications")} chevron /> - } title="Security" subtitle="Mode, guardians, posture" onPress={() => nav.navigate("Security")} chevron /> - } title="View on Blockscout" onPress={() => void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vaultAddress}`)} chevron /> - } title="Switch vault" onPress={() => void setVaultAddress(null)} chevron /> - } title="Create a new vault" subtitle="One signature" onPress={() => nav.navigate("CreateVault")} chevron last /> - - ) : <>} title="Open a vault" onPress={() => void setVaultAddress(null)} chevron />} title="Create a new vault" onPress={() => nav.navigate("CreateVault")} chevron last />} - - - Signers on this phone - - : } title={signer ? signer.label : "No signer yet"} subtitle={signer ?
      : "Create or import a key to sign from this phone"} trailing={roles ? {roleNames(roles).length > 2 ? "All roles" : roleNames(roles).join(" · ")} : signer ? no role : undefined} onPress={() => nav.navigate("Signers")} chevron /> - } title="Require Face ID to sign" subtitle={bioAvailable ? "Before every signature" : "Not enrolled on this device"} trailing={ void setBiometrics(v)} trackColor={{ true: C.accent }} />} last /> - - - Appearance - - {([["light", "Light", "sun"], ["dark", "Dark", "moon"], ["system", "System", "smartphone"]] as const).map(([v, label, icon], i) => ( - } title={label} onPress={() => setScheme(v)} last={i === 2} - trailing={scheme === v ? : undefined} /> - ))} - - - - - ); -} diff --git a/mobile/src/screens/Signers.tsx b/mobile/src/screens/Signers.tsx deleted file mode 100644 index 25f54fb..0000000 --- a/mobile/src/screens/Signers.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { Alert, Text, View } from "react-native"; -import { roleNames } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, CircleIcon, Field, Icon, Input, Notice, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; -import { F } from "../theme"; - -/** Safe's "Select signer": every key on this phone, which one signs, and how to add or remove one. */ -export function Signers({ vault }: { vault: VaultData | undefined }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void }>(); - const { signers, signer, setActiveSigner, createSigner, importSigner, removeSigner } = useStore(); - const [importing, setImporting] = useState(false); - const [key, setKey] = useState(""); - const [err, setErr] = useState(null); - const rolesOf = (a: string) => vault?.members.find((m) => m.address.toLowerCase() === a.toLowerCase())?.roles ?? 0; - return ( - nav.goBack()} />} center={Select signer} />}> - - {signers.length === 0 && No signer on this phone yet. Create a key here, then add its address as a member of your vault, or import a key you already use.} - {signers.length > 0 && ( - - {signers.map((sg, i) => { - const r = rolesOf(sg.address); - return ( - } title={sg.label} subtitle={
      } onPress={() => void setActiveSigner(sg.address)} last={i === signers.length - 1} - trailing={{r ? {roleNames(r).length > 2 ? "All roles" : roleNames(r).join(" · ")} : vault ? no role : null}{signer?.address === sg.address ? : null}} /> - ); - })} - - )} - Add a signer - - } title="Create a signer key" subtitle="Kept in the device keychain" onPress={() => void createSigner()} chevron /> - } title="Import a private key" subtitle="A key you already use" onPress={() => setImporting((v) => !v)} chevron last={!importing} /> - {importing && ( - - - - {err && {err}} - - )} - - {signer && ( - <> - Active signer - - } title={Remove {signer.label}} subtitle="Deleted from this phone" chevron last - onPress={() => Alert.alert("Remove signer key?", "The key is deleted from this phone. Anything it can sign for becomes unreachable from here unless you have it backed up.", [{ text: "Keep", style: "cancel" }, { text: "Remove", style: "destructive", onPress: () => void removeSigner(signer.address) }])} /> - - - )} - - - ); -} diff --git a/mobile/src/screens/Simulator.tsx b/mobile/src/screens/Simulator.tsx deleted file mode 100644 index bb428d5..0000000 --- a/mobile/src/screens/Simulator.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useMemo, useState } from "react"; -import { Pressable, Text, View } from "react-native"; -import { NATIVE_ASSET } from "@web/config/chain"; -import { fmtAmount, parseAmount } from "@web/lib/format"; -import { runScenarios, type Verdict } from "@web/lib/simulator"; -import { TEMPLATES, type TemplateId } from "@web/lib/templates"; -import type { Policy } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { BackButton, Badge, Card, CircleIcon, Field, Input, Row, Screen, SectionLabel, TopBar, useStyles } from "../components/ui"; -import { F } from "../theme"; - -const TONE: Record = { blocked: "ok", impossible: "ok", delayed: "info", escalated: "warn", allowed: "bad" }; -const TEXT: Record = { blocked: "Blocked", impossible: "Not possible", delayed: "Delayed", escalated: "Escalated", allowed: "Would succeed" }; - -/** Runs the policy against the attacks that actually happen, with the contract's own rules. */ -export function Simulator({ vault }: { vault: VaultData | undefined }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ goBack: () => void }>(); - const [source, setSource] = useState<"vault" | TemplateId>(vault ? "vault" : "startup"); - const [balanceText, setBalanceText] = useState("1,000,000"); - const [approvers, setApprovers] = useState("3"); - const [guardians, setGuardians] = useState("1"); - const stable = vault?.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault?.assets[0]; - const decimals = stable?.decimals ?? 6; - const symbol = stable?.symbol ?? "USD"; - const { policy, limits } = useMemo(() => { - if (source === "vault" && vault && stable) return { policy: vault.policy as Policy, limits: stable.limits }; - const t = TEMPLATES.find((x) => x.id === source) ?? TEMPLATES[0]; - return { policy: t.policy, limits: t.stable }; - }, [source, vault, stable]); - const balance = source === "vault" && stable ? stable.balance : (parseAmount(balanceText, decimals) ?? 0n); - const approverCount = source === "vault" && vault ? vault.counts.approvers : Number(approvers) || 0; - const guardianCount = source === "vault" && vault ? vault.counts.guardians : Number(guardians) || 0; - const results = useMemo(() => runScenarios({ policy, limits, balance, decimals, symbol, approverCount, guardianCount }), [policy, limits, balance, decimals, symbol, approverCount, guardianCount]); - const stopped = results.filter((r) => r.verdict !== "allowed").length; - const [open, setOpen] = useState(null); - return ( - nav.goBack()} />} center={Simulator} right={{stopped}/{results.length} stopped} />}> - - Configuration under test - - {vault && setSource("vault")}>Live vault v{vault.policyVersion}} - {TEMPLATES.map((t) => setSource(t.id)}>{t.name})} - - {source === "vault" && stable ? Treasury {fmtAmount(stable.balance, stable.decimals, stable.symbol)} · {approverCount} approvers · {guardianCount} guardians : ( - - - - - - - - )} - Scenarios - - {results.map((r, i) => ( - - } title={r.title} subtitle={r.narrative} trailing={{TEXT[r.verdict]}} chevron onPress={() => setOpen(open === r.id ? null : r.id)} last={i === results.length - 1 && open !== r.id} /> - {open === r.id && {r.detail.map((d) => ▪ {d})}} - - ))} - - - - ); -} -function Chip({ on, onPress, children }: { on: boolean; onPress: () => void; children: React.ReactNode }) { - const C = useTheme(); - return {children}; -} diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx deleted file mode 100644 index 52c3385..0000000 --- a/mobile/src/screens/Transactions.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { useNavigation } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { Pressable, RefreshControl, Text, View } from "react-native"; -import { fmtDate } from "@web/lib/format"; -import { Kind, Status } from "@web/lib/types"; -import type { ProposalView, VaultData } from "@web/lib/vaultReads"; -import { describeProposal, statusText } from "../lib/describe"; -import { Badge, Card, CircleIcon, Empty, IconButton, Notice, Row, Screen, StatusBadge, Tabs, TopBar, type IconName, useStyles } from "../components/ui"; -import { F } from "../theme"; - -export const KIND_ICON: Record = { [Kind.TRANSFER]: "arrow-up-right", [Kind.POLICY_UPDATE]: "sliders", [Kind.ASSET_LIMITS]: "sliders", [Kind.MEMBER_SET]: "users", [Kind.RECIPIENT_TRUST]: "book", [Kind.MODE_RELAX]: "shield", [Kind.RECOVERY]: "life-buoy" }; - -export function Transactions({ vault, refetch, refreshing }: { vault: VaultData; refetch: () => void; refreshing: boolean }) { - const C = useTheme(); const s = useStyles(); - const nav = useNavigation<{ navigate: (n: string, p?: object) => void }>(); - const [tab, setTab] = useState<"queue" | "history">("queue"); - const [filter, setFilter] = useState<"all" | "transfers" | "governance">("all"); - const pendingCount = vault.proposals.filter((p) => p.status === Status.PENDING).length; - const items = vault.proposals.filter((p) => (tab === "queue" ? p.status === Status.PENDING : p.status !== Status.PENDING)).filter((p) => (filter === "all" ? true : filter === "transfers" ? p.kind === Kind.TRANSFER : p.kind !== Kind.TRANSFER)); - const groups = new Map(); - for (const p of items) { const d = fmtDate(p.createdAt).split(" at ")[0]; groups.set(d, [...(groups.get(d) ?? []), p]); } - return ( - } - top={ nav.navigate("Send")} />} />}> - - - - {(["all", "transfers", "governance"] as const).map((f) => ( - setFilter(f)} style={{ paddingHorizontal: 12, height: 32, borderRadius: 16, backgroundColor: filter === f ? C.accent : C.card2, alignItems: "center", justifyContent: "center" }}>{f === "all" ? "All types" : f === "transfers" ? "Transfers" : "Governance & security"} - ))} - - {vault.logsFailed && The chain's event log could not be read, so purposes and history details are missing.} - - {vault.activityLoading ? Reading proposals and history from the chain… : items.length === 0 ? ( - {tab === "queue" ? "Proposals waiting for confirmation or execution will appear here" : "Executed, cancelled and vetoed proposals will appear here"} - ) : [...groups.entries()].map(([date, ps]) => ( - - {date} - - {ps.map((p, i) => { - const d = describeProposal(p, vault); - return } title={d.title} subtitle={d.detail} onPress={() => nav.navigate("TxDetail", { id: String(p.id) })} chevron last={i === ps.length - 1} - trailing={p.status === Status.PENDING ? {statusText(p)} : } />; - })} - - - ))} - - ); -} diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx deleted file mode 100644 index 3539868..0000000 --- a/mobile/src/screens/TxDetail.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { useNavigation, useRoute } from "@react-navigation/native"; -import { useTheme } from "../state/theme"; -import { useState } from "react"; -import { Linking, Pressable, Text, View } from "react-native"; -import { stringToHex } from "viem"; -import { SkurVaultAbi } from "@web/abi/SkurVault"; -import { ARK_DEVNET_EXPLORER } from "@web/config/chain"; -import { fmtAmount, fmtDate, fmtDuration, nowSec, short } from "@web/lib/format"; -import { explainReasons, Kind, Mode, ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, Status } from "@web/lib/types"; -import type { VaultData } from "@web/lib/vaultReads"; -import { describeProposal, memoText, statusText } from "../lib/describe"; -import { useInvalidateVault, useMyRoles } from "../hooks/useVault"; -import { useTx } from "../hooks/useTx"; -import { useStore } from "../state/store"; -import { Identicon } from "../components/Identicon"; -import { Address, BackButton, Badge, Button, Card, CircleIcon, Icon, IconButton, KV, Notice, Row, Screen, SignBar, StatusBadge, TierBadge, TopBar, TxStatus, useStyles } from "../components/ui"; -import { KIND_ICON } from "./Transactions"; -import { F } from "../theme"; - -/** Safe's "Confirm transaction": hero amount, To card with advanced details, checks and confirmations rows, sticky sign bar. */ -export function TxDetail({ vault }: { vault: VaultData }) { - const C = useTheme(); const s = useStyles(); - const route = useRoute<{ key: string; name: string; params: { id: string } }>(); - const nav = useNavigation<{ goBack: () => void; navigate: (n: string, p?: object) => void }>(); - const { signer } = useStore(); - const roles = useMyRoles(vault); - const invalidate = useInvalidateVault(vault.address); - const tx = useTx(invalidate); - const [advanced, setAdvanced] = useState(false); - const [showChecks, setShowChecks] = useState(false); - const [showConf, setShowConf] = useState(false); - const p = vault.proposals.find((x) => String(x.id) === route.params.id); - if (!p) return nav.goBack()} />} />}>This proposal is not in the loaded range.; - const d = describeProposal(p, vault); - const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); - const now = nowSec(); - const pending = p.status === Status.PENDING; - const expired = pending && Number(p.expiresAt) <= now; - const timelocked = pending && Number(p.executableAfter) > now; - const approvalsMet = p.liveApprovals >= p.requiredApprovals && p.liveGuardians >= p.requiredGuardians; - const me = signer?.address.toLowerCase(); - const alreadyApproved = Boolean(me && (p.approvers.some((a) => a.toLowerCase() === me) || p.guardianConfirmers.some((a) => a.toLowerCase() === me))); - const isGuardian = Boolean(roles & ROLE_GUARDIAN); - const canApprove = pending && !expired && !alreadyApproved && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_APPROVER | ROLE_GUARDIAN : ROLE_OWNER | ROLE_GUARDIAN)) && (isGuardian ? p.requiredGuardians > 0 : true); - const lockedOut = vault.mode === Mode.LOCKDOWN && (p.kind === Kind.TRANSFER || p.securityReducing); - const canExecute = pending && !expired && approvalsMet && !timelocked && !lockedOut && Boolean(roles & (p.kind === Kind.TRANSFER ? ROLE_EXECUTOR | ROLE_OWNER : ROLE_OWNER)); - const canVeto = pending && p.vetoable && isGuardian; - const canCancel = pending && Boolean(me && (p.proposer.toLowerCase() === me || roles & ROLE_OWNER)); - const call = (fn: string, args: readonly unknown[] = [p.id]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: fn, args }); - const memo = memoText(p); - const reasons = p.kind === Kind.TRANSFER ? explainReasons(p.riskReasons) : []; - - const primary = !signer ? { label: "Add a signer to sign", onPress: () => nav.navigate("Main", { screen: "Settings" }), disabled: false, hint: undefined as string | undefined } - : roles === 0 ? { label: "Not a member of this vault", onPress: undefined, disabled: true, hint: `${short(signer.address)} holds no role here` } - : canApprove ? { label: isGuardian ? "Confirm as guardian" : "Confirm", onPress: () => call("approve"), disabled: false, hint: undefined } - : canExecute ? { label: "Execute", onPress: () => call("execute"), disabled: false, hint: undefined } - : pending && Boolean(roles & (ROLE_EXECUTOR | ROLE_OWNER)) ? { label: "Execute", onPress: undefined, disabled: true, hint: lockedOut ? "The vault is in Lockdown" : timelocked ? `Executable after ${fmtDate(p.executableAfter)}` : !approvalsMet ? "Waiting for more confirmations" : expired ? "This proposal has expired" : undefined } - : null; - - return ( - nav.goBack()} />} center={{pending ? "Confirm transaction" : "Transaction"}} right={ void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vault.address}`)} />} />} - footer={pending && primary ? ( - - - - - - ) : undefined}> - - - - {p.kind === Kind.TRANSFER && } - - {p.kind === Kind.TRANSFER && asset ? `-${fmtAmount(p.amount, asset.decimals, asset.symbol)}` : d.title} - {p.kind === Kind.TRANSFER ? d.title : d.detail} · {fmtDate(p.createdAt)} - {pending ? {statusText(p)} : } - - - - {p.kind === Kind.TRANSFER &&
      } />} - {memo ? : null} - - - {advanced && ( - <> - } /> - - Number(p.createdAt) ? fmtDuration(Number(p.executableAfter - p.createdAt)) : "none"} /> - - - - - )} - - - - {p.kind === Kind.TRANSFER && ( - - } title="Risk review" trailing={} chevron onPress={() => setShowChecks((v) => !v)} last={!showChecks} /> - {showChecks && {reasons.length === 0 ? No elevated risk signal. Routine tier. : reasons.map((t) => ▪ {t})}} - - )} - - } title="Confirmations" trailing={{p.liveApprovals}/{p.requiredApprovals}{p.requiredGuardians ? ` · ${p.liveGuardians}/${p.requiredGuardians} guardian` : ""}} chevron onPress={() => setShowConf((v) => !v)} last={!showConf} /> - {showConf && ( - - {p.approvers.length === 0 && p.guardianConfirmers.length === 0 ? None yet : null} - {p.approvers.map((a) => {short(a, 6)}signer)} - {p.guardianConfirmers.map((a) => {short(a, 6)}guardian)} - - )} - - - {pending && (canVeto || canCancel || expired) && ( - - {canVeto && } - {canCancel && !expired && } - {expired && } - - )} - {!pending && } - void Linking.openURL(`${ARK_DEVNET_EXPLORER}/address/${vault.address}`)} style={{ alignItems: "center", marginTop: 14 }}>View vault on Blockscout - - ); -} diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx deleted file mode 100644 index 4d6515b..0000000 --- a/mobile/src/screens/Welcome.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { useEffect, useRef, useState } from "react"; -import { Dimensions, Pressable, ScrollView, StatusBar, Text, View, type NativeScrollEvent, type NativeSyntheticEvent } from "react-native"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { Identicon } from "../components/Identicon"; -import { Icon } from "../components/ui"; -import { F, type Palette } from "../theme"; -import { useTheme } from "../state/theme"; - -const W = Dimensions.get("window").width; -const ART = 310; -/** The onboarding stands on the same ground as the app, so the two never disagree. */ -const ink = (C: Palette) => ({ bg: C.canvas, ink: C.text, ink2: C.text2, line: C.border, wash: C.card }); -const shade = (C: Palette) => ({ shadowColor: "#000", shadowOpacity: C.shadowOpacity * 1.2, shadowRadius: 24, shadowOffset: { width: 0, height: 12 }, elevation: 6 } as const); - -const PAGES = [ - { title: "Track your treasury.\nAnywhere.", sub: "Balances and activity, read live from the chain.", art: }, - { title: "Every payment,\nscored first.", sub: "Approvals, delay and veto, set by the vault.", art: }, - { title: "Sign the moment\nyou're needed.", sub: "Face ID to sign. The vault checks the policy.", art: }, -]; - -/** First launch: one idea per page, a real product surface as its illustration, and a single button. */ -export function Welcome({ onDone }: { onDone: () => void }) { - const C = useTheme(); const L = ink(C); const shadow = shade(C); - const insets = useSafeAreaInsets(); - const [page, setPage] = useState(0); - const ref = useRef(null); - const onScroll = (e: NativeSyntheticEvent) => setPage(Math.round(e.nativeEvent.contentOffset.x / W)); - // The carousel always opens on the first page, whatever the view was showing before. - useEffect(() => { ref.current?.scrollTo({ x: 0, animated: false }); setPage(0); }, []); - return ( - - - - S - Skur - {"[MOBILE]"} - - - - {PAGES.map((p, i) => ( - - {p.art} - {p.title} - {p.sub} - - ))} - - - - - {PAGES.map((_, i) => )} - - - ({ height: 56, borderRadius: 16, backgroundColor: L.ink, alignItems: "center", justifyContent: "center", opacity: pressed ? 0.85 : 1 })}> - Get started - - - - ); -} - -const VAULT = "0xCC31c7474267ca5600c2D530ebD7657A09c042Dc"; -const NEW_ADDR = "0x7c4f9A2b61e3d0c8F5a4B2e1D6c9A3f8E0b71e42"; - -function Coin({ label, size, bg, fg = "#fff", style }: { label: string; size: number; bg: string; fg?: string; style?: object }) { - const C = useTheme(); const L = ink(C); const shadow = shade(C); - return ( - - {label} - - ); -} - -/** Page 1: the vault as the app actually shows it, with its assets orbiting. */ -function ArtVault() { - const C = useTheme(); const L = ink(C); const shadow = shade(C); - return ( - - - - - - - - - - Treasury vault - Normal - - 250,000 sUSD - - {[["S", "Skur Test USD", "250,000", C.accent, C.onAccent], ["K", "KASH", "3", "#4c6ef5", "#fff"]].map(([l, name, amt, bg, fg]) => ( - - {l} - {name} - {amt} - - ))} - - - ); -} - -/** Page 2: the same payment at three sizes, and what the vault asks of each. */ -function ArtTiers() { - const C = useTheme(); const L = ink(C); const shadow = shade(C); - const rows: Array<{ amt: string; req: string; tier: string; bg: string; fg: string; dx: number }> = [ - { amt: "1,000 sUSD", req: "1 approval · now", tier: "Low", bg: "#e6f6ec", fg: "#1b7f4a", dx: -14 }, - { amt: "12,000 sUSD", req: "2 approvals · 1 day", tier: "High", bg: "#fff3d6", fg: "#a86a00", dx: 10 }, - { amt: "60,000 sUSD", req: "2 + a guardian", tier: "Critical", bg: "#ffe3e3", fg: "#b42318", dx: -6 }, - ]; - return ( - - {rows.map((r) => ( - - - - - - {r.amt} - {r.req} - - {r.tier} - - ))} - - ); -} - -/** Page 3: the alert that reaches you, over the confirmation it opens. */ -function ArtSign() { - const C = useTheme(); const L = ink(C); const shadow = shade(C); - return ( - - - - - Confirm transaction - −12,000 sUSD - to 0x7c4f…41e2 - - - - - - - A transaction needs you - just now - - - - - - - Policy check passed - - - ); -} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx deleted file mode 100644 index 33575c7..0000000 --- a/mobile/src/state/store.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import AsyncStorage from "@react-native-async-storage/async-storage"; -import * as SecureStore from "expo-secure-store"; -import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; -import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; - -export type Signer = { key: `0x${string}`; address: `0x${string}`; label: string }; -type Store = { - ready: boolean; - vaultAddress: `0x${string}` | null; - setVaultAddress: (a: `0x${string}` | null) => Promise; - labels: Record; - setLabel: (vault: `0x${string}`, name: string) => Promise; - /** The active signer, or null when the phone holds no key. */ - signer: Signer | null; - signers: Signer[]; - createSigner: (label?: string) => Promise; - importSigner: (key: string, label?: string) => Promise; - removeSigner: (address?: `0x${string}`) => Promise; - setActiveSigner: (address: `0x${string}`) => Promise; - renameSigner: (address: `0x${string}`, label: string) => Promise; - biometrics: boolean; - setBiometrics: (on: boolean) => Promise; - onboarded: boolean; - setOnboarded: (v?: boolean) => Promise; - notifications: boolean; - setNotifications: (on: boolean) => Promise; -}; - -const Ctx = createContext(null); -const K = { vault: "skur.vault", labels: "skur.labels", bio: "skur.biometrics", signer: "skur.signer", signers: "skur.signers", active: "skur.activeSigner", onboarded: "skur.onboarded", notif: "skur.notifications" }; - -const toSigner = (key: `0x${string}`, label: string): Signer => ({ key, address: privateKeyToAccount(key).address, label }); - -/** App state. Signer keys live only in the device keychain (expo-secure-store); nothing leaves the phone but signed transactions. */ -export function StoreProvider({ children }: { children: ReactNode }) { - const [ready, setReady] = useState(false); - const [vaultAddress, setVault] = useState<`0x${string}` | null>(null); - const [labels, setLabels] = useState>({}); - const [signers, setSigners] = useState([]); - const [active, setActive] = useState<`0x${string}` | null>(null); - const [biometrics, setBio] = useState(true); - const [onboarded, setOnb] = useState(false); - const [notifications, setNotif] = useState(true); - - useEffect(() => { - (async () => { - try { - const [v, l, b, legacy, list, act, o, n] = await Promise.all([AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.labels), AsyncStorage.getItem(K.bio), SecureStore.getItemAsync(K.signer), SecureStore.getItemAsync(K.signers), AsyncStorage.getItem(K.active), AsyncStorage.getItem(K.onboarded), AsyncStorage.getItem(K.notif)]); - if (v) setVault(v as `0x${string}`); - if (l) setLabels(JSON.parse(l)); - if (b !== null) setBio(b === "1"); - if (o === "1") setOnb(true); - if (n !== null) setNotif(n === "1"); - let arr: Array<{ key: `0x${string}`; label: string }> = list ? JSON.parse(list) : []; - if (legacy && !arr.some((x) => x.key === legacy)) { arr = [{ key: legacy as `0x${string}`, label: "Device signer" }, ...arr]; await SecureStore.setItemAsync(K.signers, JSON.stringify(arr)); await SecureStore.deleteItemAsync(K.signer); } - const ss = arr.map((x) => toSigner(x.key, x.label)); - setSigners(ss); - setActive((act as `0x${string}`) && ss.some((s) => s.address === act) ? (act as `0x${string}`) : ss[0]?.address ?? null); - } finally { - setReady(true); - } - })(); - }, []); - - const persist = useCallback(async (ss: Signer[]) => { setSigners(ss); await SecureStore.setItemAsync(K.signers, JSON.stringify(ss.map((s) => ({ key: s.key, label: s.label })))); }, []); - const setVaultAddress = useCallback(async (a: `0x${string}` | null) => { setVault(a); if (a) await AsyncStorage.setItem(K.vault, a); else await AsyncStorage.removeItem(K.vault); }, []); - const setLabel = useCallback(async (vault: `0x${string}`, name: string) => { setLabels((l) => { const n = { ...l, [vault.toLowerCase()]: name }; void AsyncStorage.setItem(K.labels, JSON.stringify(n)); return n; }); }, []); - const addSigner = useCallback(async (key: `0x${string}`, label: string) => { - const s = toSigner(key, label); - const next = signers.some((x) => x.address === s.address) ? signers : [...signers, s]; - await persist(next); - setActive(s.address); await AsyncStorage.setItem(K.active, s.address); - return s; - }, [signers, persist]); - const createSigner = useCallback((label?: string) => addSigner(generatePrivateKey(), label ?? `Signer ${signers.length + 1}`), [addSigner, signers.length]); - const importSigner = useCallback((raw: string, label?: string) => { const k = (raw.trim().startsWith("0x") ? raw.trim() : `0x${raw.trim()}`) as `0x${string}`; if (!/^0x[0-9a-fA-F]{64}$/.test(k)) throw new Error("A private key is 64 hex characters."); return addSigner(k, label ?? `Signer ${signers.length + 1}`); }, [addSigner, signers.length]); - const removeSigner = useCallback(async (address?: `0x${string}`) => { const target = address ?? active; const next = signers.filter((s) => s.address !== target); await persist(next); const a = next[0]?.address ?? null; setActive(a); if (a) await AsyncStorage.setItem(K.active, a); else await AsyncStorage.removeItem(K.active); }, [signers, active, persist]); - const setActiveSigner = useCallback(async (address: `0x${string}`) => { setActive(address); await AsyncStorage.setItem(K.active, address); }, []); - const renameSigner = useCallback(async (address: `0x${string}`, label: string) => { await persist(signers.map((s) => (s.address === address ? { ...s, label } : s))); }, [signers, persist]); - const setBiometrics = useCallback(async (on: boolean) => { setBio(on); await AsyncStorage.setItem(K.bio, on ? "1" : "0"); }, []); - const setOnboarded = useCallback(async (v = true) => { setOnb(v); await AsyncStorage.setItem(K.onboarded, v ? "1" : "0"); }, []); - const setNotifications = useCallback(async (on: boolean) => { setNotif(on); await AsyncStorage.setItem(K.notif, on ? "1" : "0"); }, []); - - const signer = useMemo(() => signers.find((s) => s.address === active) ?? null, [signers, active]); - const value = useMemo(() => ({ ready, vaultAddress, setVaultAddress, labels, setLabel, signer, signers, createSigner, importSigner, removeSigner, setActiveSigner, renameSigner, biometrics, setBiometrics, onboarded, setOnboarded, notifications, setNotifications }), - [ready, vaultAddress, setVaultAddress, labels, setLabel, signer, signers, createSigner, importSigner, removeSigner, setActiveSigner, renameSigner, biometrics, setBiometrics, onboarded, setOnboarded, notifications, setNotifications]); - return {children}; -} - -export function useStore(): Store { - const s = useContext(Ctx); - if (!s) throw new Error("StoreProvider missing"); - return s; -} diff --git a/mobile/src/state/theme.tsx b/mobile/src/state/theme.tsx deleted file mode 100644 index 62f7b97..0000000 --- a/mobile/src/state/theme.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import AsyncStorage from "@react-native-async-storage/async-storage"; -import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; -import { useColorScheme } from "react-native"; -import { DARK, LIGHT, type Palette } from "../theme"; - -export type Scheme = "light" | "dark" | "system"; -const Ctx = createContext<{ C: Palette; scheme: Scheme; dark: boolean; setScheme: (s: Scheme) => void } | null>(null); -const KEY = "skur.theme"; - -/** One ground for the whole app, onboarding included, switchable in Settings and remembered. */ -export function ThemeProvider({ children }: { children: ReactNode }) { - const system = useColorScheme(); - const [scheme, setSchemeState] = useState("system"); - useEffect(() => { void AsyncStorage.getItem(KEY).then((v) => { if (v === "light" || v === "dark" || v === "system") setSchemeState(v); }); }, []); - const setScheme = useCallback((s: Scheme) => { setSchemeState(s); void AsyncStorage.setItem(KEY, s); }, []); - const dark = scheme === "system" ? system === "dark" : scheme === "dark"; - const value = useMemo(() => ({ C: dark ? DARK : LIGHT, scheme, dark, setScheme }), [dark, scheme, setScheme]); - return {children}; -} - -export function useTheme(): Palette { - const t = useContext(Ctx); - if (!t) throw new Error("ThemeProvider missing"); - return t.C; -} - -export function useScheme() { - const t = useContext(Ctx); - if (!t) throw new Error("ThemeProvider missing"); - return t; -} diff --git a/mobile/src/theme.ts b/mobile/src/theme.ts deleted file mode 100644 index ec21780..0000000 --- a/mobile/src/theme.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** Skur's two grounds. Same tokens in both, so a screen never needs to know which one is on. */ -export type Palette = { - canvas: string; card: string; card2: string; border: string; - text: string; text2: string; text3: string; - accent: string; accentBg: string; onAccent: string; - success: string; successBg: string; warning: string; warningBg: string; - error: string; errorBg: string; info: string; infoBg: string; - shadowOpacity: number; -}; - -export const LIGHT: Palette = { - canvas: "#ffffff", card: "#f6f7f9", card2: "#eceef2", border: "#e4e7ec", - text: "#101418", text2: "#667085", text3: "#98a2b3", - accent: "#ffd000", accentBg: "#fff6cc", onAccent: "#101418", - success: "#11875a", successBg: "#e6f6ec", warning: "#a86a00", warningBg: "#fff3d6", - error: "#b42318", errorBg: "#ffe4e2", info: "#1971c2", infoBg: "#e7f1ff", - shadowOpacity: 0.08, -}; - -export const DARK: Palette = { - canvas: "#212529", card: "#2b3035", card2: "#343a40", border: "#495057", - text: "#f8f9fa", text2: "#adb5bd", text3: "#6c757d", - accent: "#ffd000", accentBg: "#3d3400", onAccent: "#212529", - success: "#75b798", successBg: "#1b4332", warning: "#ffa94d", warningBg: "#4d2e05", - error: "#ea868f", errorBg: "#4a1c22", info: "#6ea8fe", infoBg: "#1b3a5c", - shadowOpacity: 0.4, -}; - -export const F = { - display: "SpaceGrotesk_700Bold", - displayMedium: "SpaceGrotesk_600SemiBold", - body: "DMSans_400Regular", - bodyMedium: "DMSans_500Medium", - bodyBold: "DMSans_700Bold", - mono: "DMMono_400Regular", - monoMedium: "DMMono_500Medium", -} as const; - -export const R = { sm: 8, md: 12, lg: 16, pill: 999 } as const; diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json deleted file mode 100644 index 1704c70..0000000 --- a/mobile/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "extends": "expo/tsconfig.base", - "compilerOptions": { - "strict": true, - "resolveJsonModule": true, - "paths": { - "@web/*": [ - "../web/src/*" - ] - } - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "../web/src/lib/**/*.ts", - "../web/src/abi/*.ts", - "../web/src/config/*.ts" - ], - "exclude": [ - "node_modules", - "ios", - "android", - "../web/src/lib/*.test.ts", - "../web/src/lib/motion.ts" - ] -} \ No newline at end of file diff --git a/package.json b/package.json index 2242d0a..9dbf745 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,6 @@ "app:build": "cd app && npm run build", "test": "npm run move:test && npm run sdk:test", "typecheck": "cd sdk && npm run typecheck && cd ../server && npm run typecheck && cd ../app && npm run typecheck", - "legacy:contracts:test": "cd contracts && forge test", - "legacy:web:test": "cd web && npm test", "sui:seed": "cd sdk && npm run seed", "sui:e2e": "cd sdk && npm run e2e", "verify": "scripts/verify.sh" diff --git a/scripts/export-abi.py b/scripts/export-abi.py deleted file mode 100755 index 1ae94f5..0000000 --- a/scripts/export-abi.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 -"""Copy contract ABIs from the Foundry build into the web app as typed constants.""" -import json, os, sys -root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -out = os.path.join(root, 'contracts', 'out') -targets = {'SkurVault': 'SkurVault.sol/SkurVault.json', 'SkurFactory': 'SkurFactory.sol/SkurFactory.json', 'SkurTestUSD': 'SkurTestUSD.sol/SkurTestUSD.json'} -os.makedirs(os.path.join(root, 'web', 'src', 'abi'), exist_ok=True) -for name, rel in targets.items(): - abi = json.load(open(os.path.join(out, rel)))['abi'] - with open(os.path.join(root, 'web', 'src', 'abi', f'{name}.ts'), 'w') as f: - f.write(f'// Generated from contracts/out/{rel} by scripts/export-abi.py. Do not edit.\n') - f.write(f'export const {name}Abi = {json.dumps(abi, indent=2)} as const;\n') - print(name, len(abi), 'entries') diff --git a/scripts/verify.sh b/scripts/verify.sh index 22ac366..807f7fd 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -2,8 +2,6 @@ # Everything CI would run, in one command, so a red check for reasons outside the code does not # leave you without a signal. Mirrors .github/workflows/sui.yml job for job. # -# scripts/verify.sh the Sui build -# scripts/verify.sh --all also the previous EVM build, if Foundry is installed set -uo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" @@ -50,10 +48,5 @@ fi step "Interface · typecheck" bash -c "cd '$ROOT/app' && npm run --silent typecheck" step "Interface · build" bash -c "cd '$ROOT/app' && NEXT_TELEMETRY_DISABLED=1 npm run --silent build >/dev/null" -if [ "${1:-}" = "--all" ] && have forge; then - step "EVM · contracts (previous build)" bash -c "cd '$ROOT/contracts' && forge test >/dev/null" - step "EVM · interface (previous build)" bash -c "cd '$ROOT/web' && npm run --silent test" -fi - printf '\n\033[1m%s passed, %s failed\033[0m\n' "$PASS" "$FAIL" [ "$FAIL" -eq 0 ] || exit 1 diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index a547bf3..0000000 --- a/web/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/web/.oxlintrc.json b/web/.oxlintrc.json deleted file mode 100644 index 6fa991d..0000000 --- a/web/.oxlintrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": ["react", "typescript", "oxc"], - "rules": { - "react/rules-of-hooks": "error", - "react/only-export-components": ["warn", { "allowConstantExport": true }] - } -} diff --git a/web/README.md b/web/README.md deleted file mode 100644 index d6af7e3..0000000 --- a/web/README.md +++ /dev/null @@ -1,32 +0,0 @@ -# React + TypeScript + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) - -## React Compiler - -The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). - -## Expanding the Oxlint configuration - -If you are developing a production application, we recommend enabling type-aware lint rules by installing `oxlint-tsgolint` and editing `.oxlintrc.json`: - -```json -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": ["react", "typescript", "oxc"], - "options": { - "typeAware": true - }, - "rules": { - "react/rules-of-hooks": "error", - "react/only-export-components": ["warn", { "allowConstantExport": true }] - } -} -``` - -See the [Oxlint rules documentation](https://oxc.rs/docs/guide/usage/linter/rules) for the full list of rules and categories. diff --git a/web/index.html b/web/index.html deleted file mode 100644 index 5717bc8..0000000 --- a/web/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Skur · Treasury security - - -
      - - - diff --git a/web/package-lock.json b/web/package-lock.json deleted file mode 100644 index 493a0ec..0000000 --- a/web/package-lock.json +++ /dev/null @@ -1,9434 +0,0 @@ -{ - "name": "web", - "version": "0.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "web", - "version": "0.0.0", - "dependencies": { - "@tanstack/react-query": "^5.102.8", - "react": "^19.2.8", - "react-dom": "^19.2.8", - "viem": "^2.56.5", - "wagmi": "^2.19.5" - }, - "devDependencies": { - "@types/node": "^24.13.3", - "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.7", - "@vitejs/plugin-react": "^6.1.1", - "oxlint": "^1.81.0", - "typescript": "~6.0.2", - "vite": "^8.3.0", - "vitest": "^3.2.7" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", - "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", - "license": "MIT" - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@base-org/account": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@base-org/account/-/account-2.4.0.tgz", - "integrity": "sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==", - "license": "Apache-2.0", - "dependencies": { - "@coinbase/cdp-sdk": "^1.0.0", - "@noble/hashes": "1.4.0", - "clsx": "1.2.1", - "eventemitter3": "5.0.1", - "idb-keyval": "6.2.1", - "ox": "0.6.9", - "preact": "10.24.2", - "viem": "^2.31.7", - "zustand": "5.0.3" - } - }, - "node_modules/@base-org/account/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@base-org/account/node_modules/ox": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@base-org/account/node_modules/ox/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@coinbase/cdp-sdk": { - "version": "1.56.0", - "resolved": "https://registry.npmjs.org/@coinbase/cdp-sdk/-/cdp-sdk-1.56.0.tgz", - "integrity": "sha512-Fwq77OUHRfSihdi/IB3sp2eVplv9UQjiXoZfpU0mYmxD42CRbVINQT9PVrBbn6fxqS9Vlc4XdaB166IPBVfXkA==", - "license": "MIT", - "dependencies": { - "@solana-program/system": "^0.10.0", - "@solana-program/token": "^0.9.0", - "@solana/kit": "^5.5.1", - "abitype": "1.0.6", - "axios": "^1.18.0", - "axios-retry": "^4.5.0", - "bs58": "^6.0.0", - "jose": "^6.2.0", - "md5": "^2.3.0", - "uncrypto": "^0.1.3", - "viem": "^2.47.0", - "zod": "^3.25.76" - }, - "peerDependencies": { - "@x402/core": "^2.25.0", - "@x402/evm": "^2.25.0", - "@x402/extensions": "^2.25.0", - "@x402/svm": "^2.25.0" - }, - "peerDependenciesMeta": { - "@x402/core": { - "optional": true - }, - "@x402/evm": { - "optional": true - }, - "@x402/extensions": { - "optional": true - }, - "@x402/svm": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana-program/system": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.10.0.tgz", - "integrity": "sha512-Go+LOEZmqmNlfr+Gjy5ZWAdY5HbYzk2RBewD9QinEU/bBSzpFfzqDRT55JjFRBGJUvMgf3C2vfXEGT4i8DSI4g==", - "license": "Apache-2.0", - "peerDependencies": { - "@solana/kit": "^5.0" - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana-program/token": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.9.0.tgz", - "integrity": "sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==", - "license": "Apache-2.0", - "peerDependencies": { - "@solana/kit": "^5.0" - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/accounts": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-5.5.1.tgz", - "integrity": "sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/rpc-spec": "5.5.1", - "@solana/rpc-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/addresses": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-5.5.1.tgz", - "integrity": "sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==", - "license": "MIT", - "dependencies": { - "@solana/assertions": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/nominal-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/assertions": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-5.5.1.tgz", - "integrity": "sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/codecs": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-5.5.1.tgz", - "integrity": "sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/codecs-data-structures": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/options": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/codecs-core": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-5.5.1.tgz", - "integrity": "sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/codecs-data-structures": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-5.5.1.tgz", - "integrity": "sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/codecs-numbers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-5.5.1.tgz", - "integrity": "sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/codecs-strings": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-5.5.1.tgz", - "integrity": "sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "fastestsmallesttextencoderdecoder": "^1.0.22", - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "fastestsmallesttextencoderdecoder": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/errors": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-5.5.1.tgz", - "integrity": "sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==", - "license": "MIT", - "dependencies": { - "chalk": "5.6.2", - "commander": "14.0.2" - }, - "bin": { - "errors": "bin/cli.mjs" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/fast-stable-stringify": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-5.5.1.tgz", - "integrity": "sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/functional": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-5.5.1.tgz", - "integrity": "sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/instruction-plans": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-5.5.1.tgz", - "integrity": "sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/instructions": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/promises": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/instructions": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-5.5.1.tgz", - "integrity": "sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/keys": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-5.5.1.tgz", - "integrity": "sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg==", - "license": "MIT", - "dependencies": { - "@solana/assertions": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/nominal-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/kit": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-5.5.1.tgz", - "integrity": "sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ==", - "license": "MIT", - "dependencies": { - "@solana/accounts": "5.5.1", - "@solana/addresses": "5.5.1", - "@solana/codecs": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/instruction-plans": "5.5.1", - "@solana/instructions": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/offchain-messages": "5.5.1", - "@solana/plugin-core": "5.5.1", - "@solana/programs": "5.5.1", - "@solana/rpc": "5.5.1", - "@solana/rpc-api": "5.5.1", - "@solana/rpc-parsed-types": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "@solana/rpc-subscriptions": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/signers": "5.5.1", - "@solana/sysvars": "5.5.1", - "@solana/transaction-confirmation": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/nominal-types": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-5.5.1.tgz", - "integrity": "sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/offchain-messages": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/offchain-messages/-/offchain-messages-5.5.1.tgz", - "integrity": "sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-data-structures": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/nominal-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/options": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/options/-/options-5.5.1.tgz", - "integrity": "sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==", - "license": "MIT", - "dependencies": { - "@solana/codecs-core": "5.5.1", - "@solana/codecs-data-structures": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/plugin-core": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/plugin-core/-/plugin-core-5.5.1.tgz", - "integrity": "sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/programs": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-5.5.1.tgz", - "integrity": "sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/promises": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-5.5.1.tgz", - "integrity": "sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-5.5.1.tgz", - "integrity": "sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/fast-stable-stringify": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/rpc-api": "5.5.1", - "@solana/rpc-spec": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "@solana/rpc-transformers": "5.5.1", - "@solana/rpc-transport-http": "5.5.1", - "@solana/rpc-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-api": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-5.5.1.tgz", - "integrity": "sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/rpc-parsed-types": "5.5.1", - "@solana/rpc-spec": "5.5.1", - "@solana/rpc-transformers": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-parsed-types": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-5.5.1.tgz", - "integrity": "sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-spec": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-5.5.1.tgz", - "integrity": "sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/rpc-spec-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-spec-types": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-5.5.1.tgz", - "integrity": "sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==", - "license": "MIT", - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-subscriptions": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-5.5.1.tgz", - "integrity": "sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/fast-stable-stringify": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/promises": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "@solana/rpc-subscriptions-api": "5.5.1", - "@solana/rpc-subscriptions-channel-websocket": "5.5.1", - "@solana/rpc-subscriptions-spec": "5.5.1", - "@solana/rpc-transformers": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/subscribable": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-subscriptions-api": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-5.5.1.tgz", - "integrity": "sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/rpc-subscriptions-spec": "5.5.1", - "@solana/rpc-transformers": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-subscriptions-channel-websocket": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-5.5.1.tgz", - "integrity": "sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/rpc-subscriptions-spec": "5.5.1", - "@solana/subscribable": "5.5.1", - "ws": "^8.19.0" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-subscriptions-spec": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-5.5.1.tgz", - "integrity": "sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/promises": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "@solana/subscribable": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-transformers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-5.5.1.tgz", - "integrity": "sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/nominal-types": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "@solana/rpc-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-transport-http": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-5.5.1.tgz", - "integrity": "sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1", - "@solana/rpc-spec": "5.5.1", - "@solana/rpc-spec-types": "5.5.1", - "undici-types": "^7.19.2" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/rpc-types": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-5.5.1.tgz", - "integrity": "sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/nominal-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/signers": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-5.5.1.tgz", - "integrity": "sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/instructions": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/nominal-types": "5.5.1", - "@solana/offchain-messages": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/subscribable": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-5.5.1.tgz", - "integrity": "sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ==", - "license": "MIT", - "dependencies": { - "@solana/errors": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/sysvars": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-5.5.1.tgz", - "integrity": "sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==", - "license": "MIT", - "dependencies": { - "@solana/accounts": "5.5.1", - "@solana/codecs": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/rpc-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/transaction-confirmation": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-5.5.1.tgz", - "integrity": "sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/promises": "5.5.1", - "@solana/rpc": "5.5.1", - "@solana/rpc-subscriptions": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/transaction-messages": "5.5.1", - "@solana/transactions": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/transaction-messages": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-5.5.1.tgz", - "integrity": "sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-data-structures": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/instructions": "5.5.1", - "@solana/nominal-types": "5.5.1", - "@solana/rpc-types": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/@solana/transactions": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-5.5.1.tgz", - "integrity": "sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA==", - "license": "MIT", - "dependencies": { - "@solana/addresses": "5.5.1", - "@solana/codecs-core": "5.5.1", - "@solana/codecs-data-structures": "5.5.1", - "@solana/codecs-numbers": "5.5.1", - "@solana/codecs-strings": "5.5.1", - "@solana/errors": "5.5.1", - "@solana/functional": "5.5.1", - "@solana/instructions": "5.5.1", - "@solana/keys": "5.5.1", - "@solana/nominal-types": "5.5.1", - "@solana/rpc-types": "5.5.1", - "@solana/transaction-messages": "5.5.1" - }, - "engines": { - "node": ">=20.18.0" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/abitype": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz", - "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/@coinbase/cdp-sdk/node_modules/undici-types": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.29.1.tgz", - "integrity": "sha512-2xO3p6gANwOmhSFwNy2MMYISbHTtM+K3bY0bqpD1gOGpUPIe+yFXCobxbz0s2jm7E0faMxIFcZUcCKa+N6Ozlg==", - "license": "MIT" - }, - "node_modules/@coinbase/wallet-sdk": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-4.3.6.tgz", - "integrity": "sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "1.4.0", - "clsx": "1.2.1", - "eventemitter3": "5.0.1", - "idb-keyval": "6.2.1", - "ox": "0.6.9", - "preact": "10.24.2", - "viem": "^2.27.2", - "zustand": "5.0.3" - } - }, - "node_modules/@coinbase/wallet-sdk/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@coinbase/wallet-sdk/node_modules/ox": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", - "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@coinbase/wallet-sdk/node_modules/ox/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@ecies/ciphers": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.6.tgz", - "integrity": "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==", - "license": "MIT", - "engines": { - "bun": ">=1", - "deno": ">=2.7.10", - "node": ">=16" - }, - "peerDependencies": { - "@noble/ciphers": "^1.0.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", - "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", - "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", - "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", - "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", - "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", - "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", - "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", - "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", - "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", - "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", - "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", - "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", - "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", - "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", - "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", - "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", - "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", - "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", - "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", - "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", - "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", - "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", - "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", - "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", - "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", - "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@ethereumjs/common": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.2.0.tgz", - "integrity": "sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==", - "license": "MIT", - "dependencies": { - "@ethereumjs/util": "^8.1.0", - "crc-32": "^1.2.0" - } - }, - "node_modules/@ethereumjs/rlp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", - "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/tx": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-4.2.0.tgz", - "integrity": "sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==", - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/common": "^3.2.0", - "@ethereumjs/rlp": "^4.0.1", - "@ethereumjs/util": "^8.1.0", - "ethereum-cryptography": "^2.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", - "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/rlp": "^4.0.1", - "ethereum-cryptography": "^2.0.0", - "micro-ftch": "^0.3.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@gemini-wallet/core": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@gemini-wallet/core/-/core-0.3.2.tgz", - "integrity": "sha512-Z4aHi3ECFf5oWYWM3F1rW83GJfB9OvhBYPTmb5q+VyK3uvzvS48lwo+jwh2eOoCRWEuT/crpb9Vwp2QaS5JqgQ==", - "license": "MIT", - "dependencies": { - "@metamask/rpc-errors": "7.0.2", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "viem": ">=2.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", - "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.6.0.tgz", - "integrity": "sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@lit/reactive-element": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.2.tgz", - "integrity": "sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.5.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-json-rpc-provider/-/eth-json-rpc-provider-1.0.1.tgz", - "integrity": "sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==", - "dependencies": { - "@metamask/json-rpc-engine": "^7.0.0", - "@metamask/safe-event-emitter": "^3.0.0", - "@metamask/utils": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.3.tgz", - "integrity": "sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==", - "license": "ISC", - "dependencies": { - "@metamask/rpc-errors": "^6.2.1", - "@metamask/safe-event-emitter": "^3.0.0", - "@metamask/utils": "^8.3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/json-rpc-engine/node_modules/@metamask/utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.0.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/rpc-errors": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", - "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", - "license": "MIT", - "dependencies": { - "@metamask/utils": "^9.0.0", - "fast-safe-stringify": "^2.0.6" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/@metamask/utils": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", - "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.1.2", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "semver": "^7.3.8", - "superstruct": "^1.0.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@metamask/eth-json-rpc-provider/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@metamask/json-rpc-engine": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-engine/-/json-rpc-engine-8.0.2.tgz", - "integrity": "sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==", - "license": "ISC", - "dependencies": { - "@metamask/rpc-errors": "^6.2.1", - "@metamask/safe-event-emitter": "^3.0.0", - "@metamask/utils": "^8.3.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-engine/node_modules/@metamask/rpc-errors": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", - "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", - "license": "MIT", - "dependencies": { - "@metamask/utils": "^9.0.0", - "fast-safe-stringify": "^2.0.6" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-engine/node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-engine/node_modules/@metamask/utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.0.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-engine/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@metamask/json-rpc-middleware-stream": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@metamask/json-rpc-middleware-stream/-/json-rpc-middleware-stream-7.0.2.tgz", - "integrity": "sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==", - "license": "ISC", - "dependencies": { - "@metamask/json-rpc-engine": "^8.0.2", - "@metamask/safe-event-emitter": "^3.0.0", - "@metamask/utils": "^8.3.0", - "readable-stream": "^3.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-middleware-stream/node_modules/@metamask/utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.0.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/json-rpc-middleware-stream/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@metamask/object-multiplex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz", - "integrity": "sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==", - "license": "ISC", - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.2" - }, - "engines": { - "node": "^16.20 || ^18.16 || >=20" - } - }, - "node_modules/@metamask/onboarding": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@metamask/onboarding/-/onboarding-1.0.1.tgz", - "integrity": "sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==", - "license": "MIT", - "dependencies": { - "bowser": "^2.9.0" - } - }, - "node_modules/@metamask/providers": { - "version": "16.1.0", - "resolved": "https://registry.npmjs.org/@metamask/providers/-/providers-16.1.0.tgz", - "integrity": "sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==", - "license": "MIT", - "dependencies": { - "@metamask/json-rpc-engine": "^8.0.1", - "@metamask/json-rpc-middleware-stream": "^7.0.1", - "@metamask/object-multiplex": "^2.0.0", - "@metamask/rpc-errors": "^6.2.1", - "@metamask/safe-event-emitter": "^3.1.1", - "@metamask/utils": "^8.3.0", - "detect-browser": "^5.2.0", - "extension-port-stream": "^3.0.0", - "fast-deep-equal": "^3.1.3", - "is-stream": "^2.0.0", - "readable-stream": "^3.6.2", - "webextension-polyfill": "^0.10.0" - }, - "engines": { - "node": "^18.18 || >=20" - } - }, - "node_modules/@metamask/providers/node_modules/@metamask/rpc-errors": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz", - "integrity": "sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==", - "license": "MIT", - "dependencies": { - "@metamask/utils": "^9.0.0", - "fast-safe-stringify": "^2.0.6" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/providers/node_modules/@metamask/rpc-errors/node_modules/@metamask/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/providers/node_modules/@metamask/utils": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-8.5.0.tgz", - "integrity": "sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/superstruct": "^3.0.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/providers/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@metamask/rpc-errors": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@metamask/rpc-errors/-/rpc-errors-7.0.2.tgz", - "integrity": "sha512-YYYHsVYd46XwY2QZzpGeU4PSdRhHdxnzkB8piWGvJW2xbikZ3R+epAYEL4q/K8bh9JPTucsUdwRFnACor1aOYw==", - "license": "MIT", - "dependencies": { - "@metamask/utils": "^11.0.1", - "fast-safe-stringify": "^2.0.6" - }, - "engines": { - "node": "^18.20 || ^20.17 || >=22" - } - }, - "node_modules/@metamask/safe-event-emitter": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.3.tgz", - "integrity": "sha512-Pnl74ukgoOkSItBRmZ9nnhdBbRtBI1ZvpeYjKNgxjVzDWa/AtruKZc+7LjfZ0iO8iYqh7Ts3bPs2Gu7M2hSf7g==", - "license": "ISC", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@metamask/scure-bip39": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@metamask/scure-bip39/-/scure-bip39-2.1.1.tgz", - "integrity": "sha512-1K8aBsAqr6+8jWhguVl06n8e+zjV9sUnys+5PLyVU4mb8LbulQ60F6cq7iQys3xX/yCwKt1+7c7j2nuTEpW+ZQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.3.2", - "@scure/base": "~1.1.3" - }, - "engines": { - "node": "^16.20 || ^18.16 || >=20" - } - }, - "node_modules/@metamask/scure-bip39/node_modules/@noble/hashes": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", - "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@metamask/scure-bip39/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@metamask/sdk": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@metamask/sdk/-/sdk-0.33.1.tgz", - "integrity": "sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==", - "deprecated": "No longer maintained, superseded by https://docs.metamask.io/metamask-connect", - "dependencies": { - "@babel/runtime": "^7.26.0", - "@metamask/onboarding": "^1.0.1", - "@metamask/providers": "16.1.0", - "@metamask/sdk-analytics": "0.0.5", - "@metamask/sdk-communication-layer": "0.33.1", - "@metamask/sdk-install-modal-web": "0.32.1", - "@paulmillr/qr": "^0.2.1", - "bowser": "^2.9.0", - "cross-fetch": "^4.0.0", - "debug": "4.3.4", - "eciesjs": "^0.4.11", - "eth-rpc-errors": "^4.0.3", - "eventemitter2": "^6.4.9", - "obj-multiplex": "^1.0.0", - "pump": "^3.0.0", - "readable-stream": "^3.6.2", - "socket.io-client": "^4.5.1", - "tslib": "^2.6.0", - "util": "^0.12.4", - "uuid": "^8.3.2" - } - }, - "node_modules/@metamask/sdk-analytics": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@metamask/sdk-analytics/-/sdk-analytics-0.0.5.tgz", - "integrity": "sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==", - "deprecated": "No longer maintained, superseded by @metamask/connect-analytics", - "license": "MIT", - "dependencies": { - "openapi-fetch": "^0.13.5" - } - }, - "node_modules/@metamask/sdk-communication-layer": { - "version": "0.33.1", - "resolved": "https://registry.npmjs.org/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.33.1.tgz", - "integrity": "sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==", - "deprecated": "No longer maintained, superseded by https://docs.metamask.io/metamask-connect", - "dependencies": { - "@metamask/sdk-analytics": "0.0.5", - "bufferutil": "^4.0.8", - "date-fns": "^2.29.3", - "debug": "4.3.4", - "utf-8-validate": "^5.0.2", - "uuid": "^8.3.2" - }, - "peerDependencies": { - "cross-fetch": "^4.0.0", - "eciesjs": "*", - "eventemitter2": "^6.4.9", - "readable-stream": "^3.6.2", - "socket.io-client": "^4.5.1" - } - }, - "node_modules/@metamask/sdk-install-modal-web": { - "version": "0.32.1", - "resolved": "https://registry.npmjs.org/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.32.1.tgz", - "integrity": "sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==", - "deprecated": "No longer maintained, superseded by https://docs.metamask.io/metamask-connect", - "dependencies": { - "@paulmillr/qr": "^0.2.1" - } - }, - "node_modules/@metamask/superstruct": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/@metamask/superstruct/-/superstruct-3.4.1.tgz", - "integrity": "sha512-caTaaBUcwBGbUNf3r0uT48upX4nECRbKhQ9pPOfW4sIkfcIUUDV4S9DZxq/5fuNPVt5KWpyd5xIIz0sP+iWLlg==", - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@metamask/utils": { - "version": "11.12.1", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-11.12.1.tgz", - "integrity": "sha512-X97J5AEcaKDTIAfKb4X93ZTLfvOahzDVadlveQW+7OZ7yhXjMxXoFmhX2d9UKv48iS2Dxq9kbGJ1lUfphu9ebQ==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.2.0", - "@metamask/scure-bip39": "^2.0.3", - "@metamask/superstruct": "^3.1.0", - "@noble/hashes": "^1.3.1", - "@scure/base": "^1.1.3", - "@types/debug": "^4.1.7", - "@types/lodash": "^4.17.20", - "debug": "^4.3.4", - "lodash": "^4.17.21", - "pony-cause": "^2.1.10", - "semver": "^7.5.4", - "uuid": "^9.0.1" - }, - "engines": { - "node": "^18.18 || ^20.14 || >=22" - } - }, - "node_modules/@metamask/utils/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@napi-rs/lzma-linux-x64-gnu": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", - "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^22.20 || ^24.12 || >=25" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.149.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.149.0.tgz", - "integrity": "sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/oxc-project" - } - }, - "node_modules/@oxlint/binding-android-arm-eabi": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.83.0.tgz", - "integrity": "sha512-0yGY24EwsLk5YDe6F+VkmZyRHSwJDALa3nIrPpq7FXmp2lV2d0TzvBCGeZk+wgiULRGr5blhyr4QMp5KCXJUqA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-android-arm64": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.83.0.tgz", - "integrity": "sha512-hHfJ0vc17A4iUjH5p9BsTUPYbYRNxGpvD2lbu1aBRk54bzNIx9o5TtYF39QPZcV95DagZd+4DEAw2RH3G2ZsMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-darwin-arm64": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.83.0.tgz", - "integrity": "sha512-hsOjYjszLb/3zym/TkzUMPAoQlTJcuzSyEPOAyA+skXJIX9M0o+4JfOtqopX/Vf4hSLrJ98j0nvFo23gzk8auQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-darwin-x64": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.83.0.tgz", - "integrity": "sha512-mjh5oH2EA+wl5yRJYT9K9G61O2zFlpuv+yf2JwZOi0+dq2FnTUtm1h8i+5Ik0fXPWIu/k84I1psZR9aQsLAnyA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-freebsd-x64": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.83.0.tgz", - "integrity": "sha512-fNHr64/YaO8YssuoDVC8+F4Uk5enR86q5uxfHkQrjAPs1dbAILOrD2uaud+J7MO8Fx774g44ERLD0IGIvZE48w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm-gnueabihf": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.83.0.tgz", - "integrity": "sha512-Qpwy3zzAwMj+8/lyYItHmkSMwbkprFNWTK7jPYDOxSyxEhaSLOWYUTCMkjF334J8/WD0nznCCsoBbIH6hpsuIw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm-musleabihf": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.83.0.tgz", - "integrity": "sha512-s+BirYLFq7JL2k9sP0XI3ZXJ9dYvJ8sX3jLCLoag7tt+zrSHpZxP0jqznfL+Gdgwu7ay0dYgGYJXrQvq3iWloA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm64-gnu": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.83.0.tgz", - "integrity": "sha512-7lihXt3vKr+GIyapNbHrnFHm/biiW30le6Zv/DExbAFPF6YwCQXVFlONPFehxs0CpGO4CBfYPM9rdDT+XMoIlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-arm64-musl": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.83.0.tgz", - "integrity": "sha512-q63JalLYVkZiZvls1z3PPUnpmQluOMXp0khqQMznCeAPLGydfNY8JhvuA4WlK57JfrvikU8wB5lPVveqpIXvew==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-ppc64-gnu": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.83.0.tgz", - "integrity": "sha512-krQmDF+dRbxvdqVPV88ZuOoPPu8X5BuqDA8Hd+qcS4YMRQCb+nexA57DazgGsc/rGdKBe3QmV0mnv0bdpW/p5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-riscv64-gnu": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.83.0.tgz", - "integrity": "sha512-MmOl8Y6txEAXZU1RG8Rr264jQ6D7VPmqFsU/45x/FeWsGe32hklTqGrLE6UxHzp5Rjt0wP+20tY8YXKgSFB3mw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-riscv64-musl": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.83.0.tgz", - "integrity": "sha512-u1rMymh0W3JZkq370kzQsYPULGWqhE09pZRqnZvUSoYaI9pVO5yVX+iYIslmWuEgwuzH9YAaOsScJiobWCHoOw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-s390x-gnu": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.83.0.tgz", - "integrity": "sha512-y0zK3HNwGysu7rqtE+BQG/d0bx5gh/KwlOtghN8oWeK1KcWzeaLqtZrbm8owqdma1lFyrce/hTO5ismuNu+INQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-x64-gnu": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.83.0.tgz", - "integrity": "sha512-rS5gM0NgD7ngmuJmbIehsidtrOwKkLFwCQbKEeb9KuyQrrWNq5Zkn0uV6AYdXOMJ0grrWEiLwBuvMxt8w5vsNw==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-linux-x64-musl": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.83.0.tgz", - "integrity": "sha512-W2IH4EtpcPaWcvNGCA95YoDg4vxqE/ZiPCi3arrxEEpsK7+JQN9WYwrlYFx9pcdP6KPXqRqkv3zdQPHcx7b6YQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-openharmony-arm64": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.83.0.tgz", - "integrity": "sha512-6LyKkUyoajssTPLlZmDbZIbu4IZ5B4bGuRUnBgCGpEvHP3FQMaYITncHA/unPUo7q+Z+pIu2HhdkQ+8d1SG7iA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-arm64-msvc": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.83.0.tgz", - "integrity": "sha512-Uz/fObEtF0jmNJQJ8CGRBKfefYstS0/wjD3s6IGzP8nUwsJykHQJBiN3npHwKiGRGn/vvBEgNr4B3cCzmmatvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-ia32-msvc": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.83.0.tgz", - "integrity": "sha512-u7XcvPW6Bk58tY5iWs2ESb0vJjoE/kuSpHxopbwp/p3ZtWVQXZ6wor5w3ssVTHOqd/v8b+QdhSFWQ4grEUNWpA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxlint/binding-win32-x64-msvc": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.83.0.tgz", - "integrity": "sha512-LZRubd7ph13QmAg4fFecTYVZkiYbROR2Htaxh/ufWRkDhPOm2wrwaEYR89e0YpPFD3dqBrPoxS7myBw5hmYA7Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@paulmillr/qr": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@paulmillr/qr/-/qr-0.2.1.tgz", - "integrity": "sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==", - "deprecated": "Switch to \"qr\" (new package name) for security updates: npm install qr", - "license": "(MIT OR Apache-2.0)", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.7.8.tgz", - "integrity": "sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-controllers": "1.7.8", - "@reown/appkit-pay": "1.7.8", - "@reown/appkit-polyfills": "1.7.8", - "@reown/appkit-scaffold-ui": "1.7.8", - "@reown/appkit-ui": "1.7.8", - "@reown/appkit-utils": "1.7.8", - "@reown/appkit-wallet": "1.7.8", - "@walletconnect/types": "2.21.0", - "@walletconnect/universal-provider": "2.21.0", - "bs58": "6.0.0", - "valtio": "1.13.2", - "viem": ">=2.29.0" - } - }, - "node_modules/@reown/appkit-common": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.7.8.tgz", - "integrity": "sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==", - "license": "Apache-2.0", - "dependencies": { - "big.js": "6.2.2", - "dayjs": "1.11.13", - "viem": ">=2.29.0" - } - }, - "node_modules/@reown/appkit-controllers": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.7.8.tgz", - "integrity": "sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-wallet": "1.7.8", - "@walletconnect/universal-provider": "2.21.0", - "valtio": "1.13.2", - "viem": ">=2.29.0" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@noble/ciphers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", - "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@noble/curves": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.1" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@scure/bip32": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@scure/bip39": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/core": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", - "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.16", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "es-toolkit": "1.33.0", - "events": "3.3.0", - "uint8arrays": "3.1.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/sign-client": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", - "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/core": "2.21.0", - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "2.1.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/types": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", - "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/universal-provider": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", - "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/jsonrpc-http-connection": "1.0.8", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/sign-client": "2.21.0", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "es-toolkit": "1.33.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", - "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", - "license": "Apache-2.0", - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "@walletconnect/window-metadata": "1.0.1", - "bs58": "6.0.0", - "detect-browser": "5.3.0", - "query-string": "7.1.3", - "uint8arrays": "3.1.0", - "viem": "2.23.2" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/@walletconnect/utils/node_modules/viem": { - "version": "2.23.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", - "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.7", - "ws": "8.18.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-controllers/node_modules/abitype": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-controllers/node_modules/isows": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/@reown/appkit-controllers/node_modules/ox": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", - "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-controllers/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-pay": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.7.8.tgz", - "integrity": "sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-controllers": "1.7.8", - "@reown/appkit-ui": "1.7.8", - "@reown/appkit-utils": "1.7.8", - "lit": "3.3.0", - "valtio": "1.13.2" - } - }, - "node_modules/@reown/appkit-polyfills": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.7.8.tgz", - "integrity": "sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==", - "license": "Apache-2.0", - "dependencies": { - "buffer": "6.0.3" - } - }, - "node_modules/@reown/appkit-scaffold-ui": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.7.8.tgz", - "integrity": "sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-controllers": "1.7.8", - "@reown/appkit-ui": "1.7.8", - "@reown/appkit-utils": "1.7.8", - "@reown/appkit-wallet": "1.7.8", - "lit": "3.3.0" - } - }, - "node_modules/@reown/appkit-ui": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.7.8.tgz", - "integrity": "sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-controllers": "1.7.8", - "@reown/appkit-wallet": "1.7.8", - "lit": "3.3.0", - "qrcode": "1.5.3" - } - }, - "node_modules/@reown/appkit-utils": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.7.8.tgz", - "integrity": "sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-controllers": "1.7.8", - "@reown/appkit-polyfills": "1.7.8", - "@reown/appkit-wallet": "1.7.8", - "@walletconnect/logger": "2.1.2", - "@walletconnect/universal-provider": "2.21.0", - "valtio": "1.13.2", - "viem": ">=2.29.0" - }, - "peerDependencies": { - "valtio": "1.13.2" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@noble/ciphers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", - "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@noble/curves": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.1" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@scure/bip32": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@scure/bip39": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/core": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", - "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.16", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "es-toolkit": "1.33.0", - "events": "3.3.0", - "uint8arrays": "3.1.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/sign-client": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", - "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/core": "2.21.0", - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "2.1.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/types": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", - "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/universal-provider": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", - "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/jsonrpc-http-connection": "1.0.8", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/sign-client": "2.21.0", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "es-toolkit": "1.33.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", - "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", - "license": "Apache-2.0", - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "@walletconnect/window-metadata": "1.0.1", - "bs58": "6.0.0", - "detect-browser": "5.3.0", - "query-string": "7.1.3", - "uint8arrays": "3.1.0", - "viem": "2.23.2" - } - }, - "node_modules/@reown/appkit-utils/node_modules/@walletconnect/utils/node_modules/viem": { - "version": "2.23.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", - "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.7", - "ws": "8.18.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-utils/node_modules/abitype": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-utils/node_modules/isows": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/@reown/appkit-utils/node_modules/ox": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", - "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-utils/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@reown/appkit-wallet": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.7.8.tgz", - "integrity": "sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit-common": "1.7.8", - "@reown/appkit-polyfills": "1.7.8", - "@walletconnect/logger": "2.1.2", - "zod": "3.22.4" - } - }, - "node_modules/@reown/appkit-wallet/node_modules/zod": { - "version": "3.22.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", - "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@reown/appkit/node_modules/@noble/ciphers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", - "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit/node_modules/@noble/curves": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.1" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit/node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit/node_modules/@scure/bip32": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit/node_modules/@scure/bip39": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/core": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.0.tgz", - "integrity": "sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.16", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "es-toolkit": "1.33.0", - "events": "3.3.0", - "uint8arrays": "3.1.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/sign-client": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.0.tgz", - "integrity": "sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/core": "2.21.0", - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "2.1.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/types": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.0.tgz", - "integrity": "sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/universal-provider": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.0.tgz", - "integrity": "sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/jsonrpc-http-connection": "1.0.8", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/sign-client": "2.21.0", - "@walletconnect/types": "2.21.0", - "@walletconnect/utils": "2.21.0", - "es-toolkit": "1.33.0", - "events": "3.3.0" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/utils": { - "version": "2.21.0", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.0.tgz", - "integrity": "sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==", - "license": "Apache-2.0", - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.0", - "@walletconnect/window-getters": "1.0.1", - "@walletconnect/window-metadata": "1.0.1", - "bs58": "6.0.0", - "detect-browser": "5.3.0", - "query-string": "7.1.3", - "uint8arrays": "3.1.0", - "viem": "2.23.2" - } - }, - "node_modules/@reown/appkit/node_modules/@walletconnect/utils/node_modules/viem": { - "version": "2.23.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", - "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.7", - "ws": "8.18.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit/node_modules/abitype": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/@reown/appkit/node_modules/isows": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/@reown/appkit/node_modules/ox": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", - "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@reown/appkit/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@rolldown/binding-android-arm-eabi": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.8.tgz", - "integrity": "sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.8.tgz", - "integrity": "sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.8.tgz", - "integrity": "sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.8.tgz", - "integrity": "sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.8.tgz", - "integrity": "sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.8.tgz", - "integrity": "sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.8.tgz", - "integrity": "sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.8.tgz", - "integrity": "sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.8.tgz", - "integrity": "sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.8.tgz", - "integrity": "sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.8.tgz", - "integrity": "sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.8.tgz", - "integrity": "sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.8.tgz", - "integrity": "sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.8.tgz", - "integrity": "sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.8.tgz", - "integrity": "sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.3.tgz", - "integrity": "sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.3.tgz", - "integrity": "sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.3.tgz", - "integrity": "sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.3.tgz", - "integrity": "sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.3.tgz", - "integrity": "sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.3.tgz", - "integrity": "sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.3.tgz", - "integrity": "sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.3.tgz", - "integrity": "sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==", - "cpu": [ - "arm" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.3.tgz", - "integrity": "sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.3.tgz", - "integrity": "sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.3.tgz", - "integrity": "sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.3.tgz", - "integrity": "sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.3.tgz", - "integrity": "sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.3.tgz", - "integrity": "sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.3.tgz", - "integrity": "sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.3.tgz", - "integrity": "sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.3.tgz", - "integrity": "sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.3.tgz", - "integrity": "sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.3.tgz", - "integrity": "sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.3.tgz", - "integrity": "sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.3.tgz", - "integrity": "sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.3.tgz", - "integrity": "sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.3.tgz", - "integrity": "sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.3.tgz", - "integrity": "sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.3.tgz", - "integrity": "sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@safe-global/safe-apps-provider": { - "version": "0.18.6", - "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.6.tgz", - "integrity": "sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==", - "license": "MIT", - "dependencies": { - "@safe-global/safe-apps-sdk": "^9.1.0", - "events": "^3.3.0" - } - }, - "node_modules/@safe-global/safe-apps-sdk": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", - "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", - "license": "MIT", - "dependencies": { - "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", - "viem": "^2.1.1" - } - }, - "node_modules/@safe-global/safe-gateway-typescript-sdk": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.23.1.tgz", - "integrity": "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" - }, - "node_modules/@tanstack/query-core": { - "version": "5.102.8", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.8.tgz", - "integrity": "sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-query": { - "version": "5.102.8", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.8.tgz", - "integrity": "sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==", - "license": "MIT", - "dependencies": { - "@tanstack/query-core": "5.102.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^18 || ^19" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", - "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "24.13.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.4.tgz", - "integrity": "sha512-YJ7EqCstVTzIr0fMr7qul/977en+pQHrfmuKIo6Zr9i75Be21dr3MovcfvGtyvi2HAUrRerWps5sMO9I7WaxDw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@types/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", - "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", - "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.3.0" - } - }, - "node_modules/@types/trusted-types": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", - "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", - "license": "MIT" - }, - "node_modules/@vitejs/plugin-react": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz", - "integrity": "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "oxc-transform-react": "^0.145.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "oxc-transform-react": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz", - "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.7", - "@vitest/utils": "3.2.7", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz", - "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz", - "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "3.2.7", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz", - "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.7", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz", - "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^4.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz", - "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "3.2.7", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@wagmi/connectors": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@wagmi/connectors/-/connectors-6.2.0.tgz", - "integrity": "sha512-2NfkbqhNWdjfibb4abRMrn7u6rPjEGolMfApXss6HCDVt9AW2oVC6k8Q5FouzpJezElxLJSagWz9FW1zaRlanA==", - "license": "MIT", - "dependencies": { - "@base-org/account": "2.4.0", - "@coinbase/wallet-sdk": "4.3.6", - "@gemini-wallet/core": "0.3.2", - "@metamask/sdk": "0.33.1", - "@safe-global/safe-apps-provider": "0.18.6", - "@safe-global/safe-apps-sdk": "9.1.0", - "@walletconnect/ethereum-provider": "2.21.1", - "cbw-sdk": "npm:@coinbase/wallet-sdk@3.9.3", - "porto": "0.2.35" - }, - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "@wagmi/core": "2.22.1", - "typescript": ">=5.0.4", - "viem": "2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@wagmi/core": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/@wagmi/core/-/core-2.22.1.tgz", - "integrity": "sha512-cG/xwQWsBEcKgRTkQVhH29cbpbs/TdcUJVFXCyri3ZknxhMyGv0YEjTcrNpRgt2SaswL1KrvslSNYKKo+5YEAg==", - "license": "MIT", - "dependencies": { - "eventemitter3": "5.0.1", - "mipd": "0.0.7", - "zustand": "5.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "@tanstack/query-core": ">=5.0.0", - "typescript": ">=5.0.4", - "viem": "2.x" - }, - "peerDependenciesMeta": { - "@tanstack/query-core": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/@wagmi/core/node_modules/zustand": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.0.tgz", - "integrity": "sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - }, - "node_modules/@walletconnect/core": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.21.1.tgz", - "integrity": "sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/jsonrpc-ws-connection": "1.0.16", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.1", - "@walletconnect/utils": "2.21.1", - "@walletconnect/window-getters": "1.0.1", - "es-toolkit": "1.33.0", - "events": "3.3.0", - "uint8arrays": "3.1.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@walletconnect/environment": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", - "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", - "license": "MIT", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/environment/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/ethereum-provider": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/ethereum-provider/-/ethereum-provider-2.21.1.tgz", - "integrity": "sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@reown/appkit": "1.7.8", - "@walletconnect/jsonrpc-http-connection": "1.0.8", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/sign-client": "2.21.1", - "@walletconnect/types": "2.21.1", - "@walletconnect/universal-provider": "2.21.1", - "@walletconnect/utils": "2.21.1", - "events": "3.3.0" - } - }, - "node_modules/@walletconnect/events": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", - "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", - "license": "MIT", - "dependencies": { - "keyvaluestorage-interface": "^1.0.0", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/events/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/heartbeat": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz", - "integrity": "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==", - "license": "MIT", - "dependencies": { - "@walletconnect/events": "^1.0.1", - "@walletconnect/time": "^1.0.2", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/jsonrpc-http-connection": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", - "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", - "license": "MIT", - "dependencies": { - "@walletconnect/jsonrpc-utils": "^1.0.6", - "@walletconnect/safe-json": "^1.0.1", - "cross-fetch": "^3.1.4", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/jsonrpc-http-connection/node_modules/cross-fetch": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", - "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, - "node_modules/@walletconnect/jsonrpc-provider": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz", - "integrity": "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==", - "license": "MIT", - "dependencies": { - "@walletconnect/jsonrpc-utils": "^1.0.8", - "@walletconnect/safe-json": "^1.0.2", - "events": "^3.3.0" - } - }, - "node_modules/@walletconnect/jsonrpc-types": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz", - "integrity": "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==", - "license": "MIT", - "dependencies": { - "events": "^3.3.0", - "keyvaluestorage-interface": "^1.0.0" - } - }, - "node_modules/@walletconnect/jsonrpc-utils": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", - "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", - "license": "MIT", - "dependencies": { - "@walletconnect/environment": "^1.0.1", - "@walletconnect/jsonrpc-types": "^1.0.3", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/jsonrpc-utils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/jsonrpc-ws-connection": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", - "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", - "license": "MIT", - "dependencies": { - "@walletconnect/jsonrpc-utils": "^1.0.6", - "@walletconnect/safe-json": "^1.0.2", - "events": "^3.3.0", - "ws": "^7.5.1" - } - }, - "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { - "version": "7.5.13", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", - "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@walletconnect/keyvaluestorage": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", - "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", - "license": "MIT", - "dependencies": { - "@walletconnect/safe-json": "^1.0.1", - "idb-keyval": "^6.2.1", - "unstorage": "^1.9.0" - }, - "peerDependencies": { - "@react-native-async-storage/async-storage": "1.x" - }, - "peerDependenciesMeta": { - "@react-native-async-storage/async-storage": { - "optional": true - } - } - }, - "node_modules/@walletconnect/logger": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-2.1.2.tgz", - "integrity": "sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==", - "license": "MIT", - "dependencies": { - "@walletconnect/safe-json": "^1.0.2", - "pino": "7.11.0" - } - }, - "node_modules/@walletconnect/relay-api": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.11.tgz", - "integrity": "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==", - "license": "MIT", - "dependencies": { - "@walletconnect/jsonrpc-types": "^1.0.2" - } - }, - "node_modules/@walletconnect/relay-auth": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", - "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.0", - "@noble/hashes": "1.7.0", - "@walletconnect/safe-json": "^1.0.1", - "@walletconnect/time": "^1.0.2", - "uint8arrays": "^3.0.0" - } - }, - "node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", - "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", - "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/safe-json": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", - "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", - "license": "MIT", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/safe-json/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/sign-client": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.21.1.tgz", - "integrity": "sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/core": "2.21.1", - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/logger": "2.1.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.1", - "@walletconnect/utils": "2.21.1", - "events": "3.3.0" - } - }, - "node_modules/@walletconnect/time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", - "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", - "license": "MIT", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/time/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/types": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.21.1.tgz", - "integrity": "sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/heartbeat": "1.2.2", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "events": "3.3.0" - } - }, - "node_modules/@walletconnect/universal-provider": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.21.1.tgz", - "integrity": "sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==", - "deprecated": "Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases", - "license": "Apache-2.0", - "dependencies": { - "@walletconnect/events": "1.0.1", - "@walletconnect/jsonrpc-http-connection": "1.0.8", - "@walletconnect/jsonrpc-provider": "1.0.14", - "@walletconnect/jsonrpc-types": "1.0.4", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/logger": "2.1.2", - "@walletconnect/sign-client": "2.21.1", - "@walletconnect/types": "2.21.1", - "@walletconnect/utils": "2.21.1", - "es-toolkit": "1.33.0", - "events": "3.3.0" - } - }, - "node_modules/@walletconnect/utils": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.21.1.tgz", - "integrity": "sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==", - "license": "Apache-2.0", - "dependencies": { - "@noble/ciphers": "1.2.1", - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@walletconnect/jsonrpc-utils": "1.0.8", - "@walletconnect/keyvaluestorage": "1.1.1", - "@walletconnect/relay-api": "1.0.11", - "@walletconnect/relay-auth": "1.1.0", - "@walletconnect/safe-json": "1.0.2", - "@walletconnect/time": "1.0.2", - "@walletconnect/types": "2.21.1", - "@walletconnect/window-getters": "1.0.1", - "@walletconnect/window-metadata": "1.0.1", - "bs58": "6.0.0", - "detect-browser": "5.3.0", - "query-string": "7.1.3", - "uint8arrays": "3.1.0", - "viem": "2.23.2" - } - }, - "node_modules/@walletconnect/utils/node_modules/@noble/ciphers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.2.1.tgz", - "integrity": "sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/utils/node_modules/@noble/curves": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.1" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/utils/node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/utils/node_modules/@scure/bip32": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.2.tgz", - "integrity": "sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.8.1", - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/utils/node_modules/@scure/bip39": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.4.tgz", - "integrity": "sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.7.1", - "@scure/base": "~1.2.4" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@walletconnect/utils/node_modules/abitype": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.8.tgz", - "integrity": "sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3 >=3.22.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/@walletconnect/utils/node_modules/isows": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", - "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/@walletconnect/utils/node_modules/ox": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.7.tgz", - "integrity": "sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.10.1", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", - "@scure/bip32": "^1.5.0", - "@scure/bip39": "^1.4.0", - "abitype": "^1.0.6", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@walletconnect/utils/node_modules/viem": { - "version": "2.23.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.23.2.tgz", - "integrity": "sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.7", - "ws": "8.18.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@walletconnect/utils/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/@walletconnect/window-getters": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", - "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", - "license": "MIT", - "dependencies": { - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/window-getters/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@walletconnect/window-metadata": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", - "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", - "license": "MIT", - "dependencies": { - "@walletconnect/window-getters": "^1.0.1", - "tslib": "1.14.1" - } - }, - "node_modules/@walletconnect/window-metadata/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/abitype": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", - "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3.22.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/async-mutex": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.2.6.tgz", - "integrity": "sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", - "integrity": "sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.16.0", - "form-data": "^4.0.6", - "https-proxy-agent": "^5.0.1", - "proxy-from-env": "^2.1.0" - } - }, - "node_modules/axios-retry": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", - "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", - "license": "Apache-2.0", - "dependencies": { - "is-retry-allowed": "^2.2.0" - }, - "peerDependencies": { - "axios": "0.x || 1.x" - } - }, - "node_modules/base-x": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/big.js": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", - "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/bigjs" - } - }, - "node_modules/bn.js": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", - "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", - "license": "MIT" - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, - "node_modules/bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "license": "MIT", - "dependencies": { - "base-x": "^5.0.0" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/bufferutil": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", - "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", - "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "get-intrinsic": "^1.3.0", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cbw-sdk": { - "name": "@coinbase/wallet-sdk", - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/@coinbase/wallet-sdk/-/wallet-sdk-3.9.3.tgz", - "integrity": "sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==", - "license": "Apache-2.0", - "dependencies": { - "bn.js": "^5.2.1", - "buffer": "^6.0.3", - "clsx": "^1.2.1", - "eth-block-tracker": "^7.1.0", - "eth-json-rpc-filters": "^6.0.0", - "eventemitter3": "^5.0.1", - "keccak": "^3.0.3", - "preact": "^10.16.0", - "sha.js": "^2.4.11" - } - }, - "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/check-error": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", - "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - } - }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/cookie-es": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", - "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/cross-fetch": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", - "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.7.0" - } - }, - "node_modules/crossws": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", - "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", - "license": "MIT", - "dependencies": { - "uncrypto": "^0.1.3" - } - }, - "node_modules/crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", - "license": "BSD-3-Clause", - "engines": { - "node": "*" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/dayjs": { - "version": "1.11.13", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", - "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/derive-valtio": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", - "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", - "license": "MIT", - "peerDependencies": { - "valtio": "*" - } - }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "license": "MIT" - }, - "node_modules/detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dijkstrajs": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", - "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", - "license": "MIT" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/duplexify": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", - "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.2" - } - }, - "node_modules/eciesjs": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.18.tgz", - "integrity": "sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==", - "license": "MIT", - "dependencies": { - "@ecies/ciphers": "^0.2.5", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "^1.9.7", - "@noble/hashes": "^1.8.0" - }, - "engines": { - "bun": ">=1", - "deno": ">=2", - "node": ">=16" - } - }, - "node_modules/eciesjs/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/encode-utf8": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", - "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/engine.io-client": { - "version": "6.6.6", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.6.tgz", - "integrity": "sha512-iY6QdftLQ9pyiPoX082bpf/u1UewnOaJrtJIF9T0++QB34lZrj0uP+Q/bj8AlUsAxqhnkTV2BS8SBZSxOmoV5Q==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.21.0", - "xmlhttprequest-ssl": "~2.1.1" - } - }, - "node_modules/engine.io-client/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/engine.io-client/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-toolkit": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.33.0.tgz", - "integrity": "sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/esbuild": { - "version": "0.28.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", - "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.2", - "@esbuild/android-arm": "0.28.2", - "@esbuild/android-arm64": "0.28.2", - "@esbuild/android-x64": "0.28.2", - "@esbuild/darwin-arm64": "0.28.2", - "@esbuild/darwin-x64": "0.28.2", - "@esbuild/freebsd-arm64": "0.28.2", - "@esbuild/freebsd-x64": "0.28.2", - "@esbuild/linux-arm": "0.28.2", - "@esbuild/linux-arm64": "0.28.2", - "@esbuild/linux-ia32": "0.28.2", - "@esbuild/linux-loong64": "0.28.2", - "@esbuild/linux-mips64el": "0.28.2", - "@esbuild/linux-ppc64": "0.28.2", - "@esbuild/linux-riscv64": "0.28.2", - "@esbuild/linux-s390x": "0.28.2", - "@esbuild/linux-x64": "0.28.2", - "@esbuild/netbsd-arm64": "0.28.2", - "@esbuild/netbsd-x64": "0.28.2", - "@esbuild/openbsd-arm64": "0.28.2", - "@esbuild/openbsd-x64": "0.28.2", - "@esbuild/openharmony-arm64": "0.28.2", - "@esbuild/sunos-x64": "0.28.2", - "@esbuild/win32-arm64": "0.28.2", - "@esbuild/win32-ia32": "0.28.2", - "@esbuild/win32-x64": "0.28.2" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/eth-block-tracker": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz", - "integrity": "sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==", - "license": "MIT", - "dependencies": { - "@metamask/eth-json-rpc-provider": "^1.0.0", - "@metamask/safe-event-emitter": "^3.0.0", - "@metamask/utils": "^5.0.1", - "json-rpc-random-id": "^1.0.1", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/eth-block-tracker/node_modules/@metamask/utils": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@metamask/utils/-/utils-5.0.2.tgz", - "integrity": "sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==", - "license": "ISC", - "dependencies": { - "@ethereumjs/tx": "^4.1.2", - "@types/debug": "^4.1.7", - "debug": "^4.3.4", - "semver": "^7.3.8", - "superstruct": "^1.0.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/eth-json-rpc-filters": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz", - "integrity": "sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==", - "license": "ISC", - "dependencies": { - "@metamask/safe-event-emitter": "^3.0.0", - "async-mutex": "^0.2.6", - "eth-query": "^2.1.2", - "json-rpc-engine": "^6.1.0", - "pify": "^5.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/eth-json-rpc-filters/node_modules/pify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eth-query": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/eth-query/-/eth-query-2.1.2.tgz", - "integrity": "sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==", - "license": "ISC", - "dependencies": { - "json-rpc-random-id": "^1.0.0", - "xtend": "^4.0.1" - } - }, - "node_modules/eth-rpc-errors": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz", - "integrity": "sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==", - "license": "MIT", - "dependencies": { - "fast-safe-stringify": "^2.0.6" - } - }, - "node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/ethereum-cryptography/node_modules/@noble/curves": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethereum-cryptography/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethereum-cryptography/node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethereum-cryptography/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethereum-cryptography/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/eventemitter2": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "license": "MIT" - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/extension-port-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/extension-port-stream/-/extension-port-stream-3.0.0.tgz", - "integrity": "sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==", - "license": "ISC", - "dependencies": { - "readable-stream": "^3.6.2 || ^4.4.2", - "webextension-polyfill": ">=0.10.0 <1.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-redact": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", - "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/filter-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/form-data": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", - "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.4", - "mime-types": "^2.1.35" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/h3": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", - "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", - "license": "MIT", - "dependencies": { - "cookie-es": "^1.2.3", - "crossws": "^0.3.5", - "defu": "^6.1.6", - "destr": "^2.0.5", - "iron-webcrypto": "^1.2.1", - "node-mock-http": "^1.0.4", - "radix3": "^1.1.2", - "ufo": "^1.6.3", - "uncrypto": "^0.1.3" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.13.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz", - "integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/idb-keyval": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", - "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", - "license": "Apache-2.0" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/iron-webcrypto": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", - "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/brc-dd" - } - }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT" - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-retry-allowed": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", - "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "license": "MIT" - }, - "node_modules/isows": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", - "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jose": { - "version": "6.2.12", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.12.tgz", - "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-rpc-engine": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz", - "integrity": "sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==", - "license": "ISC", - "dependencies": { - "@metamask/safe-event-emitter": "^2.0.0", - "eth-rpc-errors": "^4.0.2" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/json-rpc-engine/node_modules/@metamask/safe-event-emitter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz", - "integrity": "sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==", - "license": "ISC" - }, - "node_modules/json-rpc-random-id": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz", - "integrity": "sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==", - "license": "ISC" - }, - "node_modules/keccak": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", - "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/keyvaluestorage-interface": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", - "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==", - "license": "MIT" - }, - "node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lit": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.0.tgz", - "integrity": "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit/reactive-element": "^2.1.0", - "lit-element": "^4.2.0", - "lit-html": "^3.3.0" - } - }, - "node_modules/lit-element": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.2.tgz", - "integrity": "sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==", - "license": "BSD-3-Clause", - "dependencies": { - "@lit-labs/ssr-dom-shim": "^1.5.0", - "@lit/reactive-element": "^2.1.0", - "lit-html": "^3.3.0" - } - }, - "node_modules/lit-html": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.3.tgz", - "integrity": "sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==", - "license": "BSD-3-Clause", - "dependencies": { - "@types/trusted-types": "^2.0.2" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/md5": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", - "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", - "license": "BSD-3-Clause", - "dependencies": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "~1.1.6" - } - }, - "node_modules/micro-ftch": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", - "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", - "license": "MIT" - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mipd": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mipd/-/mipd-0.0.7.tgz", - "integrity": "sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wagmi-dev" - } - ], - "license": "MIT", - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" - }, - "node_modules/multiformats": { - "version": "9.9.0", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", - "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", - "license": "(Apache-2.0 AND MIT)" - }, - "node_modules/nanoid": { - "version": "3.3.19", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", - "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "license": "MIT" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch-native": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", - "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", - "license": "MIT" - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-mock-http": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.5.tgz", - "integrity": "sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw==", - "license": "MIT" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/obj-multiplex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/obj-multiplex/-/obj-multiplex-1.0.0.tgz", - "integrity": "sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==", - "license": "ISC", - "dependencies": { - "end-of-stream": "^1.4.0", - "once": "^1.4.0", - "readable-stream": "^2.3.3" - } - }, - "node_modules/obj-multiplex/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/obj-multiplex/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/obj-multiplex/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/obj-multiplex/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/ofetch": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", - "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", - "license": "MIT", - "dependencies": { - "destr": "^2.0.5", - "node-fetch-native": "^1.6.7", - "ufo": "^1.6.1" - } - }, - "node_modules/on-exit-leak-free": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz", - "integrity": "sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==", - "license": "MIT" - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openapi-fetch": { - "version": "0.13.8", - "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.13.8.tgz", - "integrity": "sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==", - "license": "MIT", - "dependencies": { - "openapi-typescript-helpers": "^0.0.15" - } - }, - "node_modules/openapi-typescript-helpers": { - "version": "0.0.15", - "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.15.tgz", - "integrity": "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==", - "license": "MIT" - }, - "node_modules/ox": { - "version": "0.14.44", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.44.tgz", - "integrity": "sha512-O54qXXHEk4ySamMSyBpI0AeBegS5frxU6+LA6Jb9Sf6kMOxcTNaxYmwZfpOu22DIQsdKfgQxHq8EsAGaoBQScA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.2.3", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/oxlint": { - "version": "1.83.0", - "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.83.0.tgz", - "integrity": "sha512-cyDzSzaw3uzP0TeCeq3lLRPPoaUxkbB4ZOXj+kn+5r+BX9V+4bNVGk9lxer+WrgcpebH4JxLlJ3KQjveVztOLQ==", - "dev": true, - "license": "MIT", - "bin": { - "oxlint": "bin/oxlint" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/oxc-project" - }, - "optionalDependencies": { - "@oxlint/binding-android-arm-eabi": "1.83.0", - "@oxlint/binding-android-arm64": "1.83.0", - "@oxlint/binding-darwin-arm64": "1.83.0", - "@oxlint/binding-darwin-x64": "1.83.0", - "@oxlint/binding-freebsd-x64": "1.83.0", - "@oxlint/binding-linux-arm-gnueabihf": "1.83.0", - "@oxlint/binding-linux-arm-musleabihf": "1.83.0", - "@oxlint/binding-linux-arm64-gnu": "1.83.0", - "@oxlint/binding-linux-arm64-musl": "1.83.0", - "@oxlint/binding-linux-ppc64-gnu": "1.83.0", - "@oxlint/binding-linux-riscv64-gnu": "1.83.0", - "@oxlint/binding-linux-riscv64-musl": "1.83.0", - "@oxlint/binding-linux-s390x-gnu": "1.83.0", - "@oxlint/binding-linux-x64-gnu": "1.83.0", - "@oxlint/binding-linux-x64-musl": "1.83.0", - "@oxlint/binding-openharmony-arm64": "1.83.0", - "@oxlint/binding-win32-arm64-msvc": "1.83.0", - "@oxlint/binding-win32-ia32-msvc": "1.83.0", - "@oxlint/binding-win32-x64-msvc": "1.83.0" - }, - "peerDependencies": { - "oxlint-tsgolint": ">=7.0.2001", - "vite-plus": "*" - }, - "peerDependenciesMeta": { - "oxlint-tsgolint": { - "optional": true - }, - "vite-plus": { - "optional": true - } - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.16" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", - "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/pino": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-7.11.0.tgz", - "integrity": "sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0", - "fast-redact": "^3.0.0", - "on-exit-leak-free": "^0.2.0", - "pino-abstract-transport": "v0.5.0", - "pino-std-serializers": "^4.0.0", - "process-warning": "^1.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.1.0", - "safe-stable-stringify": "^2.1.0", - "sonic-boom": "^2.2.1", - "thread-stream": "^0.15.1" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-0.5.0.tgz", - "integrity": "sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==", - "license": "MIT", - "dependencies": { - "duplexify": "^4.1.2", - "split2": "^4.0.0" - } - }, - "node_modules/pino-std-serializers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz", - "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==", - "license": "MIT" - }, - "node_modules/pngjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", - "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", - "license": "MIT", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pony-cause": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/pony-cause/-/pony-cause-2.1.11.tgz", - "integrity": "sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==", - "license": "0BSD", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/porto": { - "version": "0.2.35", - "resolved": "https://registry.npmjs.org/porto/-/porto-0.2.35.tgz", - "integrity": "sha512-gu9FfjjvvYBgQXUHWTp6n3wkTxVtEcqFotM7i3GEZeoQbvLGbssAicCz6hFZ8+xggrJWwi/RLmbwNra50SMmUQ==", - "license": "MIT", - "dependencies": { - "hono": "^4.10.3", - "idb-keyval": "^6.2.1", - "mipd": "^0.0.7", - "ox": "^0.9.6", - "zod": "^4.1.5", - "zustand": "^5.0.1" - }, - "bin": { - "porto": "dist/cli/bin/index.js" - }, - "peerDependencies": { - "@tanstack/react-query": ">=5.59.0", - "@wagmi/core": ">=2.16.3", - "expo-auth-session": ">=7.0.8", - "expo-crypto": ">=15.0.7", - "expo-web-browser": ">=15.0.8", - "react": ">=18", - "react-native": ">=0.81.4", - "typescript": ">=5.4.0", - "viem": ">=2.37.0", - "wagmi": ">=2.0.0" - }, - "peerDependenciesMeta": { - "@tanstack/react-query": { - "optional": true - }, - "expo-auth-session": { - "optional": true - }, - "expo-crypto": { - "optional": true - }, - "expo-web-browser": { - "optional": true - }, - "react": { - "optional": true - }, - "react-native": { - "optional": true - }, - "typescript": { - "optional": true - }, - "wagmi": { - "optional": true - } - } - }, - "node_modules/porto/node_modules/ox": { - "version": "0.9.17", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.17.tgz", - "integrity": "sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.0.9", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/porto/node_modules/zod": { - "version": "4.6.5", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz", - "integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", - "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.18", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/preact": { - "version": "10.24.2", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz", - "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/process-warning": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-1.0.0.tgz", - "integrity": "sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==", - "license": "MIT" - }, - "node_modules/proxy-compare": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", - "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/qrcode": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", - "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", - "license": "MIT", - "dependencies": { - "dijkstrajs": "^1.0.1", - "encode-utf8": "^1.0.3", - "pngjs": "^5.0.0", - "yargs": "^15.3.1" - }, - "bin": { - "qrcode": "bin/qrcode" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/query-string": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz", - "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==", - "license": "MIT", - "dependencies": { - "decode-uri-component": "^0.2.2", - "filter-obj": "^1.1.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, - "node_modules/radix3": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", - "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", - "license": "MIT" - }, - "node_modules/react": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", - "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.3.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", - "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.28.0" - }, - "peerDependencies": { - "react": "^19.3.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/real-require": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.1.0.tgz", - "integrity": "sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "license": "ISC" - }, - "node_modules/rolldown": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.8.tgz", - "integrity": "sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.149.0", - "@rolldown/pluginutils": "^1.0.0" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm-eabi": "1.2.8", - "@rolldown/binding-android-arm64": "1.2.8", - "@rolldown/binding-darwin-arm64": "1.2.8", - "@rolldown/binding-darwin-x64": "1.2.8", - "@rolldown/binding-freebsd-x64": "1.2.8", - "@rolldown/binding-linux-arm-gnueabihf": "1.2.8", - "@rolldown/binding-linux-arm64-gnu": "1.2.8", - "@rolldown/binding-linux-arm64-musl": "1.2.8", - "@rolldown/binding-linux-ppc64-gnu": "1.2.8", - "@rolldown/binding-linux-s390x-gnu": "1.2.8", - "@rolldown/binding-linux-x64-gnu": "1.2.8", - "@rolldown/binding-linux-x64-musl": "1.2.8", - "@rolldown/binding-openharmony-arm64": "1.2.8", - "@rolldown/binding-win32-arm64-msvc": "1.2.8", - "@rolldown/binding-win32-x64-msvc": "1.2.8" - } - }, - "node_modules/rollup": { - "version": "4.63.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.3.tgz", - "integrity": "sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@napi-rs/lzma-linux-x64-gnu": "1.5.1", - "@rollup/rollup-android-arm-eabi": "4.63.3", - "@rollup/rollup-android-arm64": "4.63.3", - "@rollup/rollup-darwin-arm64": "4.63.3", - "@rollup/rollup-darwin-x64": "4.63.3", - "@rollup/rollup-freebsd-arm64": "4.63.3", - "@rollup/rollup-freebsd-x64": "4.63.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.63.3", - "@rollup/rollup-linux-arm-musleabihf": "4.63.3", - "@rollup/rollup-linux-arm64-gnu": "4.63.3", - "@rollup/rollup-linux-arm64-musl": "4.63.3", - "@rollup/rollup-linux-loong64-gnu": "4.63.3", - "@rollup/rollup-linux-loong64-musl": "4.63.3", - "@rollup/rollup-linux-ppc64-gnu": "4.63.3", - "@rollup/rollup-linux-ppc64-musl": "4.63.3", - "@rollup/rollup-linux-riscv64-gnu": "4.63.3", - "@rollup/rollup-linux-riscv64-musl": "4.63.3", - "@rollup/rollup-linux-s390x-gnu": "4.63.3", - "@rollup/rollup-linux-x64-gnu": "4.63.3", - "@rollup/rollup-linux-x64-musl": "4.63.3", - "@rollup/rollup-openbsd-x64": "4.63.3", - "@rollup/rollup-openharmony-arm64": "4.63.3", - "@rollup/rollup-win32-arm64-msvc": "4.63.3", - "@rollup/rollup-win32-ia32-msvc": "4.63.3", - "@rollup/rollup-win32-x64-gnu": "4.63.3", - "@rollup/rollup-win32-x64-msvc": "4.63.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", - "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/socket.io-client": { - "version": "4.8.3", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", - "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1", - "engine.io-client": "~6.6.1", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-client/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-client/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/socket.io-parser": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", - "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.4.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socket.io-parser/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/sonic-boom": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", - "integrity": "sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "license": "MIT" - }, - "node_modules/strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-literal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", - "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/superstruct": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.4.tgz", - "integrity": "sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thread-stream": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-0.15.2.tgz", - "integrity": "sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==", - "license": "MIT", - "dependencies": { - "real-require": "^0.1.0" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, - "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz", - "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typescript": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", - "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", - "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", - "license": "MIT" - }, - "node_modules/uint8arrays": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", - "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", - "license": "MIT", - "dependencies": { - "multiformats": "^9.4.2" - } - }, - "node_modules/uncrypto": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", - "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/unstorage": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", - "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", - "license": "MIT", - "dependencies": { - "anymatch": "^3.1.3", - "chokidar": "^5.0.0", - "destr": "^2.0.5", - "h3": "^1.15.10", - "lru-cache": "^11.2.7", - "node-fetch-native": "^1.6.7", - "ofetch": "^1.5.1", - "ufo": "^1.6.3" - }, - "peerDependencies": { - "@azure/app-configuration": "^1.8.0", - "@azure/cosmos": "^4.2.0", - "@azure/data-tables": "^13.3.0", - "@azure/identity": "^4.6.0", - "@azure/keyvault-secrets": "^4.9.0", - "@azure/storage-blob": "^12.26.0", - "@capacitor/preferences": "^6 || ^7 || ^8", - "@deno/kv": ">=0.9.0", - "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", - "@planetscale/database": "^1.19.0", - "@upstash/redis": "^1.34.3", - "@vercel/blob": ">=0.27.1", - "@vercel/functions": "^2.2.12 || ^3.0.0", - "@vercel/kv": "^1 || ^2 || ^3", - "aws4fetch": "^1.0.20", - "db0": ">=0.2.1", - "idb-keyval": "^6.2.1", - "ioredis": "^5.4.2", - "uploadthing": "^7.4.4" - }, - "peerDependenciesMeta": { - "@azure/app-configuration": { - "optional": true - }, - "@azure/cosmos": { - "optional": true - }, - "@azure/data-tables": { - "optional": true - }, - "@azure/identity": { - "optional": true - }, - "@azure/keyvault-secrets": { - "optional": true - }, - "@azure/storage-blob": { - "optional": true - }, - "@capacitor/preferences": { - "optional": true - }, - "@deno/kv": { - "optional": true - }, - "@netlify/blobs": { - "optional": true - }, - "@planetscale/database": { - "optional": true - }, - "@upstash/redis": { - "optional": true - }, - "@vercel/blob": { - "optional": true - }, - "@vercel/functions": { - "optional": true - }, - "@vercel/kv": { - "optional": true - }, - "aws4fetch": { - "optional": true - }, - "db0": { - "optional": true - }, - "idb-keyval": { - "optional": true - }, - "ioredis": { - "optional": true - }, - "uploadthing": { - "optional": true - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", - "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/valtio": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", - "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", - "license": "MIT", - "dependencies": { - "derive-valtio": "0.1.0", - "proxy-compare": "2.6.0", - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/valtio/node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/viem": { - "version": "2.56.5", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.56.5.tgz", - "integrity": "sha512-GuEf/oee0PHgy4D6JIA8u0rY1g+sM5nF+p7HyMHO3vjlHC5G/ljfrgnUOnrES9m5Ny/P3RwWCHjDuN2T6HUWzQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.9.1", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0", - "abitype": "1.2.3", - "isows": "1.0.7", - "ox": "0.14.44", - "ws": "8.21.0" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/vite": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz", - "integrity": "sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "lightningcss": "^1.33.0", - "picomatch": "^4.0.7", - "postcss": "^8.5.28", - "rolldown": "~1.2.6", - "tinyglobby": "^0.2.17" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.7.1", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite-node/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/vite-node/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite-node/node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz", - "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.7", - "@vitest/mocker": "3.2.7", - "@vitest/pretty-format": "^3.2.7", - "@vitest/runner": "3.2.7", - "@vitest/snapshot": "3.2.7", - "@vitest/spy": "3.2.7", - "@vitest/utils": "3.2.7", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.7", - "@vitest/ui": "3.2.7", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz", - "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "3.2.7", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vitest/node_modules/vite": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", - "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0 || ^0.28.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/wagmi": { - "version": "2.19.5", - "resolved": "https://registry.npmjs.org/wagmi/-/wagmi-2.19.5.tgz", - "integrity": "sha512-RQUfKMv6U+EcSNNGiPbdkDtJwtuFxZWLmvDiQmjjBgkuPulUwDJsKhi7gjynzJdsx2yDqhHCXkKsbbfbIsHfcQ==", - "license": "MIT", - "dependencies": { - "@wagmi/connectors": "6.2.0", - "@wagmi/core": "2.22.1", - "use-sync-external-store": "1.4.0" - }, - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "@tanstack/react-query": ">=5.0.0", - "react": ">=18", - "typescript": ">=5.0.4", - "viem": "2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/webextension-polyfill": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "license": "MPL-2.0" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "license": "ISC" - }, - "node_modules/which-typed-array": { - "version": "1.1.22", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", - "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", - "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "license": "ISC" - }, - "node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zustand": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", - "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", - "license": "MIT", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=18.0.0", - "immer": ">=9.0.6", - "react": ">=18.0.0", - "use-sync-external-store": ">=1.2.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - }, - "use-sync-external-store": { - "optional": true - } - } - } - } -} diff --git a/web/package.json b/web/package.json deleted file mode 100644 index 6b36f7f..0000000 --- a/web/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "web", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc -b && vite build", - "lint": "oxlint", - "test": "vitest run", - "preview": "vite preview" - }, - "dependencies": { - "@tanstack/react-query": "^5.102.8", - "react": "^19.2.8", - "react-dom": "^19.2.8", - "viem": "^2.56.5", - "wagmi": "^2.19.5" - }, - "devDependencies": { - "@types/node": "^24.13.3", - "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.7", - "@vitejs/plugin-react": "^6.1.1", - "oxlint": "^1.81.0", - "typescript": "~6.0.2", - "vite": "^8.3.0", - "vitest": "^3.2.7" - } -} diff --git a/web/public/favicon.svg b/web/public/favicon.svg deleted file mode 100644 index 3d571db..0000000 --- a/web/public/favicon.svg +++ /dev/null @@ -1 +0,0 @@ -S diff --git a/web/public/icons.svg b/web/public/icons.svg deleted file mode 100644 index e952219..0000000 --- a/web/public/icons.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/web/src/App.tsx b/web/src/App.tsx deleted file mode 100644 index 7a0e425..0000000 --- a/web/src/App.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { useEffect, useState } from "react"; -import { AppShell, type AppPage } from "./components/AppShell"; -import { Skeleton } from "./components/Reveal"; -import { TxFlow } from "./components/TxFlow"; -import { Empty } from "./components/ui"; -import { useInvalidateVault, useVault } from "./hooks/useVault"; -import { AddressBook } from "./pages/AddressBook"; -import { Assets } from "./pages/Assets"; -import { CreateVault } from "./pages/CreateVault"; -import { Landing } from "./pages/Landing"; -import { Members } from "./pages/Members"; -import { Overview } from "./pages/Overview"; -import { Policies } from "./pages/Policies"; -import { Product } from "./pages/Product"; -import { Security } from "./pages/Security"; -import { SecurityPage } from "./pages/SecurityPage"; -import { Mobile } from "./pages/Mobile"; -import { Docs, DOC_SLUGS, type DocSlug } from "./pages/Docs"; -import { Settings } from "./pages/Settings"; -import { Simulator } from "./pages/Simulator"; -import { Solutions } from "./pages/Solutions"; -import { Transactions } from "./pages/Transactions"; -import { Welcome } from "./pages/Welcome"; -import { ThemeContext, useThemeState } from "./state/theme"; -import { useVaultAddress } from "./state/vaultAddress"; - -/** - * Routes, patterned on safe.global -> app.safe.global: - * #/ #/product #/solutions #/security #/mobile marketing - * #/welcome #/new-vault onboarding - * #/app/ the vault app - */ -type Route = { kind: "landing" } | { kind: "product" } | { kind: "solutions" } | { kind: "securitypage" } | { kind: "mobile" } | { kind: "docs"; slug: DocSlug } | { kind: "welcome" } | { kind: "create" } | { kind: "app"; page: AppPage }; - -const APP_PAGES: AppPage[] = ["overview", "assets", "transactions", "addressbook", "members", "settings", "policies", "security", "simulator"]; -const LEGACY: Record = { home: "overview", recipients: "addressbook" }; - -function readRoute(): Route { - const raw = window.location.hash.replace(/^#\/?/, "").split("?")[0].split("#")[0]; - if (raw === "" || raw === "/") return { kind: "landing" }; - if (raw === "product") return { kind: "product" }; - if (raw === "solutions") return { kind: "solutions" }; - if (raw === "security") return { kind: "securitypage" }; - if (raw === "mobile") return { kind: "mobile" }; - if (raw === "docs" || raw.startsWith("docs/")) { - const slug = raw.slice(5) as DocSlug; - return { kind: "docs", slug: DOC_SLUGS.includes(slug) ? slug : "introduction" }; - } - if (raw === "welcome") return { kind: "welcome" }; - if (raw === "new-vault") return { kind: "create" }; - const seg = raw.replace(/^app\//, ""); - const page = (LEGACY[seg] ?? seg) as AppPage; - if (APP_PAGES.includes(page)) return { kind: "app", page }; - return { kind: "landing" }; -} - -function go(route: Route) { - const hash = route.kind === "landing" ? "#/" : route.kind === "product" ? "#/product" : route.kind === "solutions" ? "#/solutions" : route.kind === "securitypage" ? "#/security" : route.kind === "mobile" ? "#/mobile" : route.kind === "docs" ? `#/docs/${route.slug}` : route.kind === "welcome" ? "#/welcome" : route.kind === "create" ? "#/new-vault" : `#/app/${route.page}`; - if (window.location.hash !== hash) window.location.hash = hash; - window.scrollTo({ top: 0 }); -} - -function LoadingVault() { - return ( -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - ); -} - -export default function App() { - const themeState = useThemeState(); - const [route, setRoute] = useState(readRoute); - const [vaultAddress, setVaultAddress] = useVaultAddress(); - const { data: vault, error, isLoading } = useVault(route.kind === "app" ? vaultAddress : null); - const invalidate = useInvalidateVault(vaultAddress); - const [flow, setFlow] = useState<{ open: boolean; asset?: `0x${string}` }>({ open: false }); - - useEffect(() => { - const onHash = () => setRoute(readRoute()); - window.addEventListener("hashchange", onHash); - return () => window.removeEventListener("hashchange", onHash); - }, []); - - useEffect(() => { window.scrollTo(0, 0); }, [route.kind, "page" in route ? route.page : "", "slug" in route ? route.slug : ""]); - const marketing = route.kind === "landing" || route.kind === "product" || route.kind === "solutions" || route.kind === "securitypage" || route.kind === "mobile" || route.kind === "docs"; - useEffect(() => { - document.documentElement.setAttribute("data-theme", marketing ? "light" : themeState.theme); - }, [marketing, themeState.theme]); - - const navigate = (page: AppPage) => go({ kind: "app", page }); - const openFlow = (asset?: `0x${string}`) => setFlow({ open: true, asset }); - const openVault = (a: `0x${string}`) => { setVaultAddress(a); go({ kind: "app", page: "overview" }); }; - const launch = () => go({ kind: "welcome" }); - - if (route.kind === "landing") return ; - if (route.kind === "product") return ; - if (route.kind === "solutions") return ; - if (route.kind === "securitypage") return ; - if (route.kind === "mobile") return ; - if (route.kind === "docs") return { window.location.hash = `#/docs/${s}`; }} />; - - return ( - - {route.kind === "welcome" && go({ kind: "create" })} onLanding={() => go({ kind: "landing" })} />} - {route.kind === "create" && go({ kind: "welcome" })} />} - {route.kind === "app" && ( - <> - openFlow()} onSwitchVault={launch}> -
      - {route.page === "settings" ? ( - - ) : route.page === "simulator" ? ( - - ) : !vaultAddress ? ( - No vault selected. . - ) : error ? ( -
      Could not read the vault: {(error as Error).message}
      - ) : isLoading || !vault ? ( - - ) : route.page === "overview" ? ( - openFlow()} /> - ) : route.page === "assets" ? ( - openFlow(a)} onNavigate={navigate} /> - ) : route.page === "transactions" ? ( - openFlow()} /> - ) : route.page === "addressbook" ? ( - - ) : route.page === "members" ? ( - - ) : route.page === "policies" ? ( - - ) : ( - - )} -
      -
      - {flow.open && vault && setFlow({ open: false })} onChanged={() => { invalidate(); navigate("transactions"); }} />} - - )} -
      - ); -} diff --git a/web/src/abi/SkurFactory.ts b/web/src/abi/SkurFactory.ts deleted file mode 100644 index ff1da47..0000000 --- a/web/src/abi/SkurFactory.ts +++ /dev/null @@ -1,341 +0,0 @@ -// Generated from contracts/out/SkurFactory.sol/SkurFactory.json by scripts/export-abi.py. Do not edit. -export const SkurFactoryAbi = [ - { - "type": "constructor", - "inputs": [ - { - "name": "impl", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "createVault", - "inputs": [ - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - }, - { - "name": "members", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "roles", - "type": "uint8[]", - "internalType": "uint8[]" - }, - { - "name": "policy", - "type": "tuple", - "internalType": "struct Policy", - "components": [ - { - "name": "approvalsLow", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsHigh", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsCritical", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "governanceThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianRequiredCritical", - "type": "bool", - "internalType": "bool" - }, - { - "name": "delayHigh", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "delayCritical", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recipientActivationDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "policyChangeDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recoveryDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposalTtl", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "highExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "criticalExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hardBlockExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeWindow", - "type": "uint32", - "internalType": "uint32" - } - ] - }, - { - "name": "assets", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "limits", - "type": "tuple[]", - "internalType": "struct AssetLimits[]", - "components": [ - { - "name": "approved", - "type": "bool", - "internalType": "bool" - }, - { - "name": "lowMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "highMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "perTxMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "outputs": [ - { - "name": "vault", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "implementation", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "isVault", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "predictVaultAddress", - "inputs": [ - { - "name": "creator", - "type": "address", - "internalType": "address" - }, - { - "name": "salt", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "vaultAt", - "inputs": [ - { - "name": "index", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "vaultCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "vaultsOf", - "inputs": [ - { - "name": "member", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "address[]", - "internalType": "address[]" - } - ], - "stateMutability": "view" - }, - { - "type": "event", - "name": "VaultCreated", - "inputs": [ - { - "name": "vault", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "creator", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "index", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "salt", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "FailedDeployment", - "inputs": [] - }, - { - "type": "error", - "name": "InsufficientBalance", - "inputs": [ - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "NotAVault", - "inputs": [] - }, - { - "type": "error", - "name": "NotImplementation", - "inputs": [] - } -] as const; diff --git a/web/src/abi/SkurTestUSD.ts b/web/src/abi/SkurTestUSD.ts deleted file mode 100644 index e391def..0000000 --- a/web/src/abi/SkurTestUSD.ts +++ /dev/null @@ -1,352 +0,0 @@ -// Generated from contracts/out/SkurTestUSD.sol/SkurTestUSD.json by scripts/export-abi.py. Do not edit. -export const SkurTestUSDAbi = [ - { - "type": "constructor", - "inputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "MAX_MINT", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "allowance", - "inputs": [ - { - "name": "owner", - "type": "address", - "internalType": "address" - }, - { - "name": "spender", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "spender", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "balanceOf", - "inputs": [ - { - "name": "account", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "decimals", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "pure" - }, - { - "type": "function", - "name": "mint", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "name", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "symbol", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "string", - "internalType": "string" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalSupply", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "transfer", - "inputs": [ - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "transferFrom", - "inputs": [ - { - "name": "from", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "Approval", - "inputs": [ - { - "name": "owner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "spender", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Transfer", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "value", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "ERC20InsufficientAllowance", - "inputs": [ - { - "name": "spender", - "type": "address", - "internalType": "address" - }, - { - "name": "allowance", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ERC20InsufficientBalance", - "inputs": [ - { - "name": "sender", - "type": "address", - "internalType": "address" - }, - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "needed", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ERC20InvalidApprover", - "inputs": [ - { - "name": "approver", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ERC20InvalidReceiver", - "inputs": [ - { - "name": "receiver", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ERC20InvalidSender", - "inputs": [ - { - "name": "sender", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ERC20InvalidSpender", - "inputs": [ - { - "name": "spender", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "MintTooLarge", - "inputs": [] - } -] as const; diff --git a/web/src/abi/SkurVault.ts b/web/src/abi/SkurVault.ts deleted file mode 100644 index 22e2060..0000000 --- a/web/src/abi/SkurVault.ts +++ /dev/null @@ -1,2136 +0,0 @@ -// Generated from contracts/out/SkurVault.sol/SkurVault.json by scripts/export-abi.py. Do not edit. -export const SkurVaultAbi = [ - { - "type": "constructor", - "inputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "receive", - "stateMutability": "payable" - }, - { - "type": "function", - "name": "approve", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "approverCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "cancel", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "depositERC20", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "execute", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "executedCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "executorCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "expire", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "getApprovers", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "address[]", - "internalType": "address[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getAssetLimits", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct AssetLimits", - "components": [ - { - "name": "approved", - "type": "bool", - "internalType": "bool" - }, - { - "name": "lowMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "highMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "perTxMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getAssets", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "address[]", - "internalType": "address[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getGuardianConfirmers", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "address[]", - "internalType": "address[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getMembers", - "inputs": [], - "outputs": [ - { - "name": "addrs", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "roles", - "type": "uint8[]", - "internalType": "uint8[]" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getPolicy", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct Policy", - "components": [ - { - "name": "approvalsLow", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsHigh", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsCritical", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "governanceThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianRequiredCritical", - "type": "bool", - "internalType": "bool" - }, - { - "name": "delayHigh", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "delayCritical", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recipientActivationDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "policyChangeDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recoveryDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposalTtl", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "highExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "criticalExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hardBlockExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeWindow", - "type": "uint32", - "internalType": "uint32" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getProposal", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct Proposal", - "components": [ - { - "name": "kind", - "type": "uint8", - "internalType": "enum Kind" - }, - { - "name": "status", - "type": "uint8", - "internalType": "enum Status" - }, - { - "name": "tier", - "type": "uint8", - "internalType": "enum Tier" - }, - { - "name": "requiredApprovals", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "requiredGuardians", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "securityReducing", - "type": "bool", - "internalType": "bool" - }, - { - "name": "riskReasons", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "policyVersion", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposer", - "type": "address", - "internalType": "address" - }, - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "target", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "createdAt", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "executableAfter", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "expiresAt", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "data", - "type": "bytes", - "internalType": "bytes" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "getRecipient", - "inputs": [ - { - "name": "r", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "tuple", - "internalType": "struct Recipient", - "components": [ - { - "name": "trust", - "type": "uint8", - "internalType": "enum Trust" - }, - { - "name": "registeredAt", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "activatesAt", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "paymentCount", - "type": "uint64", - "internalType": "uint64" - }, - { - "name": "totalPaid", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "guardianCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "hasApproved", - "inputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "initialize", - "inputs": [ - { - "name": "members", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "roles", - "type": "uint8[]", - "internalType": "uint8[]" - }, - { - "name": "policy", - "type": "tuple", - "internalType": "struct Policy", - "components": [ - { - "name": "approvalsLow", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsHigh", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsCritical", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "governanceThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianRequiredCritical", - "type": "bool", - "internalType": "bool" - }, - { - "name": "delayHigh", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "delayCritical", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recipientActivationDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "policyChangeDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recoveryDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposalTtl", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "highExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "criticalExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hardBlockExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeWindow", - "type": "uint32", - "internalType": "uint32" - } - ] - }, - { - "name": "assets", - "type": "address[]", - "internalType": "address[]" - }, - { - "name": "limits", - "type": "tuple[]", - "internalType": "struct AssetLimits[]", - "components": [ - { - "name": "approved", - "type": "bool", - "internalType": "bool" - }, - { - "name": "lowMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "highMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "perTxMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "isVetoable", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "", - "type": "bool", - "internalType": "bool" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "liveApprovals", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "approvals", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "guardians", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "mode", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "enum Mode" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "ownerCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "pendingCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "policyVersion", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint32", - "internalType": "uint32" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "previewTransfer", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - } - ], - "outputs": [ - { - "name": "r", - "type": "tuple", - "internalType": "struct RiskResult", - "components": [ - { - "name": "tier", - "type": "uint8", - "internalType": "enum Tier" - }, - { - "name": "reasons", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "exposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "requiredApprovals", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "requiredGuardians", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "delay", - "type": "uint32", - "internalType": "uint32" - } - ] - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "proposalCount", - "inputs": [], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "proposeAssetLimits", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "next", - "type": "tuple", - "internalType": "struct AssetLimits", - "components": [ - { - "name": "approved", - "type": "bool", - "internalType": "bool" - }, - { - "name": "lowMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "highMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "perTxMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposeMember", - "inputs": [ - { - "name": "member", - "type": "address", - "internalType": "address" - }, - { - "name": "roles", - "type": "uint8", - "internalType": "uint8" - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposeModeRelax", - "inputs": [ - { - "name": "target", - "type": "uint8", - "internalType": "enum Mode" - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposePolicy", - "inputs": [ - { - "name": "next", - "type": "tuple", - "internalType": "struct Policy", - "components": [ - { - "name": "approvalsLow", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsHigh", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsCritical", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "governanceThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianRequiredCritical", - "type": "bool", - "internalType": "bool" - }, - { - "name": "delayHigh", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "delayCritical", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recipientActivationDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "policyChangeDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recoveryDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposalTtl", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "highExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "criticalExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hardBlockExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeWindow", - "type": "uint32", - "internalType": "uint32" - } - ] - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposeRecipientTrust", - "inputs": [ - { - "name": "recipient", - "type": "address", - "internalType": "address" - }, - { - "name": "trust", - "type": "uint8", - "internalType": "enum Trust" - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposeRecovery", - "inputs": [ - { - "name": "oldSigner", - "type": "address", - "internalType": "address" - }, - { - "name": "newSigner", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "proposeTransfer", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "memo", - "type": "string", - "internalType": "string" - } - ], - "outputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "raiseMode", - "inputs": [ - { - "name": "target", - "type": "uint8", - "internalType": "enum Mode" - }, - { - "name": "reason", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "registerRecipient", - "inputs": [ - { - "name": "r", - "type": "address", - "internalType": "address" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "function", - "name": "rolesOf", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint8", - "internalType": "uint8" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalDeposited", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "totalOutflow", - "inputs": [ - { - "name": "", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "", - "type": "uint256", - "internalType": "uint256" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "velocityOf", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - } - ], - "outputs": [ - { - "name": "daySpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "envelopeSpent", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "envelope", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "envelopeResetsAt", - "type": "uint64", - "internalType": "uint64" - } - ], - "stateMutability": "view" - }, - { - "type": "function", - "name": "veto", - "inputs": [ - { - "name": "id", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "reason", - "type": "bytes32", - "internalType": "bytes32" - } - ], - "outputs": [], - "stateMutability": "nonpayable" - }, - { - "type": "event", - "name": "AssetLimitsSet", - "inputs": [ - { - "name": "asset", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "limits", - "type": "tuple", - "indexed": false, - "internalType": "struct AssetLimits", - "components": [ - { - "name": "approved", - "type": "bool", - "internalType": "bool" - }, - { - "name": "lowMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "highMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "perTxMax", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "CircuitBreakerTripped", - "inputs": [ - { - "name": "asset", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "attempted", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "envelopeSpent", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "envelope", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "Deposit", - "inputs": [ - { - "name": "from", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "asset", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "MemberSet", - "inputs": [ - { - "name": "member", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "previousRoles", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - }, - { - "name": "roles", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ModeChanged", - "inputs": [ - { - "name": "previous", - "type": "uint8", - "indexed": true, - "internalType": "enum Mode" - }, - { - "name": "mode", - "type": "uint8", - "indexed": true, - "internalType": "enum Mode" - }, - { - "name": "by", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "reason", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "PolicyActivated", - "inputs": [ - { - "name": "version", - "type": "uint32", - "indexed": true, - "internalType": "uint32" - }, - { - "name": "activatedAt", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - }, - { - "name": "policy", - "type": "tuple", - "indexed": false, - "internalType": "struct Policy", - "components": [ - { - "name": "approvalsLow", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsHigh", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "approvalsCritical", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "governanceThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianThreshold", - "type": "uint8", - "internalType": "uint8" - }, - { - "name": "guardianRequiredCritical", - "type": "bool", - "internalType": "bool" - }, - { - "name": "delayHigh", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "delayCritical", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recipientActivationDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "policyChangeDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "recoveryDelay", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "proposalTtl", - "type": "uint32", - "internalType": "uint32" - }, - { - "name": "highExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "criticalExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "hardBlockExposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "envelopeWindow", - "type": "uint32", - "internalType": "uint32" - } - ] - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalApproved", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "approver", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "approvals", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalCancelled", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "by", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalCreated", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "kind", - "type": "uint8", - "indexed": true, - "internalType": "enum Kind" - }, - { - "name": "proposer", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "asset", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "target", - "type": "address", - "indexed": false, - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - }, - { - "name": "tier", - "type": "uint8", - "indexed": false, - "internalType": "enum Tier" - }, - { - "name": "riskReasons", - "type": "uint16", - "indexed": false, - "internalType": "uint16" - }, - { - "name": "requiredApprovals", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - }, - { - "name": "requiredGuardians", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - }, - { - "name": "executableAfter", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - }, - { - "name": "expiresAt", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - }, - { - "name": "securityReducing", - "type": "bool", - "indexed": false, - "internalType": "bool" - }, - { - "name": "memo", - "type": "string", - "indexed": false, - "internalType": "string" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalExecuted", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "executor", - "type": "address", - "indexed": true, - "internalType": "address" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalGuardianConfirmed", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "guardian", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "confirmations", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "ProposalVetoed", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "guardian", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "reason", - "type": "bytes32", - "indexed": false, - "internalType": "bytes32" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RecipientRegistered", - "inputs": [ - { - "name": "recipient", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "activatesAt", - "type": "uint64", - "indexed": false, - "internalType": "uint64" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RecipientTrustSet", - "inputs": [ - { - "name": "recipient", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "previous", - "type": "uint8", - "indexed": false, - "internalType": "enum Trust" - }, - { - "name": "trust", - "type": "uint8", - "indexed": false, - "internalType": "enum Trust" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "RecoveryCompleted", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "oldSigner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "newSigner", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "roles", - "type": "uint8", - "indexed": false, - "internalType": "uint8" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "TransferExecuted", - "inputs": [ - { - "name": "id", - "type": "uint256", - "indexed": true, - "internalType": "uint256" - }, - { - "name": "asset", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "to", - "type": "address", - "indexed": true, - "internalType": "address" - }, - { - "name": "amount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "event", - "name": "VaultInitialized", - "inputs": [ - { - "name": "policyVersion", - "type": "uint32", - "indexed": false, - "internalType": "uint32" - }, - { - "name": "memberCount", - "type": "uint256", - "indexed": false, - "internalType": "uint256" - } - ], - "anonymous": false - }, - { - "type": "error", - "name": "AlreadyApproved", - "inputs": [] - }, - { - "type": "error", - "name": "AlreadyInitialized", - "inputs": [] - }, - { - "type": "error", - "name": "AmountZero", - "inputs": [] - }, - { - "type": "error", - "name": "AssetNotApproved", - "inputs": [ - { - "name": "asset", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ExposureHardBlocked", - "inputs": [ - { - "name": "exposureBps", - "type": "uint16", - "internalType": "uint16" - }, - { - "name": "maxBps", - "type": "uint16", - "internalType": "uint16" - } - ] - }, - { - "type": "error", - "name": "InsufficientApprovals", - "inputs": [ - { - "name": "have", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "need", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "InsufficientBalance", - "inputs": [ - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "balance", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "InsufficientGuardians", - "inputs": [ - { - "name": "have", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "need", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "InvalidPolicy", - "inputs": [ - { - "name": "reason", - "type": "string", - "internalType": "string" - } - ] - }, - { - "type": "error", - "name": "InvalidProposal", - "inputs": [ - { - "name": "reason", - "type": "string", - "internalType": "string" - } - ] - }, - { - "type": "error", - "name": "InvalidRoles", - "inputs": [] - }, - { - "type": "error", - "name": "MemberExists", - "inputs": [] - }, - { - "type": "error", - "name": "ModeNotRelaxation", - "inputs": [] - }, - { - "type": "error", - "name": "ModeNotStricter", - "inputs": [] - }, - { - "type": "error", - "name": "NativeTransferFailed", - "inputs": [] - }, - { - "type": "error", - "name": "NotAuthorized", - "inputs": [ - { - "name": "requiredRole", - "type": "uint8", - "internalType": "uint8" - } - ] - }, - { - "type": "error", - "name": "NotCancellable", - "inputs": [] - }, - { - "type": "error", - "name": "NotMember", - "inputs": [] - }, - { - "type": "error", - "name": "NotPending", - "inputs": [] - }, - { - "type": "error", - "name": "NotVetoable", - "inputs": [] - }, - { - "type": "error", - "name": "PerTxLimitExceeded", - "inputs": [ - { - "name": "amount", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "max", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ProposalExpired", - "inputs": [] - }, - { - "type": "error", - "name": "RecipientBlocked", - "inputs": [ - { - "name": "recipient", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "RecipientNotRegistered", - "inputs": [] - }, - { - "type": "error", - "name": "ReentrancyGuardReentrantCall", - "inputs": [] - }, - { - "type": "error", - "name": "SafeERC20FailedOperation", - "inputs": [ - { - "name": "token", - "type": "address", - "internalType": "address" - } - ] - }, - { - "type": "error", - "name": "ThresholdUnsatisfiable", - "inputs": [ - { - "name": "reason", - "type": "string", - "internalType": "string" - } - ] - }, - { - "type": "error", - "name": "Timelocked", - "inputs": [ - { - "name": "executableAfter", - "type": "uint64", - "internalType": "uint64" - } - ] - }, - { - "type": "error", - "name": "UnknownProposal", - "inputs": [] - }, - { - "type": "error", - "name": "VaultLocked", - "inputs": [] - }, - { - "type": "error", - "name": "VelocityExceeded", - "inputs": [ - { - "name": "wouldSpend", - "type": "uint256", - "internalType": "uint256" - }, - { - "name": "dailyMax", - "type": "uint256", - "internalType": "uint256" - } - ] - }, - { - "type": "error", - "name": "ZeroAddress", - "inputs": [] - } -] as const; diff --git a/web/src/assets/hero.png b/web/src/assets/hero.png deleted file mode 100644 index 02251f4b956c55af2d76fd0788124d7eee2b45eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13057 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 P00000NkvXXu0mjft=yBf diff --git a/web/src/assets/vite.svg b/web/src/assets/vite.svg deleted file mode 100644 index 5101b67..0000000 --- a/web/src/assets/vite.svg +++ /dev/null @@ -1 +0,0 @@ -Vite diff --git a/web/src/components/AppShell.tsx b/web/src/components/AppShell.tsx deleted file mode 100644 index e925dd1..0000000 --- a/web/src/components/AppShell.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { useEffect, useState, type ReactNode } from "react"; -import { useAccount, useConnect, useDisconnect, useSwitchChain } from "wagmi"; -import { arkDevnet, explorerAddress, NATIVE_ASSET } from "../config/chain"; -import { fmtAmount } from "../lib/format"; -import { Mode, roleNames, Status } from "../lib/types"; -import { useTheme } from "../state/theme"; -import { useVaultLabel } from "../state/vaultLabel"; -import { Button, ModeBadge } from "./ui"; -import { Identicon } from "./Identicon"; -import { IconApps, IconAssets, IconBook, IconChevron, IconCollapse, IconDocs, IconExternal, IconHelp, IconLab, IconMoon, IconOverview, IconPlus, IconPolicy, IconSettings, IconShield, IconSun, IconTx, IconUsers, IconWallet } from "./icons"; -import type { VaultData } from "../hooks/useVault"; - -export type AppPage = "overview" | "assets" | "transactions" | "addressbook" | "members" | "settings" | "policies" | "security" | "simulator"; - -const MAIN_NAV: Array<[AppPage, string, ReactNode]> = [ - ["overview", "Overview", ], - ["assets", "Assets", ], - ["transactions", "Transactions", ], - ["addressbook", "Address book", ], - ["members", "Members", ], - ["settings", "Settings", ], -]; -const SECURITY_NAV: Array<[AppPage, string, ReactNode]> = [ - ["policies", "Policies", ], - ["security", "Security", ], - ["simulator", "Simulator", ], -]; - -/** Safe{Wallet} application layout: full-height sidebar with the Home pill, content column with the account pill row. */ -export function AppShell({ page, onNavigate, onHome, vault, vaultAddress, onNewTransaction, onSwitchVault, children }: { page: AppPage; onNavigate: (p: AppPage) => void; onHome: () => void; vault?: VaultData; vaultAddress: `0x${string}` | null; onNewTransaction: () => void; onSwitchVault: () => void; children: ReactNode }) { - const [collapsed, setCollapsed] = useState(() => { try { return localStorage.getItem("skur.sidebar") === "collapsed"; } catch { return false; } }); - useEffect(() => { try { localStorage.setItem("skur.sidebar", collapsed ? "collapsed" : "open"); } catch { /* ignore */ } }, [collapsed]); - const { address, isConnected, chainId } = useAccount(); - const { connectors, connect, isPending } = useConnect(); - const { disconnect } = useDisconnect(); - const { switchChain } = useSwitchChain(); - const { theme, toggle } = useTheme(); - const [label] = useVaultLabel(vaultAddress); - const me = vault?.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const wrongChain = isConnected && chainId !== arkDevnet.id; - const pending = vault?.proposals.filter((p) => p.status === Status.PENDING).length ?? 0; - const stable = vault?.assets.find((a) => a.address !== NATIVE_ASSET); - const native = vault?.assets.find((a) => a.address === NATIVE_ASSET); - const canPropose = Boolean((me?.roles ?? 0) & 3) && vault?.mode !== Mode.LOCKDOWN; - - return ( -
      - - -
      -
      -
      -
      - {vaultAddress ? ( - - ) : ( - - )} -
      - - {vaultAddress && ( - - )} - {wrongChain ? ( - - ) : isConnected && address ? ( - - ) : ( - connectors.slice(0, 1).map((c) => ( - - )) - )} -
      -
      - {children} -
      -
      -
      - ); -} - -export const AppsIcon = IconApps; diff --git a/web/src/components/Identicon.tsx b/web/src/components/Identicon.tsx deleted file mode 100644 index 0b55c83..0000000 --- a/web/src/components/Identicon.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useMemo } from "react"; -import { keccak256, stringToHex } from "viem"; - -/** Deterministic blocky identicon for an address, in the spirit of the avatar Safe shows beside every account. */ -export function Identicon({ address, size = 40 }: { address: string; size?: number }) { - const { cells, fg, bg } = useMemo(() => { - const hash = keccak256(stringToHex(address.toLowerCase())).slice(2); - const hue = parseInt(hash.slice(0, 4), 16) % 360; - const hue2 = (hue + 140) % 360; - const bits = hash.slice(4); - const cells: boolean[] = []; - // 5x5 grid, mirrored horizontally; 15 bits drive the left half + centre column - for (let y = 0; y < 5; y++) { - const row: boolean[] = []; - for (let x = 0; x < 3; x++) { - const nibble = parseInt(bits[(y * 3 + x) % bits.length], 16); - row.push(nibble % 3 !== 0); - } - cells.push(row[0], row[1], row[2], row[1], row[0]); - } - return { cells, fg: `hsl(${hue} 70% 45%)`, bg: `hsl(${hue2} 60% 88%)` }; - }, [address]); - const unit = size / 5; - return ( - - - {cells.map((on, i) => - on ? : null, - )} - - ); -} diff --git a/web/src/components/MarketingShell.tsx b/web/src/components/MarketingShell.tsx deleted file mode 100644 index 39d3425..0000000 --- a/web/src/components/MarketingShell.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import type { ReactNode } from "react"; -import { useScrolled } from "../lib/motion"; -import { IconChevronRight } from "./icons"; - -export type MarketingPage = "landing" | "product" | "solutions" | "security" | "mobile" | "docs"; - -/** Nav, closing CTA and footer shared by every marketing page. */ -export function MarketingShell({ page, onLaunch, children, hideCta = false }: { page: MarketingPage; onLaunch: () => void; children: ReactNode; hideCta?: boolean }) { - const scrolled = useScrolled(); - return ( -
      -
      -
      - SSkur - -
      - Ark devnet · 9000 - -
      -
      -
      - {children} - {!hideCta && ( -
      -
      -
      Start here
      -

      Put a firewall in front of
      your treasury

      -

      Self-custodial, enforced onchain, and readable by the people who sign.

      -
      - Read the docs - -
      -
      -
      - )} -
      - -
      - ); -} - -/** Hero used by the product, solutions and security pages. */ -export function SubHero({ eyebrow, title, sub, onLaunch, children }: { eyebrow: string; title: ReactNode; sub: string; onLaunch: () => void; children?: ReactNode }) { - return ( - <> -
      -
      - {[[0, 130], [1310, 0], [1180, 260], [130, 390], [910, 390]].map(([x, y], i) => ( - - ))} -
      -
      {eyebrow}
      -

      {title}

      -

      {sub}

      -
      - - {children} -
      -
      -
      -
      - - ); -} diff --git a/web/src/components/Mockup.tsx b/web/src/components/Mockup.tsx deleted file mode 100644 index 69a507e..0000000 --- a/web/src/components/Mockup.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/** Static miniature of the app used as artwork on the landing page, the way safe.global shows its dashboard. */ -export function AppMockup({ variant = "overview" }: { variant?: "overview" | "queue" | "policy" }) { - return ( -
      -
      -
      S  Home
      -
      + New transaction
      - {["Overview", "Assets", "Transactions", "Address book", "Members", "Settings"].map((n, i) => ( -
      {n}
      - ))} -
      Security
      - {["Policies", "Security", "Simulator"].map((n) => ( -
      {n}
      - ))} -
      -
      -
      - - Main treasury
      ark:0xCC31…42Dc
      - 2/3 · 250,000 sUSD · Normal -
      - {variant === "overview" && ( - <> -
      -
      Total balance
      -
      250,000.00 sUSD
      - ↗ Send⌗ Receive -
      Top assets
      -
      $ sUSD250,000
      -
      K KASH2
      -
      -
      -
      Pending transactions
      -
      Send 12,000 sUSD1 out of 2
      -
      Send 900 sUSD✓ 1 out of 1
      -
      Update policy⏱ 1d timelock
      -
      - - )} - {variant === "queue" && ( -
      -
      Queue
      -
      ↗ Send 12,000 sUSD to 0x4F…a1c2High risk · 1 out of 2
      -
      ↗ Send 60,000 sUSD to 0x9B…77e0Critical · guardian · 1d
      -
      ⚙ Lower approvals to 1Security-reducing · vetoable
      -
      - )} - {variant === "policy" && ( -
      -
      Policy simulator
      -
      One finance signer compromisedBlocked
      -
      Drain split into twenty transfersBlocked
      -
      Attacker weakens policy, then withdrawsDelayed 1d
      -
      Guardian key compromisedNot possible
      -
      - )} -
      -
      - ); -} diff --git a/web/src/components/NetworkGuard.tsx b/web/src/components/NetworkGuard.tsx deleted file mode 100644 index 0637f43..0000000 --- a/web/src/components/NetworkGuard.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { useAccount, useSwitchChain } from "wagmi"; -import { arkDevnet } from "../config/chain"; -import { Button } from "./ui"; - -/** Shows a switch button while the connected wallet is on a chain other than the Ark devnet. */ -export function NetworkGuard() { - const { isConnected, chainId } = useAccount(); - const { switchChain, isPending } = useSwitchChain(); - if (!isConnected || chainId === arkDevnet.id) return null; - return ( - - ); -} diff --git a/web/src/components/PhoneMockup.tsx b/web/src/components/PhoneMockup.tsx deleted file mode 100644 index 8bc36b9..0000000 --- a/web/src/components/PhoneMockup.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { tokenMark } from "../lib/tokens"; - -type Variant = "home" | "queue" | "confirm"; - -const TOKENS: Array<[string, string, string]> = [ - ["sUSD", "250,000", "0 of 100,000 today"], - ["KASH", "3", "0 of 5,000 today"], - ["sEUR", "84,500", "0 of 100,000 today"], - ["sBTC", "3.42", "0 of 50 today"], -]; - -/** - * The phone app, drawn at true device scale (393 x 852) and scaled as a unit, so the type sizes and - * spacing are the app's own rather than a squeezed approximation. - */ -export function PhoneMockup({ variant = "home", width = 268, label }: { variant?: Variant; width?: number; label?: string }) { - return ( -
      -
      -
      - -
      {variant === "home" ? : variant === "queue" ? : }
      - {variant === "confirm" ? null : } - -
      - -
      -
      - ); -} - -function StatusBar() { - return ( -
      - 9:41 - - - - - -
      - ); -} - -function TabBar({ active }: { active: number }) { - return ( -
      - {["⌂", "⇄", "⚙"].map((g, i) => ( - - {g} - {i === 1 ? 1 : null} - - ))} -
      - ); -} - -function Mark({ symbol, size = 40 }: { symbol: string; size?: number }) { - const m = tokenMark(symbol); - return {m.glyph}; -} - -function Home() { - return ( - <> -
      - 1/2 - Treasury vault⌄ - -
      -
      1Pending transactions›
      -
      AArk devnet0xD3f0…ED52
      -
      250,000sUSD
      -
      ↗ Send↙ Receive
      -
      Tokens
      - {TOKENS.map(([sym, amt, sub]) => ( -
      - - {tokenMark(sym).name}{sub} - {amt} -
      - ))} - - ); -} - -function Queue() { - return ( - <> -
      Transactions+
      -
      Queue · 2History
      -
      All typesTransfersGovernance
      -
      Sep 17, 2026
      -
      - {[["↗", "Send", "12,000 sUSD to 0x7c4f…41e2", "1 of 2"], ["≡", "Policy update", "tightens every control", "0 of 1"]].map(([g, t, d, s], i) => ( -
      - {g} - {t}{d} - {s} - › -
      - ))} -
      - - ); -} - -function Confirm() { - return ( - <> -
      ←Confirm transaction
      -
      - ↗ - −12,000 sUSD - Send · to 0x7c4f…41e2 - 1 of 2 confirmations -
      -
      -
      To0x7c4f…41e2
      -
      PurposeInvoice 1042
      -
      NetworkArk devnet · 9000
      -
      -
      -
      ⛨Risk reviewnever paid · above routineHigh›
      -
      ◎Confirmationsone more signer needed1/2›
      -
      -
      ✎Confirm0x4FEA…EEc0›
      - - ); -} diff --git a/web/src/components/Reveal.tsx b/web/src/components/Reveal.tsx deleted file mode 100644 index 6acdadc..0000000 --- a/web/src/components/Reveal.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import type { ReactNode } from "react"; -import { useReveal } from "../lib/motion"; - -/** Scroll-reveal wrapper. `stagger` animates each direct child in sequence. */ -export function Reveal({ children, stagger = false, className = "", as: Tag = "div" }: { children: ReactNode; stagger?: boolean; className?: string; as?: "div" | "section" | "ul" }) { - const ref = useReveal(); - return ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - - {children} - - ); -} - -export function Skeleton({ w = "100%", h = 14, style = {} }: { w?: number | string; h?: number; style?: React.CSSProperties }) { - return ; -} diff --git a/web/src/components/RiskReview.tsx b/web/src/components/RiskReview.tsx deleted file mode 100644 index eae3b87..0000000 --- a/web/src/components/RiskReview.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { fmtAmount, fmtBps, fmtDuration, short } from "../lib/format"; -import { explainReasons, Tier, TIER_LABEL, Trust, TRUST_LABEL, type AssetMeta } from "../lib/types"; -import { TierBadge } from "./ui"; - -export type ReviewInput = { - asset: AssetMeta; - to: `0x${string}`; - toLabel?: string; - amount: bigint; - memo: string; - tier: Tier; - reasons: number; - exposureBps: number; - requiredApprovals: number; - requiredGuardians: number; - delay: number; - trust: Trust; - activatesAt?: bigint; - vetoable: boolean; -}; - -/** Human-readable intent shown before a wallet signature is requested. */ -export function RiskReview({ r }: { r: ReviewInput }) { - const reasons = explainReasons(r.reasons); - const nowSec = Math.floor(Date.now() / 1000); - const probationWait = r.activatesAt && Number(r.activatesAt) > nowSec + r.delay ? Number(r.activatesAt) - nowSec : 0; - const effectiveDelay = Math.max(r.delay, probationWait); - const remaining = r.asset.balance - r.amount; - return ( -
      -
      - Action - - Send {fmtAmount(r.amount, r.asset.decimals, r.asset.symbol)} to {r.toLabel ? `${r.toLabel} (${short(r.to)})` : short(r.to)} - -
      - {r.memo && ( -
      - Purpose - {r.memo} -
      - )} -
      - Treasury impact - - {fmtBps(r.exposureBps)} of {r.asset.symbol} holdings · {fmtAmount(remaining < 0n ? 0n : remaining, r.asset.decimals, r.asset.symbol)} remains - -
      -
      - Recipient - {TRUST_LABEL[r.trust]}{r.trust === Trust.UNKNOWN ? " · will be registered as New" : ""} -
      -
      - Risk tier - -
      -
      - Security requirement - - {TIER_LABEL[r.tier]} · {r.requiredApprovals} approval{r.requiredApprovals === 1 ? "" : "s"} - {r.requiredGuardians ? ` + ${r.requiredGuardians} guardian confirmation${r.requiredGuardians === 1 ? "" : "s"}` : ""} - {effectiveDelay ? ` · executable after ${fmtDuration(effectiveDelay)}` : " · no delay"} - -
      - {r.vetoable && ( -
      - Guardian veto - Any guardian can cancel this at any point before it executes. -
      - )} - {reasons.length > 0 && ( -
      - Why this tier -
        - {reasons.map((t) => ( -
      • {t}
      • - ))} -
      -
      - )} -
      - ); -} diff --git a/web/src/components/Ticker.tsx b/web/src/components/Ticker.tsx deleted file mode 100644 index b2ee227..0000000 --- a/web/src/components/Ticker.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useEffect, useState } from "react"; - -type Sample = { amt: string; to: string; tier: "low" | "high" | "critical" | "blocked"; label: string; why: string[] }; - -const SAMPLES: Sample[] = [ - { amt: "1,000 sUSD", to: "Design retainer · verified", tier: "low", label: "LOW · 1 approval · executes now", why: ["Below the routine threshold", "Recipient verified, paid 14 times before", "Uses 3% of today's cap"] }, - { amt: "12,000 sUSD", to: "0x7c4f…41e2 · never paid", tier: "high", label: "HIGH · 2 approvals · waits 24h", why: ["Above the routine threshold", "This vault has never paid the address", "Activation delay applies; any guardian can veto"] }, - { amt: "60,000 sUSD", to: "Exchange deposit · verified", tier: "critical", label: "CRITICAL · 2 + guardian · 24h", why: ["24% of holdings in one payment", "Above the high threshold", "Needs a guardian; any guardian can veto"] }, - { amt: "9,900 sUSD × 20", to: "Split across one day", tier: "blocked", label: "BLOCKED · circuit breaker", why: ["Outflow is counted cumulatively", "Loss envelope crossed on payment 11", "Vault enters Lockdown instead of paying"] }, -]; - -/** Live scorer for the hero: cycles through sample payments and shows how the vault would tier each one. */ -export function ScoreTicker() { - const reduced = typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; - const [i, setI] = useState(0); - const [phase, setPhase] = useState<"scoring" | "done">(reduced ? "done" : "scoring"); - useEffect(() => { - if (reduced) return; - const t = setTimeout(() => setPhase("done"), phase === "scoring" ? 1100 : 3400); - if (phase === "done") { - const n = setTimeout(() => { setI((x) => (x + 1) % SAMPLES.length); setPhase("scoring"); }, 3400); - return () => { clearTimeout(t); clearTimeout(n); }; - } - return () => clearTimeout(t); - }, [phase, reduced]); - const s = SAMPLES[i]; - return ( -
      -
      Risk engine · live previewPolicy v3 · Normal
      -
      -
      Payment{s.amt}
      -
      Recipient{s.to}
      -
      -
      - {phase === "scoring" ? Scoring against policy… : {s.label}} -
      -
        - {phase === "done" && s.why.map((w, k) =>
      • {w}
      • )} -
      -
      -
      - Requirements are pinned at proposal and checked again at execution. - {SAMPLES.map((_, k) => )} -
      -
      - ); -} diff --git a/web/src/components/TxFlow.tsx b/web/src/components/TxFlow.tsx deleted file mode 100644 index f3096a4..0000000 --- a/web/src/components/TxFlow.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import { useEffect, useState } from "react"; -import { usePublicClient } from "wagmi"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { describeError, useTx } from "../hooks/useTx"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, parseAmount } from "../lib/format"; -import { Mode, REASON_RECIPIENT_PROBATION, Tier, Trust } from "../lib/types"; -import { RiskReview, type ReviewInput } from "./RiskReview"; -import { Button, Field, Modal, TokenIcon, TxStatus } from "./ui"; - -/** - * "New transaction" flow, patterned on Safe's send-tokens dialog: details, then a review step that is - * populated by the vault's own previewTransfer before the wallet is ever asked to sign. - */ -export function TxFlow({ vault, onClose, onChanged, presetAsset }: { vault: VaultData; onClose: () => void; onChanged: () => void; presetAsset?: `0x${string}` }) { - const client = usePublicClient(); - const approved = vault.assets.filter((a) => a.limits.approved); - const [step, setStep] = useState<1 | 2>(1); - const [asset, setAsset] = useState(presetAsset ?? approved[0]?.address ?? ""); - const [to, setTo] = useState(""); - const [amountText, setAmountText] = useState(""); - const [memo, setMemo] = useState(""); - const [preview, setPreview] = useState(null); - const [previewError, setPreviewError] = useState(null); - const [loadingPreview, setLoadingPreview] = useState(false); - const tx = useTx(() => { - onChanged(); - }); - - const meta = approved.find((a) => a.address === asset); - const amount = meta ? parseAmount(amountText, meta.decimals) : null; - const validTo = isAddress(to); - const detailsOk = Boolean(meta && amount && amount > 0n && validTo); - - useEffect(() => { - if (step !== 2 || !client || !meta || !validTo || !amount) return; - let cancelled = false; - setPreview(null); - setPreviewError(null); - setLoadingPreview(true); - (async () => { - try { - const [r, rec] = await Promise.all([ - client.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "previewTransfer", args: [meta.address, to as `0x${string}`, amount] }), - client.readContract({ address: vault.address, abi: SkurVaultAbi, functionName: "getRecipient", args: [to as `0x${string}`] }), - ]); - if (cancelled) return; - const tier = Number(r.tier) as Tier; - const reasons = Number(r.reasons); - const trust = Number(rec.trust) as Trust; - setPreview({ - asset: meta, - to: to as `0x${string}`, - amount, - memo, - tier, - reasons, - exposureBps: Number(r.exposureBps), - requiredApprovals: Number(r.requiredApprovals), - requiredGuardians: Number(r.requiredGuardians), - delay: Number(r.delay), - trust, - activatesAt: trust === Trust.UNKNOWN ? BigInt(Math.floor(Date.now() / 1000) + vault.policy.recipientActivationDelay) : rec.activatesAt, - vetoable: tier === Tier.CRITICAL || Boolean(reasons & REASON_RECIPIENT_PROBATION) || vault.mode !== Mode.NORMAL, - }); - } catch (e) { - if (!cancelled) setPreviewError(describeError(e)); - } finally { - if (!cancelled) setLoadingPreview(false); - } - })(); - return () => { - cancelled = true; - }; - }, [step, client, meta, to, amount, memo, validTo, vault]); - - const submit = () => { - if (!meta || !amount || !validTo) return; - tx.send({ address: vault.address, abi: SkurVaultAbi, functionName: "proposeTransfer", args: [meta.address, to as `0x${string}`, amount, memo] }); - }; - const done = tx.state.phase === "done"; - - const steps = ( - <> - 1 Details - · - 2 Review - - ); - - return ( - - - - - ) : done ? ( - <> - - - - ) : ( - <> - - - - ) - } - > - {step === 1 ? ( - <> - - setTo(e.target.value.trim())} placeholder="0x…" list="known-recipients" autoFocus /> - - {vault.recipients.map((r) => ( - - -
      - - - - - setAmountText(e.target.value)} placeholder="0.00" inputMode="decimal" /> - -
      - - setMemo(e.target.value)} placeholder="Invoice 1042, design retainer" maxLength={140} /> - - - ) : ( - <> - {meta && amount && ( -
      - -
      -
      {fmtAmount(amount, meta.decimals, meta.symbol)}
      -
      to {to}
      -
      -
      - )} - {loadingPreview &&
      Asking the vault how it scores this payment…
      } - {previewError &&
      {previewError}
      } - {preview && } - - - )} -
      - ); -} diff --git a/web/src/components/TxRow.tsx b/web/src/components/TxRow.tsx deleted file mode 100644 index c84b7ab..0000000 --- a/web/src/components/TxRow.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { useState } from "react"; -import { useAccount } from "wagmi"; -import { decodeAbiParameters, stringToHex } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { useTx } from "../hooks/useTx"; -import type { ProposalView, VaultData } from "../hooks/useVault"; -import { fmtAmount, fmtBps, fmtDate, fmtRelative, nowSec, short } from "../lib/format"; -import { explainReasons, Kind, KIND_LABEL, Mode, MODE_LABEL, ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, roleNames, Status, Trust, TRUST_LABEL } from "../lib/types"; -import { Address, Badge, Button, ConfirmPill, TierBadge, TokenIcon, TxStatus } from "./ui"; -import { IconChevron, IconLock, IconPolicy, IconSend, IconShield, IconUsers } from "./icons"; - -function describe(p: ProposalView, vault: VaultData): { kind: string; amount?: string; symbol?: string; detail: string } { - const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); - switch (p.kind) { - case Kind.TRANSFER: - return { kind: "Send", amount: asset ? `-${fmtAmount(p.amount, asset.decimals)} ${asset.symbol}` : String(p.amount), symbol: asset?.symbol, detail: `to ${short(p.target)}` }; - case Kind.POLICY_UPDATE: - return { kind: "Policy update", detail: p.securityReducing ? "loosens at least one control" : "tightens or keeps every control" }; - case Kind.ASSET_LIMITS: - return { kind: "Asset limits", detail: `${asset?.symbol ?? short(p.target)} · ${p.securityReducing ? "loosens a limit or approves an asset" : "tightens limits"}` }; - case Kind.MEMBER_SET: { - const roles = Number(p.amount); - return { kind: roles === 0 ? "Remove member" : "Set roles", detail: `${short(p.target)}${roles ? ` → ${roleNames(roles).join(" + ")}` : ""}` }; - } - case Kind.RECIPIENT_TRUST: - return { kind: "Recipient trust", detail: `${short(p.target)} → ${TRUST_LABEL[Number(p.amount) as Trust]}` }; - case Kind.MODE_RELAX: - return { kind: "Lower security mode", detail: `to ${MODE_LABEL[Number(p.amount) as Mode]} · guardians must confirm` }; - case Kind.RECOVERY: { - let newSigner = "?"; - try { - newSigner = decodeAbiParameters([{ type: "address" }], p.data)[0]; - } catch { - /* ignore */ - } - return { kind: "Recovery", detail: `${short(p.target)} → ${short(newSigner)}` }; - } - } -} - -function KindIcon({ kind }: { kind: Kind }) { - if (kind === Kind.TRANSFER) return ; - if (kind === Kind.RECOVERY || kind === Kind.MODE_RELAX) return ; - if (kind === Kind.MEMBER_SET) return ; - return ; -} - -/** One transaction as Safe renders it: a rounded card row (type, amount, time, status) that expands into details and a timeline. */ -export function TxRow({ p, vault, onChanged, compact = false }: { p: ProposalView; vault: VaultData; onChanged: () => void; compact?: boolean }) { - const [open, setOpen] = useState(false); - const { address } = useAccount(); - const tx = useTx(onChanged); - const me = vault.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const roles = me?.roles ?? 0; - const now = nowSec(); - const d = describe(p, vault); - const asset = vault.assets.find((a) => a.address.toLowerCase() === p.asset.toLowerCase()); - const pending = p.status === Status.PENDING; - const expired = pending && Number(p.expiresAt) < now; - const timelocked = Number(p.executableAfter) > now; - const alreadyApproved = address ? [...p.approvers, ...p.guardianConfirmers].some((a) => a.toLowerCase() === address.toLowerCase()) : false; - - const canApprove = pending && !expired && !alreadyApproved && (roles & ROLE_GUARDIAN ? p.requiredGuardians > 0 : p.kind === Kind.RECOVERY ? false : p.kind === Kind.TRANSFER ? Boolean(roles & ROLE_APPROVER) : Boolean(roles & ROLE_OWNER)); - const executeRole = p.kind === Kind.TRANSFER ? ROLE_EXECUTOR : p.kind === Kind.RECOVERY ? ROLE_OWNER | ROLE_GUARDIAN : ROLE_OWNER | ROLE_EXECUTOR; - const approvalsMet = p.liveApprovals >= p.requiredApprovals && p.liveGuardians >= p.requiredGuardians; - const lockedOut = vault.mode === Mode.LOCKDOWN && (p.kind === Kind.TRANSFER || (p.securityReducing && p.kind !== Kind.MODE_RELAX)); - const canExecute = pending && !expired && Boolean(roles & executeRole) && approvalsMet && !timelocked && !lockedOut; - const canVeto = pending && !expired && Boolean(roles & ROLE_GUARDIAN) && p.vetoable; - const canCancel = pending && !expired && (Boolean(roles & ROLE_OWNER) || p.proposer.toLowerCase() === address?.toLowerCase()); - const call = (functionName: string, args: readonly unknown[] = [p.id]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName, args }); - const reasons = explainReasons(p.riskReasons); - const need = p.requiredApprovals + p.requiredGuardians; - const have = Math.min(p.liveApprovals, p.requiredApprovals) + Math.min(p.liveGuardians, p.requiredGuardians); - const stage: "confirm" | "wait" | "execute" | "final" = !pending ? "final" : !approvalsMet ? "confirm" : timelocked || lockedOut ? "wait" : "execute"; - - const status = pending && !expired ? ( - - ) : ( - - {p.status === Status.EXECUTED ? "Success" : p.status === Status.VETOED ? "Vetoed" : expired ? "Expired" : "Cancelled"} - - ); - - return ( -
      -
      setOpen((o) => !o)} style={compact ? { gridTemplateColumns: "24px 1fr auto 24px", padding: "14px 12px" } : undefined}> - -
      - {d.kind} - {compact && d.amount && · {d.amount}} - {compact &&
      {d.detail}
      } -
      - {!compact && ( -
      - {d.symbol && } - {d.amount ?? d.detail} - {d.amount && {d.detail}} -
      - )} - {!compact &&
      {fmtDate(p.createdAt).split(",").slice(-1)[0]?.trim() || fmtRelative(p.createdAt)}
      } -
      {status}
      - -
      - - {open && ( -
      -
      -
      - {KIND_LABEL[p.kind]} #{String(p.id)} - {p.kind === Kind.TRANSFER && } - {p.securityReducing && Security-reducing} - {pending && !expired && ( - - {stage === "execute" ? "Ready to execute" : stage === "wait" ? (lockedOut ? "Locked down" : `Executable ${fmtRelative(p.executableAfter)}`) : "Needs confirmations"} - - )} -
      -
      - {p.kind === Kind.TRANSFER && ( - <> -
      Recipient
      -
      Amount
      {asset ? fmtAmount(p.amount, asset.decimals, asset.symbol) : String(p.amount)}
      - {asset && asset.balance > 0n &&
      Treasury impact
      {fmtBps(Number((p.amount * 10_000n) / (asset.balance + (p.status === Status.EXECUTED ? p.amount : 0n))))} of {asset.symbol}
      } - - )} - {p.kind !== Kind.TRANSFER && p.target !== "0x0000000000000000000000000000000000000000" &&
      Target
      } - {p.memo &&
      Purpose
      {p.memo}
      } -
      Proposed by
      -
      Requirement
      {p.requiredApprovals} approval{p.requiredApprovals === 1 ? "" : "s"}{p.requiredGuardians ? ` + ${p.requiredGuardians} guardian` : ""}{Number(p.executableAfter) > Number(p.createdAt) ? ` · not before ${fmtDate(p.executableAfter)}` : ""}
      -
      Expires
      {fmtDate(p.expiresAt)}
      - {p.vetoable && pending &&
      Guardian veto
      open until execution
      } -
      - {reasons.length > 0 && p.kind === Kind.TRANSFER && ( - <> -
      Why this tier
      -
        {reasons.map((r) =>
      • {r}
      • )}
      - - )} - {pending && ( -
      - {canApprove && } - {Boolean(roles & executeRole) && !expired && ( - - )} - {canVeto && } - {canCancel && !expired && } - {expired && } -
      - )} - -
      -
        -
      • Created
        {fmtDate(p.createdAt)} by {short(p.proposer)}
      • -
      • = p.requiredApprovals ? "done" : stage === "confirm" ? "active" : ""}> -
        Confirmations ({Math.min(p.liveApprovals, p.requiredApprovals)} of {p.requiredApprovals})
        -
        - {p.approvers.length === 0 && No confirmations yet} - {p.approvers.map((a) => ✓
        )} -
        -
      • - {p.requiredGuardians > 0 && ( -
      • = p.requiredGuardians ? "done" : stage === "confirm" ? "active" : ""}> -
        Guardian confirmations ({Math.min(p.liveGuardians, p.requiredGuardians)} of {p.requiredGuardians})
        -
        - {p.guardianConfirmers.length === 0 && Independent sign-off required} - {p.guardianConfirmers.map((a) => ✓
        )} -
        -
      • - )} - {Number(p.executableAfter) > Number(p.createdAt) && ( -
      • -
        Timelock
        -
        {timelocked ? `Executable ${fmtRelative(p.executableAfter)}` : `Passed ${fmtDate(p.executableAfter)}`}
        -
      • - )} -
      • -
        {p.status === Status.EXECUTED ? "Executed" : p.status === Status.VETOED ? "Vetoed by a guardian" : p.status === Status.CANCELLED ? "Cancelled" : "Execute"}
        -
        {pending ? (stage === "execute" ? "Any executor can execute now" : "Waiting on the steps above") : ""}
        -
      • -
      -
      - )} -
      - ); -} diff --git a/web/src/components/icons.tsx b/web/src/components/icons.tsx deleted file mode 100644 index 94cebba..0000000 --- a/web/src/components/icons.tsx +++ /dev/null @@ -1,219 +0,0 @@ -/** Small inline icon set (24px grid, 1.75 stroke), matching the line-icon style of the Safe interface. */ -import type { SVGProps } from "react"; - -const base = (props: SVGProps) => ({ - width: 18, - height: 18, - viewBox: "0 0 24 24", - fill: "none", - stroke: "currentColor", - strokeWidth: 1.75, - strokeLinecap: "round" as const, - strokeLinejoin: "round" as const, - ...props, -}); - -export const IconOverview = (p: SVGProps) => ( - - - - -); -export const IconAssets = (p: SVGProps) => ( - - - - -); -export const IconTx = (p: SVGProps) => ( - - - -); -export const IconBook = (p: SVGProps) => ( - - - - - -); -export const IconUsers = (p: SVGProps) => ( - - - - -); -export const IconApps = (p: SVGProps) => ( - - - - - - -); -export const IconPolicy = (p: SVGProps) => ( - - - - -); -export const IconShield = (p: SVGProps) => ( - - - - -); -export const IconLab = (p: SVGProps) => ( - - - -); -export const IconSettings = (p: SVGProps) => ( - - - - -); -export const IconSend = (p: SVGProps) => ( - - - -); -export const IconReceive = (p: SVGProps) => ( - - - - -); -export const IconCopy = (p: SVGProps) => ( - - - - -); -export const IconExternal = (p: SVGProps) => ( - - - -); -export const IconChevron = (p: SVGProps) => ( - - - -); -export const IconChevronRight = (p: SVGProps) => ( - - - -); -export const IconArrowRight = (p: SVGProps) => ( - - - -); -export const IconCheck = (p: SVGProps) => ( - - - -); -export const IconSun = (p: SVGProps) => ( - - - - -); -export const IconMoon = (p: SVGProps) => ( - - - -); -export const IconLock = (p: SVGProps) => ( - - - - -); -export const IconClose = (p: SVGProps) => ( - - - -); -export const IconClock = (p: SVGProps) => ( - - - - -); -export const IconWallet = (p: SVGProps) => ( - - - - -); -export const IconPlus = (p: SVGProps) => ( - - - -); -export const IconSearch = (p: SVGProps) => ( - - - - -); -export const IconBell = (p: SVGProps) => ( - - - - -); -export const IconHelp = (p: SVGProps) => ( - - - - -); -export const IconDocs = (p: SVGProps) => ( - - - - -); -export const IconTrend = (p: SVGProps) => ( - - - -); -export const IconLayers = (p: SVGProps) => ( - - - - -); -export const IconGuard = (p: SVGProps) => ( - - - - -); -export const IconBank = (p: SVGProps) => ( - - - -); -export const IconSwap = (p: SVGProps) => ( - - - -); -export const IconCollapse = (p: SVGProps) => ( - - - - -); -export const IconMenu = (p: SVGProps) => ( - - - -); diff --git a/web/src/components/ui.tsx b/web/src/components/ui.tsx deleted file mode 100644 index a9c67e2..0000000 --- a/web/src/components/ui.tsx +++ /dev/null @@ -1,211 +0,0 @@ -import { useEffect, useState, type ReactNode } from "react"; -import { explorerAddress, explorerTx } from "../config/chain"; -import { short } from "../lib/format"; -import { tokenMark } from "../lib/tokens"; -import { Mode, MODE_LABEL, Status, STATUS_LABEL, Tier, TIER_LABEL, Trust, TRUST_LABEL } from "../lib/types"; -import type { TxState } from "../hooks/useTx"; -import { IconCheck, IconClose, IconCopy, IconExternal } from "./icons"; - -export function Card({ title, subtitle, actions, children, className = "", flush = false }: { title?: ReactNode; subtitle?: ReactNode; actions?: ReactNode; children: ReactNode; className?: string; flush?: boolean }) { - return ( -
      - {(title || actions) && ( -
      -
      - {title &&

      {title}

      } - {subtitle &&

      {subtitle}

      } -
      - {actions &&
      {actions}
      } -
      - )} - {children} -
      - ); -} - -/** Two-column section used by Safe's settings pages: label column on the left, content on the right. */ -export function Section({ title, children }: { title: ReactNode; children: ReactNode }) { - return ( -
      -

      {title}

      -
      {children}
      -
      - ); -} - -export type Tone = "neutral" | "ok" | "warn" | "bad" | "info" | "review" | "brand"; - -export function Badge({ children, tone = "neutral" }: { children: ReactNode; tone?: Tone }) { - return {children}; -} - -/** "1 out of 2" confirmation pill, the way Safe shows signature progress. */ -export function ConfirmPill({ have, need }: { have: number; need: number }) { - const done = have >= need; - return ( - - {done ? : null} - {have} out of {need} - - ); -} - -export function TierBadge({ tier }: { tier: Tier }) { - const tone: Tone = tier === Tier.LOW ? "ok" : tier === Tier.HIGH ? "warn" : "bad"; - return {TIER_LABEL[tier]} risk; -} -export function ModeBadge({ mode }: { mode: Mode }) { - const tone: Tone = mode === Mode.NORMAL ? "ok" : mode === Mode.ELEVATED ? "warn" : "bad"; - return {MODE_LABEL[mode]}; -} -export function StatusBadge({ status }: { status: Status }) { - const tone: Tone = status === Status.EXECUTED ? "ok" : status === Status.PENDING ? "review" : status === Status.VETOED ? "bad" : "neutral"; - return {STATUS_LABEL[status]}; -} -export function TrustBadge({ trust }: { trust: Trust }) { - const tone: Tone = trust === Trust.TRUSTED || trust === Trust.VERIFIED ? "ok" : trust === Trust.NEW ? "info" : trust === Trust.UNKNOWN ? "neutral" : "bad"; - return {TRUST_LABEL[trust]}; -} - -export function CopyButton({ value, small = true }: { value: string; small?: boolean }) { - const [ok, setOk] = useState(false); - useEffect(() => { - if (!ok) return; - const t = setTimeout(() => setOk(false), 1200); - return () => clearTimeout(t); - }, [ok]); - return ( - - ); -} - -export function Address({ value, label, full = false, copy = false, prefix }: { value: string; label?: string; full?: boolean; copy?: boolean; prefix?: string }) { - return ( - - {label ? {label} : null} - - {prefix ? {prefix}: : null}{full ? value : short(value)} - - {copy && } - - ); -} - -export function TxLink({ hash }: { hash: string }) { - return ( - - {short(hash, 6)} - - - ); -} - -export type ButtonKind = "primary" | "secondary" | "dark" | "danger" | "ghost" | "white" | "black"; - -export function Button({ children, onClick, kind = "primary", disabled, type = "button", title, size, block, icon, className = "" }: { children: ReactNode; onClick?: () => void; kind?: ButtonKind; disabled?: boolean; type?: "button" | "submit"; title?: string; size?: "sm" | "lg"; block?: boolean; icon?: ReactNode; className?: string }) { - return ( - - ); -} - -export function Field({ label, children, hint }: { label: ReactNode; children: ReactNode; hint?: ReactNode }) { - return ( - - ); -} - -export function TxStatus({ state }: { state: TxState }) { - if (state.phase === "idle") return null; - if (state.phase === "error") return
      {state.message}
      ; - if (state.phase === "done") return
      Confirmed onchain.
      ; - if (state.phase === "mining") return
      Waiting for the block…
      ; - return
      {state.phase === "simulating" ? "Checking the transaction against the vault policy…" : "Confirm in your wallet…"}
      ; -} - -export function Empty({ children, icon }: { children: ReactNode; icon?: ReactNode }) { - if (icon) { - return ( -
      -
      {icon}
      -
      {children}
      -
      - ); - } - return
      {children}
      ; -} - -export function KV({ rows }: { rows: Array<[ReactNode, ReactNode]> }) { - return ( -
      - {rows.map(([k, v], i) => ( -
      -
      {k}
      -
      {v}
      -
      - ))} -
      - ); -} - -export function Tabs({ value, onChange, items }: { value: T; onChange: (t: T) => void; items: Array<{ id: T; label: ReactNode; count?: number }> }) { - return ( -
      - {items.map((it) => ( - - ))} -
      - ); -} - -export function Switch({ on, onChange, label }: { on: boolean; onChange: (v: boolean) => void; label?: ReactNode }) { - return ( - onChange(!on)} role="switch" aria-checked={on}> - - {label && {label}} - - ); -} - -export function TokenIcon({ symbol, size = 32 }: { symbol: string; size?: number }) { - const m = tokenMark(symbol); - return ( - - {m.glyph} - - ); -} - -export function Modal({ title, onClose, children, footer, steps }: { title: ReactNode; onClose: () => void; children: ReactNode; footer?: ReactNode; steps?: ReactNode }) { - useEffect(() => { - const onKey = (e: KeyboardEvent) => e.key === "Escape" && onClose(); - window.addEventListener("keydown", onKey); - return () => window.removeEventListener("keydown", onKey); - }, [onClose]); - return ( -
      e.target === e.currentTarget && onClose()}> -
      -
      -
      -

      {title}

      - {steps &&
      {steps}
      } -
      - -
      -
      {children}
      - {footer &&
      {footer}
      } -
      -
      - ); -} diff --git a/web/src/config/chain.ts b/web/src/config/chain.ts deleted file mode 100644 index 5bc6215..0000000 --- a/web/src/config/chain.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { defineChain } from "viem"; -import deployments from "./deployments.json"; - -/** - * The single place the Ark Constellation endpoints live in the interface. - * The sslip.io hosts are devnet-only and move to an Ark-owned domain for testnet/mainnet. - * The other copy is contracts/foundry.toml. - */ -export const ARK_DEVNET_RPC = "https://evm.34.60.137.196.sslip.io"; -export const ARK_DEVNET_WS = "wss://evm-ws.34.60.137.196.sslip.io"; -export const ARK_DEVNET_EXPLORER = "https://explorer.34.60.137.196.sslip.io"; -export const ARK_DEVNET_FAUCET = "https://faucet.34.60.137.196.sslip.io/"; - -export const arkDevnet = defineChain({ - id: 9000, - name: "Ark Constellation Devnet", - nativeCurrency: { name: "KASH", symbol: "KASH", decimals: 18 }, - rpcUrls: { - default: { http: [ARK_DEVNET_RPC], webSocket: [ARK_DEVNET_WS] }, - }, - blockExplorers: { - default: { name: "Blockscout", url: ARK_DEVNET_EXPLORER }, - }, - testnet: true, -}); - -export type Deployments = { - chainId: number; - testUsd: `0x${string}`; - testEur?: `0x${string}`; - testBtc?: `0x${string}`; - testEth?: `0x${string}`; - factory: `0x${string}`; - vaultImplementation: `0x${string}`; - demoVault: `0x${string}`; - deployer: `0x${string}`; - deployedAtBlock: number; -}; - -export const DEPLOYMENTS = deployments as Deployments; - -export const NATIVE_ASSET = "0x0000000000000000000000000000000000000000" as const; - -export function explorerAddress(addr: string): string { - return `${ARK_DEVNET_EXPLORER}/address/${addr}`; -} - -export function explorerTx(hash: string): string { - return `${ARK_DEVNET_EXPLORER}/tx/${hash}`; -} diff --git a/web/src/config/deployments.json b/web/src/config/deployments.json deleted file mode 100644 index bbf8be2..0000000 --- a/web/src/config/deployments.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "chainId": 9000, - "testUsd": "0x3e41424ADF6Bb69B6271ef9B0541ACD59A0d454a", - "factory": "0x018c12BA8b085da81E434b9e4001e07CF48764E9", - "vaultImplementation": "0xE21C7ad3a56D187848F9915bb43f88820278DeA3", - "demoVault": "0xD3f026024e015e1eC841a88D983883d4a017ED52", - "deployer": "0x4FEA262782b5BE34B18cf24b6aC026215899EEc0", - "deployedAtBlock": 481946, - "testEur": "0xb524729FbfCA5724BfcfBbEd70eF3e45b1aBD8F1", - "testBtc": "0xdF32512Dd6bC9E196fb442150b182172E1Ce292e", - "testEth": "0x2e494E1b1138aD260Be8bede8E8dA5110E5239bd" -} \ No newline at end of file diff --git a/web/src/hooks/useTx.ts b/web/src/hooks/useTx.ts deleted file mode 100644 index 242da39..0000000 --- a/web/src/hooks/useTx.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { useCallback, useState } from "react"; -import { useAccount, usePublicClient, useSwitchChain, useWalletClient } from "wagmi"; -import { getWalletClient } from "wagmi/actions"; -import { wagmiConfig } from "../wagmi"; -import type { Abi } from "viem"; -import { describeError } from "../lib/errors"; -import { arkDevnet } from "../config/chain"; - -export type TxState = - | { phase: "idle" } - | { phase: "simulating" } - | { phase: "signing" } - | { phase: "mining"; hash: `0x${string}` } - | { phase: "done"; hash: `0x${string}` } - | { phase: "error"; message: string }; - -/** - * Simulate, sign, wait. Simulation runs first so a policy refusal surfaces as a readable custom error - * before the wallet ever asks for a signature (human-readable intent before signing). - */ -export function useTx(onDone?: () => void) { - const { data: walletForChain } = useWalletClient({ chainId: arkDevnet.id }); - const { isConnected, chainId } = useAccount(); - const { switchChainAsync } = useSwitchChain(); - const client = usePublicClient(); - const [state, setState] = useState({ phase: "idle" }); - - const send = useCallback( - async (args: { address: `0x${string}`; abi: Abi; functionName: string; args?: readonly unknown[]; value?: bigint }) => { - if (!client || !isConnected) { - setState({ phase: "error", message: "Connect a wallet to continue." }); - return; - } - let wallet = walletForChain; - // A connected wallet on another network yields no client for this chain: ask it to switch first. - if (!wallet || chainId !== arkDevnet.id) { - try { - setState({ phase: "signing" }); - await switchChainAsync({ chainId: arkDevnet.id }); - wallet = await getWalletClient(wagmiConfig, { chainId: arkDevnet.id }); - } catch { - setState({ phase: "error", message: `Your wallet is on another network. Switch it to Ark Constellation devnet (chain ${arkDevnet.id}) and try again.` }); - return; - } - } - try { - setState({ phase: "simulating" }); - const { request } = await client.simulateContract({ - ...args, - account: wallet.account, - chain: arkDevnet, - } as Parameters[0]); - setState({ phase: "signing" }); - const hash = await wallet.writeContract(request); - setState({ phase: "mining", hash }); - await client.waitForTransactionReceipt({ hash }); - setState({ phase: "done", hash }); - onDone?.(); - } catch (e) { - setState({ phase: "error", message: describeError(e) }); - } - }, - [walletForChain, client, isConnected, chainId, switchChainAsync, onDone], - ); - - const reset = useCallback(() => setState({ phase: "idle" }), []); - return { state, send, reset, busy: state.phase === "simulating" || state.phase === "signing" || state.phase === "mining" }; -} - -export { describeError } from "../lib/errors"; diff --git a/web/src/hooks/useVault.ts b/web/src/hooks/useVault.ts deleted file mode 100644 index bc92ddc..0000000 --- a/web/src/hooks/useVault.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { usePublicClient } from "wagmi"; -import type { PublicClient } from "viem"; -import { fetchActivity, fetchCore, type VaultActivity, type VaultData } from "../lib/vaultReads"; - -export type { Member, ProposalView, VelocityView, RecipientView, VaultCore, VaultActivity, VaultData } from "../lib/vaultReads"; - -export function vaultQueryKey(address: `0x${string}` | null) { - return ["vault", address] as const; -} - -const EMPTY_ACTIVITY: VaultActivity = { proposals: [], recipients: [], logsFailed: false, policyHistory: [], modeHistory: [] }; - -/** - * Two queries so the interface paints as soon as balances and policy arrive, then fills in the - * queue and history. Both refresh on an interval and are invalidated together after a write. - */ -export function useVault(address: `0x${string}` | null): { data: VaultData | undefined; error: unknown; isLoading: boolean } { - const client = usePublicClient(); - const core = useQuery({ - queryKey: [...vaultQueryKey(address), "core"], - queryFn: () => fetchCore(client as PublicClient, address as `0x${string}`), - enabled: Boolean(address && client), - refetchInterval: 20_000, - staleTime: 10_000, - }); - const activity = useQuery({ - queryKey: [...vaultQueryKey(address), "activity", core.data?.proposalCount ?? -1], - queryFn: () => fetchActivity(client as PublicClient, address as `0x${string}`, core.data?.proposalCount ?? 0, core.data?.blockNumber ?? 0n), - enabled: Boolean(address && client && core.data), - refetchInterval: 30_000, - staleTime: 15_000, - placeholderData: (prev) => prev, - }); - const data: VaultData | undefined = core.data - ? { ...core.data, ...(activity.data ?? EMPTY_ACTIVITY), activityLoading: !activity.data, fetchedAt: core.dataUpdatedAt } - : undefined; - return { data, error: core.error ?? activity.error, isLoading: core.isLoading }; -} - -/** - * Refresh after a write. The devnet RPC sits behind replicas that can lag a mined receipt by several - * seconds, so one refetch straight after the receipt often reads the old state; a few bounded - * follow-ups catch up without waiting for the regular interval. - */ -export function useInvalidateVault(address: `0x${string}` | null) { - const qc = useQueryClient(); - return () => { - const key = vaultQueryKey(address); - void qc.invalidateQueries({ queryKey: key }); - for (const ms of [6_000, 15_000, 30_000]) setTimeout(() => void qc.invalidateQueries({ queryKey: key }), ms); - }; -} diff --git a/web/src/lib/errors.ts b/web/src/lib/errors.ts deleted file mode 100644 index 7db037a..0000000 --- a/web/src/lib/errors.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { BaseError, ContractFunctionRevertedError } from "viem"; - -/** Maps the vault's custom errors to plain language. Shared by web and mobile. */ -const ERROR_TEXT: Record string> = { - NotAuthorized: (a) => `Your wallet does not hold the required role (${roleText(Number(a[0]))}).`, - VaultLocked: () => "The vault is in Lockdown. Outgoing payments and security-reducing changes are blocked until it is lowered.", - Timelocked: (a) => `This cannot execute before ${new Date(Number(a[0]) * 1000).toLocaleString()}.`, - InsufficientApprovals: (a) => `${a[0]} of the required ${a[1]} approvals are in place.`, - InsufficientGuardians: (a) => `${a[0]} of the required ${a[1]} guardian confirmations are in place.`, - PerTxLimitExceeded: () => "This amount is above the per-transaction cap for the asset.", - VelocityExceeded: () => "This would push today's outflow past the 24-hour cap for the asset.", - ExposureHardBlocked: (a) => `This would move ${Number(a[0]) / 100}% of holdings; the policy refuses anything above ${Number(a[1]) / 100}%.`, - RecipientBlocked: () => "This recipient is blocked by policy.", - AssetNotApproved: () => "This asset is not on the vault's approved list.", - AlreadyApproved: () => "You have already confirmed this proposal.", - NotPending: () => "This proposal is no longer open.", - ProposalExpired: () => "This proposal has expired.", - NotVetoable: () => "Guardians cannot veto this proposal: it is neither critical, probationary nor security-reducing.", - ModeNotStricter: () => "The mode can only be raised directly. Lowering it goes through governance.", - ModeNotRelaxation: () => "That mode is not lower than the current one.", - InvalidPolicy: (a) => `Invalid policy: ${String(a[0])}.`, - ThresholdUnsatisfiable: (a) => `Thresholds would be unsatisfiable: ${String(a[0])}.`, - InvalidProposal: (a) => `Invalid proposal: ${String(a[0])}.`, - InvalidRoles: () => "Guardians cannot hold treasury roles, and roles must be valid.", - MemberExists: () => "That address is already a member.", - NotMember: () => "That address is not a member.", - InsufficientBalance: () => "The vault does not hold enough of this asset right now.", - AmountZero: () => "Amount must be greater than zero.", - ZeroAddress: () => "Address cannot be empty.", - NotCancellable: () => "Only the proposer or an owner can cancel this.", -}; - -function roleText(bits: number): string { - const n: string[] = []; - if (bits & 1) n.push("Owner"); - if (bits & 2) n.push("Approver"); - if (bits & 4) n.push("Executor"); - if (bits & 8) n.push("Guardian"); - return n.join(" or ") || "unknown"; -} - -export function describeError(e: unknown): string { - if (e instanceof BaseError) { - const revert = e.walk((err) => err instanceof ContractFunctionRevertedError) as ContractFunctionRevertedError | null; - if (revert?.data) { - const name = revert.data.errorName; - const f = ERROR_TEXT[name]; - if (f) return f(revert.data.args ?? []); - return `${name}(${(revert.data.args ?? []).map(String).join(", ")})`; - } - return e.shortMessage; - } - return e instanceof Error ? e.message : String(e); -} diff --git a/web/src/lib/format.ts b/web/src/lib/format.ts deleted file mode 100644 index fd45e11..0000000 --- a/web/src/lib/format.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { formatUnits, parseUnits } from "viem"; - -export function short(addr: string, n = 4): string { - if (!addr) return ""; - return `${addr.slice(0, 2 + n)}…${addr.slice(-n)}`; -} - -export function fmtAmount(value: bigint, decimals: number, symbol?: string, maxFrac = 2): string { - const s = formatUnits(value, decimals); - const [int, frac = ""] = s.split("."); - const intFmt = Number(int).toLocaleString("en-US"); - const fracTrim = frac.slice(0, maxFrac).replace(/0+$/, ""); - const out = fracTrim ? `${intFmt}.${fracTrim}` : intFmt; - return symbol ? `${out} ${symbol}` : out; -} - -export function parseAmount(text: string, decimals: number): bigint | null { - try { - const cleaned = text.replace(/,/g, "").trim(); - if (!cleaned) return null; - return parseUnits(cleaned, decimals); - } catch { - return null; - } -} - -export function fmtBps(bps: number): string { - return `${(bps / 100).toFixed(bps % 100 === 0 ? 0 : 2)}%`; -} - -export function fmtDuration(seconds: number): string { - if (seconds <= 0) return "none"; - const d = Math.floor(seconds / 86400); - const h = Math.floor((seconds % 86400) / 3600); - const m = Math.floor((seconds % 3600) / 60); - const parts: string[] = []; - if (d) parts.push(`${d}d`); - if (h) parts.push(`${h}h`); - if (m && !d) parts.push(`${m}m`); - return parts.join(" ") || `${seconds}s`; -} - -export function fmtDate(ts: bigint | number): string { - const n = Number(ts); - if (!n) return "—"; - return new Date(n * 1000).toLocaleString("en-US", { dateStyle: "medium", timeStyle: "short" }); -} - -export function fmtRelative(ts: bigint | number, now = Date.now() / 1000): string { - const n = Number(ts); - if (!n) return "—"; - const diff = n - now; - if (Math.abs(diff) < 60) return diff >= 0 ? "now" : "just now"; - const abs = fmtDuration(Math.abs(Math.round(diff))); - return diff > 0 ? `in ${abs}` : `${abs} ago`; -} - -export function nowSec(): number { - return Math.floor(Date.now() / 1000); -} diff --git a/web/src/lib/maxLoss.ts b/web/src/lib/maxLoss.ts deleted file mode 100644 index 2e19360..0000000 --- a/web/src/lib/maxLoss.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Mode, Tier, type AssetLimits, type Policy } from "./types"; -import { effectiveCaps } from "./risk"; - -/** - * Maximum possible loss, per asset, translated from a policy into numbers a finance team understands. - * Conservative by construction: it assumes every signer needed for a tier is compromised and that the - * attacker chooses amounts optimally. It is an upper bound under the stated assumptions, never a guarantee. - */ -export type MaxLoss = { - /** Largest amount that can leave without any delay (LOW-tier transfers, repeated until a cap binds). */ - immediate: bigint; - /** Amount that can leave within 24h if only approvers are compromised and no guardian acts. */ - day: bigint; - /** Seconds a CRITICAL transfer must wait, i.e. how long guardians have to veto the largest transfers. */ - criticalDelay: number; - highDelay: number; - /** Which control produced each number. */ - immediateBinding: string; - dayBinding: string; - assumptions: string[]; -}; - -export function computeMaxLoss(policy: Policy, limits: AssetLimits, balance: bigint, mode: Mode): MaxLoss { - const caps = effectiveCaps(limits.perTxMax, limits.dailyMax, mode); - const assumptions = [ - "Enough approvers to satisfy each tier are compromised and cooperate.", - "Executors are compromised or collude.", - "No guardian vetoes or freezes during the delay windows.", - "Recipients used by the attacker are already activated (not in probation).", - "Limits are per asset; each asset has its own envelope and caps.", - ]; - - // --- immediate: LOW-tier transfers need no delay. Each is at most lowMax (or exposure-bounded). - // An attacker repeats them until the daily cap or envelope binds. In Elevated mode LOW is impossible. - let immediate = 0n; - let immediateBinding = "no undelayed tier"; - if (mode === Mode.NORMAL) { - const exposureLow = policy.highExposureBps === 0 ? balance : (balance * BigInt(policy.highExposureBps - 1)) / 10_000n; - const perTransfer = min(limits.lowMax, caps.perTxMax || limits.lowMax, exposureLow); - if (perTransfer > 0n) { - immediate = balance; - immediateBinding = "entire balance (no daily cap or envelope)"; - const envelope = policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10_000n; - if (caps.dailyMax !== 0n && caps.dailyMax < immediate) { - immediate = caps.dailyMax; - immediateBinding = "daily cap"; - } - if (envelope !== 0n && envelope < immediate) { - immediate = envelope; - immediateBinding = "loss envelope"; - } - } else { - immediate = 0n; - immediateBinding = "routine tier disabled by limits"; - } - } - - // --- 24h: approvers can also push HIGH-tier transfers if delayHigh < 24h. Still bounded by caps. - let day = 0n; - let dayBinding = "no path"; - const highReachable = policy.delayHigh < 86_400; - const envelope = policy.envelopeBps === 0 ? 0n : (balance * BigInt(policy.envelopeBps)) / 10_000n; - const perTx = caps.perTxMax === 0n ? balance : caps.perTxMax; - const highCeiling = policy.criticalExposureBps === 0 ? balance : (balance * BigInt(policy.criticalExposureBps - 1)) / 10_000n; - const candidates: Array<[bigint, string]> = []; - candidates.push([balance, "entire balance"]); - if (caps.dailyMax !== 0n) candidates.push([caps.dailyMax * 2n, "two daily buckets across a boundary"]); - if (envelope !== 0n) candidates.push([envelope * 2n, "two envelope windows across a boundary"]); - if (!highReachable) { - // Only LOW transfers fit in 24h; each is at most lowMax and the tier is bounded by exposure. - candidates.push([immediate * 2n, "routine tier only, two buckets"]); - } else { - candidates.push([min(perTx, highCeiling) === 0n ? 0n : balance, "high tier reachable within 24h"]); - } - [day, dayBinding] = candidates.reduce((a, b) => (b[0] < a[0] ? b : a)); - if (mode === Mode.LOCKDOWN) { - immediate = 0n; - day = 0n; - immediateBinding = "vault is in Lockdown"; - dayBinding = "vault is in Lockdown"; - } - return { - immediate, - day, - criticalDelay: policy.delayCritical, - highDelay: policy.delayHigh, - immediateBinding, - dayBinding, - assumptions, - }; -} - -function min(...xs: bigint[]): bigint { - return xs.reduce((a, b) => (b < a ? b : a)); -} - -export { Tier }; diff --git a/web/src/lib/motion.ts b/web/src/lib/motion.ts deleted file mode 100644 index f1138c7..0000000 --- a/web/src/lib/motion.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useEffect, useRef, useState } from "react"; - -/** Adds the `in` class when the element scrolls into view, once. Pairs with .reveal / .reveal-stagger. */ -export function useReveal(threshold = 0.15) { - const ref = useRef(null); - useEffect(() => { - const el = ref.current; - if (!el) return; - if (typeof IntersectionObserver === "undefined") { - el.classList.add("in"); - return; - } - const io = new IntersectionObserver( - (entries) => { - for (const e of entries) { - if (e.isIntersecting) { - el.classList.add("in"); - io.disconnect(); - } - } - }, - { threshold, rootMargin: "0px 0px -8% 0px" }, - ); - io.observe(el); - return () => io.disconnect(); - }, [threshold]); - return ref; -} - -/** Counts from 0 to `target` once visible. */ -export function useCountUp(target: number, durationMs = 1200) { - const ref = useRef(null); - const [value, setValue] = useState(0); - useEffect(() => { - const el = ref.current; - if (!el) return; - const reduce = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches; - if (reduce || typeof IntersectionObserver === "undefined") { - setValue(target); - return; - } - let raf = 0; - const io = new IntersectionObserver((entries) => { - if (!entries.some((e) => e.isIntersecting)) return; - io.disconnect(); - const start = performance.now(); - const tick = (now: number) => { - const t = Math.min(1, (now - start) / durationMs); - const eased = 1 - Math.pow(1 - t, 3); - setValue(Math.round(target * eased)); - if (t < 1) raf = requestAnimationFrame(tick); - }; - raf = requestAnimationFrame(tick); - }); - io.observe(el); - return () => { - io.disconnect(); - cancelAnimationFrame(raf); - }; - }, [target, durationMs]); - return { ref, value }; -} - -/** True once the window has scrolled past `px`. Used for the sticky nav's shadow. */ -export function useScrolled(px = 8) { - const [scrolled, setScrolled] = useState(false); - useEffect(() => { - const onScroll = () => setScrolled(window.scrollY > px); - onScroll(); - window.addEventListener("scroll", onScroll, { passive: true }); - return () => window.removeEventListener("scroll", onScroll); - }, [px]); - return scrolled; -} diff --git a/web/src/lib/policy.ts b/web/src/lib/policy.ts deleted file mode 100644 index 2612cd2..0000000 --- a/web/src/lib/policy.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type { AssetLimits, Policy } from "./types"; - -/** Mirror of contracts/src/SkurPolicyLib.sol. The contract decides; this only previews. */ -const MIN_EXECUTION_WINDOW = 3600; -const BPS = 10_000; - -export function validatePolicy(p: Policy): string[] { - const errs: string[] = []; - if (p.approvalsLow === 0) errs.push("Low-tier approvals must be at least 1."); - if (p.approvalsHigh < p.approvalsLow) errs.push("High-tier approvals cannot be lower than low-tier approvals."); - if (p.approvalsCritical < p.approvalsHigh) errs.push("Critical-tier approvals cannot be lower than high-tier approvals."); - if (p.governanceThreshold === 0) errs.push("Governance threshold must be at least 1."); - if (p.guardianRequiredCritical && p.guardianThreshold === 0) errs.push("Guardian confirmation is required but the guardian threshold is 0."); - if (p.delayCritical < p.delayHigh) errs.push("Critical delay cannot be shorter than high delay."); - if (p.criticalExposureBps !== 0 && p.highExposureBps > p.criticalExposureBps) errs.push("High exposure threshold must not exceed the critical one."); - if (p.criticalExposureBps > BPS || p.highExposureBps > BPS) errs.push("Exposure thresholds must be at most 100%."); - if (p.hardBlockExposureBps !== 0 && p.hardBlockExposureBps < p.criticalExposureBps) errs.push("Hard block must not be below the critical exposure threshold."); - if (p.hardBlockExposureBps > BPS) errs.push("Hard block must be at most 100%."); - if (p.envelopeBps > BPS) errs.push("Envelope must be at most 100%."); - if (p.envelopeBps !== 0 && p.envelopeWindow < MIN_EXECUTION_WINDOW) errs.push("Envelope window must be at least one hour."); - const longest = Math.max(p.delayCritical, p.policyChangeDelay, p.recoveryDelay, p.recipientActivationDelay); - if (p.proposalTtl < longest + MIN_EXECUTION_WINDOW) errs.push("Proposal lifetime must exceed the longest delay by at least one hour."); - return errs; -} - -export function validateLimits(l: AssetLimits): string[] { - const errs: string[] = []; - if (l.lowMax > l.highMax) errs.push("Routine maximum cannot exceed the high maximum."); - if (l.perTxMax !== 0n && l.dailyMax !== 0n && l.perTxMax > l.dailyMax) errs.push("Per-transaction cap cannot exceed the daily cap."); - return errs; -} - -export function validateCounts(p: Policy, owners: number, approvers: number, executors: number, guardians: number): string[] { - const errs: string[] = []; - if (owners < 1) errs.push("At least one owner is required."); - if (executors < 1) errs.push("At least one executor is required."); - if (owners < p.governanceThreshold) errs.push(`Governance threshold (${p.governanceThreshold}) exceeds the number of owners (${owners}).`); - if (approvers < p.approvalsCritical) errs.push(`Critical approvals (${p.approvalsCritical}) exceed the number of approvers (${approvers}).`); - if (guardians < p.guardianThreshold) errs.push(`Guardian threshold (${p.guardianThreshold}) exceeds the number of guardians (${guardians}).`); - return errs; -} - -function thresholdLoosens(a: number, b: number): boolean { - if (a === 0) return false; - if (b === 0) return true; - return b > a; -} - -function capLoosens(a: bigint, b: bigint): boolean { - if (a === 0n) return false; - if (b === 0n) return true; - return b > a; -} - -/** Returns the list of fields that weaken security (empty means the change is tightening-only). */ -export function policyReductions(a: Policy, b: Policy): string[] { - const out: string[] = []; - if (b.approvalsLow < a.approvalsLow) out.push("fewer approvals for routine transfers"); - if (b.approvalsHigh < a.approvalsHigh) out.push("fewer approvals for high-risk transfers"); - if (b.approvalsCritical < a.approvalsCritical) out.push("fewer approvals for critical transfers"); - if (b.governanceThreshold < a.governanceThreshold) out.push("lower governance threshold"); - if (b.guardianThreshold < a.guardianThreshold) out.push("fewer guardian confirmations"); - if (a.guardianRequiredCritical && !b.guardianRequiredCritical) out.push("guardian no longer required for critical transfers"); - if (b.delayHigh < a.delayHigh) out.push("shorter high-risk delay"); - if (b.delayCritical < a.delayCritical) out.push("shorter critical delay"); - if (b.recipientActivationDelay < a.recipientActivationDelay) out.push("shorter new-recipient delay"); - if (b.policyChangeDelay < a.policyChangeDelay) out.push("shorter policy-change delay"); - if (b.recoveryDelay < a.recoveryDelay) out.push("shorter recovery delay"); - if (b.proposalTtl > a.proposalTtl) out.push("longer proposal lifetime"); - if (thresholdLoosens(a.highExposureBps, b.highExposureBps)) out.push("higher exposure threshold for escalation"); - if (thresholdLoosens(a.criticalExposureBps, b.criticalExposureBps)) out.push("higher exposure threshold for critical"); - if (thresholdLoosens(a.hardBlockExposureBps, b.hardBlockExposureBps)) out.push("weaker exposure hard block"); - if (thresholdLoosens(a.envelopeBps, b.envelopeBps)) out.push("larger loss envelope"); - if (a.envelopeBps !== 0 && b.envelopeWindow < a.envelopeWindow) out.push("shorter envelope window"); - return out; -} - -export function limitReductions(a: AssetLimits, b: AssetLimits): string[] { - const out: string[] = []; - if (!a.approved && b.approved) out.push("approving a new asset"); - if (b.lowMax > a.lowMax) out.push("higher routine maximum"); - if (b.highMax > a.highMax) out.push("higher high-tier maximum"); - if (capLoosens(a.perTxMax, b.perTxMax)) out.push("weaker per-transaction cap"); - if (capLoosens(a.dailyMax, b.dailyMax)) out.push("weaker daily cap"); - return out; -} - -export function policyToContract(p: Policy) { - return { - approvalsLow: p.approvalsLow, - approvalsHigh: p.approvalsHigh, - approvalsCritical: p.approvalsCritical, - governanceThreshold: p.governanceThreshold, - guardianThreshold: p.guardianThreshold, - guardianRequiredCritical: p.guardianRequiredCritical, - delayHigh: p.delayHigh, - delayCritical: p.delayCritical, - recipientActivationDelay: p.recipientActivationDelay, - policyChangeDelay: p.policyChangeDelay, - recoveryDelay: p.recoveryDelay, - proposalTtl: p.proposalTtl, - highExposureBps: p.highExposureBps, - criticalExposureBps: p.criticalExposureBps, - hardBlockExposureBps: p.hardBlockExposureBps, - envelopeBps: p.envelopeBps, - envelopeWindow: p.envelopeWindow, - } as const; -} - -export function policyFromContract(raw: Record): Policy { - const n = (k: string) => Number(raw[k] ?? 0); - return { - approvalsLow: n("approvalsLow"), - approvalsHigh: n("approvalsHigh"), - approvalsCritical: n("approvalsCritical"), - governanceThreshold: n("governanceThreshold"), - guardianThreshold: n("guardianThreshold"), - guardianRequiredCritical: Boolean(raw.guardianRequiredCritical), - delayHigh: n("delayHigh"), - delayCritical: n("delayCritical"), - recipientActivationDelay: n("recipientActivationDelay"), - policyChangeDelay: n("policyChangeDelay"), - recoveryDelay: n("recoveryDelay"), - proposalTtl: n("proposalTtl"), - highExposureBps: n("highExposureBps"), - criticalExposureBps: n("criticalExposureBps"), - hardBlockExposureBps: n("hardBlockExposureBps"), - envelopeBps: n("envelopeBps"), - envelopeWindow: n("envelopeWindow"), - }; -} diff --git a/web/src/lib/policyFields.ts b/web/src/lib/policyFields.ts deleted file mode 100644 index d7db8ac..0000000 --- a/web/src/lib/policyFields.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { Policy } from "./types"; - -/** Policy editor field definitions, shared by the web and mobile editors. */ -export const H = 3600; -export type Unit = "count" | "hours" | "bps" | "bool"; -export type PolicyField = { key: keyof Policy; label: string; hint: string; unit: Unit; max?: number }; - -export const POLICY_GROUPS: Array<{ title: string; sub: string; fields: PolicyField[] }> = [ - { - title: "Approvals", - sub: "How many confirmations each tier needs. Guardians confirm critical transfers in addition to approvers.", - fields: [ - { key: "approvalsLow", label: "Low tier", hint: "Routine payments under the routine threshold.", unit: "count" }, - { key: "approvalsHigh", label: "High tier", hint: "Larger payments, new recipients, elevated posture.", unit: "count" }, - { key: "approvalsCritical", label: "Critical tier", hint: "Very large or high-exposure payments.", unit: "count" }, - { key: "guardianRequiredCritical", label: "Guardian required for Critical", hint: "An independent sign-off on the largest transfers.", unit: "bool" }, - { key: "guardianThreshold", label: "Guardian confirmations", hint: "For critical transfers, leaving Lockdown and recovery.", unit: "count" }, - { key: "governanceThreshold", label: "Owner approvals for governance", hint: "Policy, limits, members, trust, mode changes.", unit: "count" }, - ], - }, - { - title: "Delays", - sub: "A delay gives guardians a veto window and gives the organisation time to notice.", - fields: [ - { key: "delayHigh", label: "High-tier delay", hint: "Between full approval and execution.", unit: "hours" }, - { key: "delayCritical", label: "Critical delay", hint: "Also the guardian veto window.", unit: "hours" }, - { key: "recipientActivationDelay", label: "New-recipient activation", hint: "A never-seen address cannot be paid sooner.", unit: "hours" }, - { key: "policyChangeDelay", label: "Security-reducing change delay", hint: "Any loosening waits this long and can be vetoed.", unit: "hours" }, - { key: "recoveryDelay", label: "Recovery delay", hint: "Owners can cancel a recovery during it.", unit: "hours" }, - { key: "proposalTtl", label: "Proposal lifetime", hint: "Must exceed the longest delay by at least 1h.", unit: "hours" }, - ], - }, - { - title: "Exposure", - sub: "Share of the asset's holdings that a single payment may move before it is escalated or refused.", - fields: [ - { key: "highExposureBps", label: "Escalate to High at", hint: "Percent of holdings.", unit: "bps", max: 100 }, - { key: "criticalExposureBps", label: "Escalate to Critical at", hint: "", unit: "bps", max: 100 }, - { key: "hardBlockExposureBps", label: "Refuse above", hint: "0 disables the hard block.", unit: "bps", max: 100 }, - ], - }, - { - title: "Circuit breaker", - sub: "Cumulative outflow per window as a share of holdings. The transfer that would exceed it is not paid; the vault enters Lockdown.", - fields: [ - { key: "envelopeBps", label: "Loss envelope", hint: "0 disables the breaker.", unit: "bps", max: 100 }, - { key: "envelopeWindow", label: "Envelope window", hint: "At least 1 hour.", unit: "hours" }, - ], - }, -]; - diff --git a/web/src/lib/posture.ts b/web/src/lib/posture.ts deleted file mode 100644 index a8d21be..0000000 --- a/web/src/lib/posture.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { fmtDuration } from "./format"; -import type { VaultData } from "./vaultReads"; - -/** Plain-language posture checks shared by the web and mobile interfaces. */ -export type PostureItem = { ok: "ok" | "warn" | "bad"; text: string }; - -export function postureItems(vault: VaultData): PostureItem[] { - const p = vault.policy; - const g = vault.counts.guardians; - return [ - { ok: g > 0 ? "ok" : "bad", text: g > 0 ? `${g} independent guardian${g === 1 ? "" : "s"} configured` : "No guardian: nobody independent can veto or freeze" }, - { ok: p.guardianRequiredCritical ? "ok" : "warn", text: p.guardianRequiredCritical ? "Critical transfers need guardian confirmation" : "Critical transfers do not need a guardian" }, - { ok: p.delayCritical >= 24 * 3600 ? "ok" : "warn", text: `Critical delay ${fmtDuration(p.delayCritical)}` }, - { ok: p.recipientActivationDelay > 0 ? "ok" : "bad", text: p.recipientActivationDelay > 0 ? `New recipients wait ${fmtDuration(p.recipientActivationDelay)}` : "New recipients can be paid immediately" }, - { ok: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "ok" : "warn", text: vault.assets.every((a) => a.limits.dailyMax > 0n) ? "24h outflow cap on every asset" : "Some assets have no 24h cap" }, - { ok: p.envelopeBps > 0 ? "ok" : "warn", text: p.envelopeBps > 0 ? `Circuit breaker at ${p.envelopeBps / 100}% per ${fmtDuration(p.envelopeWindow)}` : "No loss envelope configured" }, - { ok: p.policyChangeDelay > 0 ? "ok" : "bad", text: p.policyChangeDelay > 0 ? `Security-reducing changes wait ${fmtDuration(p.policyChangeDelay)}` : "Policy can be weakened instantly" }, - { ok: p.recoveryDelay > 0 && g > 0 ? "ok" : "warn", text: `Recovery configured (${fmtDuration(p.recoveryDelay)} delay)` }, - { ok: p.approvalsLow >= 2 ? "ok" : "warn", text: p.approvalsLow >= 2 ? "Routine payments need two approvals" : "Routine payments need a single approval" }, - ]; -} - diff --git a/web/src/lib/risk.test.ts b/web/src/lib/risk.test.ts deleted file mode 100644 index f08b61a..0000000 --- a/web/src/lib/risk.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { classify, exposureBps, requirements, type RiskInput } from "./risk"; -import { - Mode, - REASON_AMOUNT_CRITICAL, - REASON_AMOUNT_HIGH, - REASON_EXPOSURE_CRITICAL, - REASON_EXPOSURE_HIGH, - REASON_MODE_ELEVATED, - REASON_RECIPIENT_PROBATION, - REASON_RECIPIENT_RESTRICTED, - REASON_RECIPIENT_UNKNOWN, - REASON_VELOCITY_PRESSURE, - Tier, - Trust, -} from "./types"; - -const USD = 1_000_000n; - -function base(): RiskInput { - return { - amount: 1_000n * USD, - assetBalance: 1_000_000n * USD, - lowMax: 5_000n * USD, - highMax: 25_000n * USD, - dailyMax: 100_000n * USD, - daySpent: 0n, - trust: Trust.VERIFIED, - inProbation: false, - mode: Mode.NORMAL, - highExposureBps: 500, - criticalExposureBps: 2000, - }; -} - -/** Same vectors as contracts/test/SkurRisk.t.sol. */ -describe("risk engine mirror", () => { - it("routine supplier payment is LOW", () => { - const r = classify(base()); - expect(r).toEqual({ tier: Tier.LOW, reasons: 0, exposureBps: 10 }); - }); - - it("amount above lowMax is HIGH", () => { - const r = classify({ ...base(), amount: 10_000n * USD }); - expect(r.tier).toBe(Tier.HIGH); - expect(r.reasons).toBe(REASON_AMOUNT_HIGH); - }); - - it("amount above highMax is CRITICAL", () => { - const r = classify({ ...base(), amount: 30_000n * USD }); - expect(r.tier).toBe(Tier.CRITICAL); - expect(r.reasons).toBe(REASON_AMOUNT_CRITICAL); - }); - - it("exposure escalates a small treasury", () => { - const r = classify({ ...base(), assetBalance: 50_000n * USD, amount: 4_000n * USD, dailyMax: 0n }); - expect(r).toEqual({ tier: Tier.HIGH, reasons: REASON_EXPOSURE_HIGH, exposureBps: 800 }); - }); - - it("exposure critical", () => { - const r = classify({ ...base(), assetBalance: 20_000n * USD, amount: 4_000n * USD, dailyMax: 0n }); - expect(r).toEqual({ tier: Tier.CRITICAL, reasons: REASON_EXPOSURE_CRITICAL, exposureBps: 2000 }); - }); - - it("new recipient bumps one tier", () => { - let r = classify({ ...base(), trust: Trust.NEW, inProbation: true }); - expect(r.tier).toBe(Tier.HIGH); - expect(r.reasons).toBe(REASON_RECIPIENT_PROBATION); - r = classify({ ...base(), trust: Trust.NEW, inProbation: true, amount: 10_000n * USD }); - expect(r.tier).toBe(Tier.CRITICAL); - expect(r.reasons).toBe(REASON_AMOUNT_HIGH | REASON_RECIPIENT_PROBATION); - }); - - it("unknown recipient treated as probation", () => { - const r = classify({ ...base(), trust: Trust.UNKNOWN }); - expect(r.tier).toBe(Tier.HIGH); - expect(r.reasons).toBe(REASON_RECIPIENT_UNKNOWN | REASON_RECIPIENT_PROBATION); - }); - - it("activated new recipient is normal", () => { - const r = classify({ ...base(), trust: Trust.NEW, inProbation: false }); - expect(r).toMatchObject({ tier: Tier.LOW, reasons: 0 }); - }); - - it("restricted recipient always critical", () => { - const r = classify({ ...base(), trust: Trust.RESTRICTED }); - expect(r).toMatchObject({ tier: Tier.CRITICAL, reasons: REASON_RECIPIENT_RESTRICTED }); - }); - - it("velocity pressure", () => { - const r = classify({ ...base(), daySpent: 49_500n * USD }); - expect(r).toMatchObject({ tier: Tier.HIGH, reasons: REASON_VELOCITY_PRESSURE }); - }); - - it("elevated mode bumps", () => { - const r = classify({ ...base(), mode: Mode.ELEVATED }); - expect(r).toMatchObject({ tier: Tier.HIGH, reasons: REASON_MODE_ELEVATED }); - }); - - it("worst case stacks", () => { - const r = classify({ - ...base(), - amount: 30_000n * USD, - assetBalance: 100_000n * USD, - trust: Trust.UNKNOWN, - mode: Mode.ELEVATED, - }); - expect(r.tier).toBe(Tier.CRITICAL); - expect(r.exposureBps).toBe(3000); - expect(r.reasons).toBe( - REASON_AMOUNT_CRITICAL | - REASON_EXPOSURE_CRITICAL | - REASON_RECIPIENT_UNKNOWN | - REASON_RECIPIENT_PROBATION | - REASON_MODE_ELEVATED, - ); - }); - - it("exposure edges", () => { - expect(exposureBps(0n, 100n)).toBe(0); - expect(exposureBps(1n, 0n)).toBe(10_000); - expect(exposureBps(100n, 100n)).toBe(10_000); - expect(exposureBps(150n, 100n)).toBe(10_000); - expect(exposureBps(1n, 100n)).toBe(100); - expect(exposureBps(1n, 30_000n)).toBe(0); - }); - - it("requirements per tier", () => { - const p = { - approvalsLow: 1, - approvalsHigh: 2, - approvalsCritical: 3, - governanceThreshold: 2, - guardianThreshold: 2, - guardianRequiredCritical: true, - delayHigh: 21600, - delayCritical: 86400, - recipientActivationDelay: 0, - policyChangeDelay: 0, - recoveryDelay: 0, - proposalTtl: 0, - highExposureBps: 0, - criticalExposureBps: 0, - hardBlockExposureBps: 0, - envelopeBps: 0, - envelopeWindow: 0, - }; - expect(requirements(p, Tier.LOW)).toEqual({ approvals: 1, guardians: 0, delay: 0 }); - expect(requirements(p, Tier.HIGH)).toEqual({ approvals: 2, guardians: 0, delay: 21600 }); - expect(requirements(p, Tier.CRITICAL)).toEqual({ approvals: 3, guardians: 2, delay: 86400 }); - expect(requirements({ ...p, guardianRequiredCritical: false }, Tier.CRITICAL).guardians).toBe(0); - }); -}); diff --git a/web/src/lib/risk.ts b/web/src/lib/risk.ts deleted file mode 100644 index 67a5c2d..0000000 --- a/web/src/lib/risk.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - BPS, - Mode, - REASON_AMOUNT_CRITICAL, - REASON_AMOUNT_HIGH, - REASON_EXPOSURE_CRITICAL, - REASON_EXPOSURE_HIGH, - REASON_MODE_ELEVATED, - REASON_RECIPIENT_PROBATION, - REASON_RECIPIENT_RESTRICTED, - REASON_RECIPIENT_UNKNOWN, - REASON_VELOCITY_PRESSURE, - Tier, - Trust, - type Policy, -} from "./types"; - -/** - * TypeScript mirror of contracts/src/SkurRisk.sol. - * Used only for the policy simulator and for previewing policies that are not deployed yet. - * For a live vault the interface calls `previewTransfer` on the contract, which is authoritative. - * test/SkurRisk.t.sol and risk.test.ts pin the same vectors. - */ -export type RiskInput = { - amount: bigint; - assetBalance: bigint; - lowMax: bigint; - highMax: bigint; - dailyMax: bigint; - daySpent: bigint; - trust: Trust; - inProbation: boolean; - mode: Mode; - highExposureBps: number; - criticalExposureBps: number; -}; - -export type RiskOutput = { tier: Tier; reasons: number; exposureBps: number }; - -export function exposureBps(amount: bigint, balance: bigint): number { - if (amount === 0n) return 0; - if (balance === 0n || amount >= balance) return Number(BPS); - return Number((amount * BPS) / balance); -} - -function bump(t: Tier): Tier { - return t === Tier.LOW ? Tier.HIGH : Tier.CRITICAL; -} - -function atLeast(t: Tier, floor: Tier): Tier { - return t >= floor ? t : floor; -} - -export function classify(i: RiskInput): RiskOutput { - let tier = Tier.LOW; - let reasons = 0; - - if (i.amount > i.highMax) { - tier = Tier.CRITICAL; - reasons |= REASON_AMOUNT_CRITICAL; - } else if (i.amount > i.lowMax) { - tier = Tier.HIGH; - reasons |= REASON_AMOUNT_HIGH; - } - - const exposure = exposureBps(i.amount, i.assetBalance); - if (i.criticalExposureBps !== 0 && exposure >= i.criticalExposureBps) { - tier = Tier.CRITICAL; - reasons |= REASON_EXPOSURE_CRITICAL; - } else if (i.highExposureBps !== 0 && exposure >= i.highExposureBps) { - tier = atLeast(tier, Tier.HIGH); - reasons |= REASON_EXPOSURE_HIGH; - } - - if (i.trust === Trust.RESTRICTED) { - tier = Tier.CRITICAL; - reasons |= REASON_RECIPIENT_RESTRICTED; - } else if (i.trust === Trust.UNKNOWN) { - tier = bump(tier); - reasons |= REASON_RECIPIENT_UNKNOWN | REASON_RECIPIENT_PROBATION; - } else if (i.trust === Trust.NEW && i.inProbation) { - tier = bump(tier); - reasons |= REASON_RECIPIENT_PROBATION; - } - - if (i.dailyMax !== 0n && (i.daySpent + i.amount) * 2n > i.dailyMax) { - tier = atLeast(tier, Tier.HIGH); - reasons |= REASON_VELOCITY_PRESSURE; - } - - if (i.mode === Mode.ELEVATED) { - tier = bump(tier); - reasons |= REASON_MODE_ELEVATED; - } - - return { tier, reasons, exposureBps: exposure }; -} - -export function requirements(p: Policy, tier: Tier): { approvals: number; guardians: number; delay: number } { - if (tier === Tier.LOW) return { approvals: p.approvalsLow, guardians: 0, delay: 0 }; - if (tier === Tier.HIGH) return { approvals: p.approvalsHigh, guardians: 0, delay: p.delayHigh }; - return { - approvals: p.approvalsCritical, - guardians: p.guardianRequiredCritical ? p.guardianThreshold : 0, - delay: p.delayCritical, - }; -} - -/** Effective caps under the current mode (Elevated halves them, floored at 1 unit). */ -export function effectiveCaps(perTxMax: bigint, dailyMax: bigint, mode: Mode): { perTxMax: bigint; dailyMax: bigint } { - if (mode !== Mode.ELEVATED) return { perTxMax, dailyMax }; - const half = (x: bigint) => (x === 0n ? 0n : x / 2n === 0n ? 1n : x / 2n); - return { perTxMax: half(perTxMax), dailyMax: half(dailyMax) }; -} diff --git a/web/src/lib/simulator.ts b/web/src/lib/simulator.ts deleted file mode 100644 index b6486bf..0000000 --- a/web/src/lib/simulator.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { classify, effectiveCaps, requirements } from "./risk"; -import { Mode, Tier, Trust, type AssetLimits, type Policy } from "./types"; -import { fmtDuration } from "./format"; - -/** - * Policy simulator: runs a configured policy against the blueprint's attack scenarios before it is - * activated. Everything here is the deterministic risk engine plus the vault's limit checks; nothing is - * heuristic. Verdicts describe what the contract would do, in business language. - */ -export type Verdict = "blocked" | "delayed" | "escalated" | "allowed" | "impossible"; - -export type ScenarioResult = { - id: string; - title: string; - narrative: string; - verdict: Verdict; - detail: string[]; -}; - -export type SimContext = { - policy: Policy; - limits: AssetLimits; - balance: bigint; - decimals: number; - symbol: string; - approverCount: number; - guardianCount: number; -}; - -function fmt(v: bigint, ctx: SimContext): string { - const s = Number(v) / 10 ** ctx.decimals; - return `${s.toLocaleString("en-US", { maximumFractionDigits: 2 })} ${ctx.symbol}`; -} - -function single(ctx: SimContext, amount: bigint, trust: Trust, inProbation: boolean, mode: Mode, compromised: number) { - const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, mode); - const detail: string[] = []; - if (mode === Mode.LOCKDOWN) return { verdict: "blocked" as Verdict, detail: ["Vault is in Lockdown: no outgoing execution."] }; - if (trust === Trust.BLOCKED) return { verdict: "blocked" as Verdict, detail: ["Recipient is blocked."] }; - if (caps.perTxMax !== 0n && amount > caps.perTxMax) { - return { verdict: "blocked" as Verdict, detail: [`Per-transaction cap is ${fmt(caps.perTxMax, ctx)}; the proposal is refused at creation.`] }; - } - const r = classify({ - amount, - assetBalance: ctx.balance, - lowMax: ctx.limits.lowMax, - highMax: ctx.limits.highMax, - dailyMax: caps.dailyMax, - daySpent: 0n, - trust, - inProbation, - mode, - highExposureBps: ctx.policy.highExposureBps, - criticalExposureBps: ctx.policy.criticalExposureBps, - }); - if (ctx.policy.hardBlockExposureBps !== 0 && r.exposureBps > ctx.policy.hardBlockExposureBps) { - return { verdict: "blocked" as Verdict, detail: [`Exposure ${(r.exposureBps / 100).toFixed(1)}% exceeds the hard block of ${ctx.policy.hardBlockExposureBps / 100}%.`] }; - } - if (caps.dailyMax !== 0n && amount > caps.dailyMax) { - return { verdict: "blocked" as Verdict, detail: [`Daily cap is ${fmt(caps.dailyMax, ctx)}; execution would revert.`] }; - } - const envelope = ctx.policy.envelopeBps === 0 ? 0n : (ctx.balance * BigInt(ctx.policy.envelopeBps)) / 10_000n; - if (envelope !== 0n && amount > envelope) { - return { verdict: "blocked" as Verdict, detail: [`Loss envelope is ${fmt(envelope, ctx)} per ${fmtDuration(ctx.policy.envelopeWindow)}; the circuit breaker trips and the vault enters Lockdown instead of paying.`] }; - } - const req = requirements(ctx.policy, r.tier); - detail.push(`Risk tier: ${Tier[r.tier]} (exposure ${(r.exposureBps / 100).toFixed(2)}%).`); - detail.push(`Needs ${req.approvals} approval${req.approvals === 1 ? "" : "s"}${req.guardians ? ` and ${req.guardians} guardian confirmation${req.guardians === 1 ? "" : "s"}` : ""}${req.delay ? `, then waits ${fmtDuration(req.delay)}` : ", no delay"}.`); - let delay = req.delay; - if (inProbation) { - delay = Math.max(delay, ctx.policy.recipientActivationDelay); - detail.push(`Recipient activation delay forces a wait of at least ${fmtDuration(ctx.policy.recipientActivationDelay)}.`); - } - const vetoable = r.tier === Tier.CRITICAL || inProbation || mode !== Mode.NORMAL; - if (vetoable) detail.push("Any guardian can veto before execution."); - if (req.guardians > ctx.guardianCount) { - return { verdict: "impossible" as Verdict, detail: [...detail, "More guardian confirmations are required than guardians exist."] }; - } - if (compromised < req.approvals) { - detail.push(`Attacker controls ${compromised} approver${compromised === 1 ? "" : "s"}, fewer than required.`); - return { verdict: "blocked" as Verdict, detail }; - } - if (req.guardians > 0) { - detail.push("Guardian confirmation is an independent control the attacker does not hold."); - return { verdict: "blocked" as Verdict, detail }; - } - if (delay > 0) return { verdict: "delayed" as Verdict, detail }; - if (r.tier > Tier.LOW) return { verdict: "escalated" as Verdict, detail }; - return { verdict: "allowed" as Verdict, detail }; -} - -export function runScenarios(ctx: SimContext): ScenarioResult[] { - const out: ScenarioResult[] = []; - const pct = (bps: number) => (ctx.balance * BigInt(bps)) / 10_000n; - const unit = 10n ** BigInt(ctx.decimals); - - // 1. Finance signer compromised, $100k to a new address - { - const amount = 100_000n * unit; - const r = single(ctx, amount, Trust.UNKNOWN, true, Mode.NORMAL, 1); - out.push({ - id: "single-signer-new-address", - title: "One finance signer compromised", - narrative: `An attacker holding a single approver key proposes ${fmt(amount, ctx)} to an address the vault has never paid.`, - verdict: r.verdict, - detail: r.detail, - }); - } - // 2. Three signers compromised, 40% of treasury - { - const amount = pct(4000); - const r = single(ctx, amount, Trust.VERIFIED, false, Mode.NORMAL, 3); - out.push({ - id: "three-signers-40pct", - title: "Three signers compromised, 40% withdrawal", - narrative: `An attacker holding three approver keys proposes ${fmt(amount, ctx)}, 40% of holdings, to a verified recipient.`, - verdict: r.verdict, - detail: r.detail, - }); - } - // 3. Split drain: 20 x 9,900 - { - const each = 9_900n * unit; - const total = each * 20n; - const caps = effectiveCaps(ctx.limits.perTxMax, ctx.limits.dailyMax, Mode.NORMAL); - const envelope = ctx.policy.envelopeBps === 0 ? 0n : pct(ctx.policy.envelopeBps); - const detail: string[] = []; - let verdict: Verdict = "allowed"; - const tierEach = classify({ - amount: each, - assetBalance: ctx.balance, - lowMax: ctx.limits.lowMax, - highMax: ctx.limits.highMax, - dailyMax: caps.dailyMax, - daySpent: 0n, - trust: Trust.VERIFIED, - inProbation: false, - mode: Mode.NORMAL, - highExposureBps: ctx.policy.highExposureBps, - criticalExposureBps: ctx.policy.criticalExposureBps, - }); - detail.push(`Each transfer alone is ${Tier[tierEach.tier]} tier.`); - if (caps.dailyMax !== 0n && total > caps.dailyMax) { - const n = Number(caps.dailyMax / each); - detail.push(`Daily cap ${fmt(caps.dailyMax, ctx)} stops execution after ${n} transfer${n === 1 ? "" : "s"} (${fmt(each * BigInt(n), ctx)}).`); - verdict = "blocked"; - } - if (envelope !== 0n && total > envelope) { - const n = Number(envelope / each); - detail.push(`Loss envelope ${fmt(envelope, ctx)} trips the circuit breaker after ${n} transfer${n === 1 ? "" : "s"}; the vault enters Lockdown.`); - verdict = "blocked"; - } - if (caps.dailyMax !== 0n && (each * 2n) > caps.dailyMax / 2n) { - detail.push("Once half the daily cap is spent, every further payment is scored HIGH."); - if (verdict === "allowed") verdict = "escalated"; - } - if (verdict === "allowed") detail.push("No cumulative cap is configured, so the split drain would succeed. Set a daily cap or a loss envelope."); - out.push({ - id: "split-drain", - title: "Drain split into twenty transfers", - narrative: `Twenty payments of ${fmt(each, ctx)}, ${fmt(total, ctx)} in total, inside one day.`, - verdict, - detail, - }); - } - // 4. Attacker weakens policy then withdraws - { - const detail: string[] = []; - detail.push(`Lowering any threshold, delay or cap is a security-reducing change: it waits ${fmtDuration(ctx.policy.policyChangeDelay)} and any guardian can veto it.`); - detail.push(`It needs ${ctx.policy.governanceThreshold} owner approval${ctx.policy.governanceThreshold === 1 ? "" : "s"}, and cannot be created at all while the vault is in Lockdown.`); - detail.push("Until it activates, in-flight proposals keep their pinned requirements."); - const verdict: Verdict = ctx.policy.policyChangeDelay > 0 ? "delayed" : "allowed"; - if (verdict === "allowed") detail.push("The policy-change delay is 0, so a compromised owner quorum could loosen the policy at once. Set a delay."); - out.push({ - id: "policy-weaken", - title: "Attacker weakens the policy, then withdraws", - narrative: "A compromised owner quorum lowers approvals and caps before trying to drain the vault.", - verdict, - detail, - }); - } - // 5. Guardian compromised - { - out.push({ - id: "guardian-compromised", - title: "Guardian key compromised", - narrative: "An attacker holding a guardian key tries to withdraw.", - verdict: "impossible", - detail: [ - "Guardians hold no treasury role: they cannot propose, approve or execute payments, and the contract refuses to give them treasury roles.", - `The worst a guardian can do is freeze the vault or propose a recovery that waits ${fmtDuration(ctx.policy.recoveryDelay)} and any owner can cancel.`, - ], - }); - } - // 6. Elevated posture check: routine payment during an incident - { - const amount = ctx.limits.lowMax; - const r = single(ctx, amount, Trust.VERIFIED, false, Mode.ELEVATED, 2); - out.push({ - id: "elevated-routine", - title: "Routine payment during an incident", - narrative: `The vault is in Elevated mode and a ${fmt(amount, ctx)} routine payment is proposed.`, - verdict: r.verdict, - detail: r.detail, - }); - } - return out; -} diff --git a/web/src/lib/templates.ts b/web/src/lib/templates.ts deleted file mode 100644 index 266b284..0000000 --- a/web/src/lib/templates.ts +++ /dev/null @@ -1,178 +0,0 @@ -import type { AssetLimits, Policy } from "./types"; - -/** Mirror of contracts/script/SkurTemplates.sol. Amounts assume a 6-decimal stablecoin and 18-decimal KASH. */ -const H = 3600; -const D = 86400; -export const USD = 1_000_000n; -export const KASH = 10n ** 18n; - -export type TemplateId = "startup" | "sme" | "dao" | "fund" | "nonprofit" | "familyOffice"; - -export type Template = { - id: TemplateId; - name: string; - tagline: string; - minSigners: number; - minGuardians: number; - policy: Policy; - stable: AssetLimits; - native: AssetLimits; -}; - -const startupPolicy: Policy = { - approvalsLow: 1, - approvalsHigh: 2, - approvalsCritical: 2, - governanceThreshold: 2, - guardianThreshold: 1, - guardianRequiredCritical: true, - delayHigh: 6 * H, - delayCritical: 24 * H, - recipientActivationDelay: 24 * H, - policyChangeDelay: 24 * H, - recoveryDelay: 48 * H, - proposalTtl: 7 * D, - highExposureBps: 500, - criticalExposureBps: 2000, - hardBlockExposureBps: 5000, - envelopeBps: 1000, - envelopeWindow: 24 * H, -}; - -const startupStable: AssetLimits = { - approved: true, - lowMax: 5_000n * USD, - highMax: 25_000n * USD, - perTxMax: 100_000n * USD, - dailyMax: 100_000n * USD, -}; - -const startupNative: AssetLimits = { - approved: true, - lowMax: 100n * KASH, - highMax: 1_000n * KASH, - perTxMax: 0n, - dailyMax: 5_000n * KASH, -}; - -export const TEMPLATES: Template[] = [ - { - id: "startup", - name: "Startup", - tagline: "Simple thresholds, new-recipient delay, one guardian.", - minSigners: 2, - minGuardians: 1, - policy: startupPolicy, - stable: startupStable, - native: startupNative, - }, - { - id: "sme", - name: "SME", - tagline: "Tiered approvals, velocity limits, supplier trust.", - minSigners: 3, - minGuardians: 1, - policy: { ...startupPolicy, approvalsCritical: 3, delayHigh: 4 * H, envelopeBps: 500 }, - stable: { ...startupStable, lowMax: 10_000n * USD, highMax: 50_000n * USD, perTxMax: 150_000n * USD, dailyMax: 150_000n * USD }, - native: startupNative, - }, - { - id: "dao", - name: "Protocol / DAO", - tagline: "Higher quorum, contract-call controls, timelocks.", - minSigners: 4, - minGuardians: 2, - policy: { - ...startupPolicy, - approvalsLow: 2, - approvalsHigh: 3, - approvalsCritical: 4, - governanceThreshold: 3, - guardianThreshold: 2, - delayHigh: 24 * H, - delayCritical: 72 * H, - policyChangeDelay: 72 * H, - recoveryDelay: 7 * D, - proposalTtl: 14 * D, - highExposureBps: 200, - criticalExposureBps: 1000, - hardBlockExposureBps: 2500, - envelopeBps: 500, - }, - stable: { ...startupStable, lowMax: 25_000n * USD, highMax: 100_000n * USD, perTxMax: 500_000n * USD, dailyMax: 500_000n * USD }, - native: { ...startupNative, lowMax: 1_000n * KASH, highMax: 10_000n * KASH, dailyMax: 50_000n * KASH }, - }, - { - id: "fund", - name: "Fund", - tagline: "Exposure limits, strong guardians, long critical delays.", - minSigners: 3, - minGuardians: 2, - policy: { - ...startupPolicy, - approvalsLow: 2, - approvalsHigh: 3, - approvalsCritical: 3, - guardianThreshold: 2, - delayHigh: 12 * H, - delayCritical: 72 * H, - recipientActivationDelay: 48 * H, - policyChangeDelay: 72 * H, - recoveryDelay: 7 * D, - proposalTtl: 14 * D, - highExposureBps: 100, - criticalExposureBps: 500, - hardBlockExposureBps: 2000, - envelopeBps: 300, - }, - stable: { ...startupStable, lowMax: 50_000n * USD, highMax: 250_000n * USD, perTxMax: 1_000_000n * USD, dailyMax: 1_000_000n * USD }, - native: { ...startupNative, lowMax: 1_000n * KASH, highMax: 10_000n * KASH, dailyMax: 50_000n * KASH }, - }, - { - id: "nonprofit", - name: "Nonprofit", - tagline: "Restricted recipients, approval separation, auditability.", - minSigners: 3, - minGuardians: 1, - policy: { - ...startupPolicy, - approvalsLow: 2, - approvalsHigh: 2, - approvalsCritical: 3, - recipientActivationDelay: 72 * H, - delayHigh: 12 * H, - delayCritical: 48 * H, - envelopeBps: 500, - }, - stable: startupStable, - native: startupNative, - }, - { - id: "familyOffice", - name: "Family Office", - tagline: "Conservative limits, cold guardian, recovery policy.", - minSigners: 2, - minGuardians: 1, - policy: { - ...startupPolicy, - delayHigh: 24 * H, - delayCritical: 72 * H, - recipientActivationDelay: 72 * H, - policyChangeDelay: 72 * H, - recoveryDelay: 14 * D, - proposalTtl: 21 * D, - highExposureBps: 100, - criticalExposureBps: 500, - hardBlockExposureBps: 1500, - envelopeBps: 200, - }, - stable: { ...startupStable, lowMax: 10_000n * USD, highMax: 50_000n * USD, perTxMax: 250_000n * USD, dailyMax: 250_000n * USD }, - native: startupNative, - }, -]; - -export function templateById(id: TemplateId): Template { - const t = TEMPLATES.find((x) => x.id === id); - if (!t) throw new Error(`unknown template ${id}`); - return t; -} diff --git a/web/src/lib/tokens.ts b/web/src/lib/tokens.ts deleted file mode 100644 index 1a406c5..0000000 --- a/web/src/lib/tokens.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Marks for the assets a Skur vault can hold. Devnet tokens have no brand, so each carries a - * distinct colour and glyph; both interfaces draw the same mark for the same symbol. - */ -export type TokenMark = { name: string; glyph: string; bg: string; fg: string }; - -const MARKS: Record = { - sUSD: { name: "Skur Test USD", glyph: "$", bg: "#16a34a", fg: "#ffffff" }, - sEUR: { name: "Skur Test EUR", glyph: "€", bg: "#2563eb", fg: "#ffffff" }, - sBTC: { name: "Skur Test BTC", glyph: "₿", bg: "#f7931a", fg: "#ffffff" }, - sETH: { name: "Skur Test ETH", glyph: "Ξ", bg: "#5b5bd6", fg: "#ffffff" }, - KASH: { name: "Ark KASH", glyph: "◈", bg: "#ffd000", fg: "#101418" }, -}; - -export function tokenMark(symbol: string): TokenMark { - return MARKS[symbol] ?? { name: symbol, glyph: symbol.replace(/^s/, "").slice(0, 1).toUpperCase(), bg: "#64748b", fg: "#ffffff" }; -} diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts deleted file mode 100644 index 93a6ff8..0000000 --- a/web/src/lib/types.ts +++ /dev/null @@ -1,193 +0,0 @@ -/** Mirrors contracts/src/SkurTypes.sol. Keep in sync; the contract is authoritative. */ - -export const ROLE_OWNER = 1; -export const ROLE_APPROVER = 2; -export const ROLE_EXECUTOR = 4; -export const ROLE_GUARDIAN = 8; -export const ROLE_TREASURY_MASK = ROLE_OWNER | ROLE_APPROVER | ROLE_EXECUTOR; - -export const BPS = 10_000n; - -export const REASON_AMOUNT_HIGH = 1 << 0; -export const REASON_AMOUNT_CRITICAL = 1 << 1; -export const REASON_EXPOSURE_HIGH = 1 << 2; -export const REASON_EXPOSURE_CRITICAL = 1 << 3; -export const REASON_RECIPIENT_PROBATION = 1 << 4; -export const REASON_RECIPIENT_RESTRICTED = 1 << 5; -export const REASON_MODE_ELEVATED = 1 << 6; -export const REASON_VELOCITY_PRESSURE = 1 << 7; -export const REASON_RECIPIENT_UNKNOWN = 1 << 8; - -export enum Mode { - NORMAL = 0, - ELEVATED = 1, - LOCKDOWN = 2, -} - -export enum Tier { - LOW = 0, - HIGH = 1, - CRITICAL = 2, -} - -export enum Trust { - UNKNOWN = 0, - NEW = 1, - VERIFIED = 2, - TRUSTED = 3, - RESTRICTED = 4, - BLOCKED = 5, -} - -export enum Kind { - TRANSFER = 0, - POLICY_UPDATE = 1, - ASSET_LIMITS = 2, - MEMBER_SET = 3, - RECIPIENT_TRUST = 4, - MODE_RELAX = 5, - RECOVERY = 6, -} - -export enum Status { - NONE = 0, - PENDING = 1, - EXECUTED = 2, - CANCELLED = 3, - VETOED = 4, -} - -export type Policy = { - approvalsLow: number; - approvalsHigh: number; - approvalsCritical: number; - governanceThreshold: number; - guardianThreshold: number; - guardianRequiredCritical: boolean; - delayHigh: number; - delayCritical: number; - recipientActivationDelay: number; - policyChangeDelay: number; - recoveryDelay: number; - proposalTtl: number; - highExposureBps: number; - criticalExposureBps: number; - hardBlockExposureBps: number; - envelopeBps: number; - envelopeWindow: number; -}; - -export type AssetLimits = { - approved: boolean; - lowMax: bigint; - highMax: bigint; - perTxMax: bigint; - dailyMax: bigint; -}; - -export type Recipient = { - trust: Trust; - registeredAt: bigint; - activatesAt: bigint; - paymentCount: bigint; - totalPaid: bigint; -}; - -export type Proposal = { - kind: Kind; - status: Status; - tier: Tier; - requiredApprovals: number; - requiredGuardians: number; - securityReducing: boolean; - riskReasons: number; - policyVersion: number; - proposer: `0x${string}`; - asset: `0x${string}`; - target: `0x${string}`; - amount: bigint; - createdAt: bigint; - executableAfter: bigint; - expiresAt: bigint; - data: `0x${string}`; -}; - -export type AssetMeta = { - address: `0x${string}`; - symbol: string; - decimals: number; - limits: AssetLimits; - balance: bigint; -}; - -export const MODE_LABEL: Record = { - [Mode.NORMAL]: "Normal", - [Mode.ELEVATED]: "Elevated", - [Mode.LOCKDOWN]: "Lockdown", -}; - -export const TIER_LABEL: Record = { - [Tier.LOW]: "Low", - [Tier.HIGH]: "High", - [Tier.CRITICAL]: "Critical", -}; - -export const TRUST_LABEL: Record = { - [Trust.UNKNOWN]: "Unknown", - [Trust.NEW]: "New", - [Trust.VERIFIED]: "Verified", - [Trust.TRUSTED]: "Trusted", - [Trust.RESTRICTED]: "Restricted", - [Trust.BLOCKED]: "Blocked", -}; - -export const KIND_LABEL: Record = { - [Kind.TRANSFER]: "Transfer", - [Kind.POLICY_UPDATE]: "Policy update", - [Kind.ASSET_LIMITS]: "Asset limits", - [Kind.MEMBER_SET]: "Membership change", - [Kind.RECIPIENT_TRUST]: "Recipient trust", - [Kind.MODE_RELAX]: "Lower security mode", - [Kind.RECOVERY]: "Signer recovery", -}; - -export const STATUS_LABEL: Record = { - [Status.NONE]: "None", - [Status.PENDING]: "Pending", - [Status.EXECUTED]: "Executed", - [Status.CANCELLED]: "Cancelled", - [Status.VETOED]: "Vetoed", -}; - -export function roleNames(bits: number): string[] { - const out: string[] = []; - if (bits & ROLE_OWNER) out.push("Owner"); - if (bits & ROLE_APPROVER) out.push("Approver"); - if (bits & ROLE_EXECUTOR) out.push("Executor"); - if (bits & ROLE_GUARDIAN) out.push("Guardian"); - return out; -} - -export const REASON_TEXT: Array<[number, string]> = [ - [REASON_AMOUNT_CRITICAL, "the amount is above the critical threshold for this asset"], - [REASON_AMOUNT_HIGH, "the amount is above the routine threshold for this asset"], - [REASON_EXPOSURE_CRITICAL, "it would move a critical share of the vault's holdings"], - [REASON_EXPOSURE_HIGH, "it would move a significant share of the vault's holdings"], - [REASON_RECIPIENT_RESTRICTED, "the recipient is restricted by policy"], - [REASON_RECIPIENT_UNKNOWN, "this vault has never paid the recipient before"], - [REASON_RECIPIENT_PROBATION, "the recipient is still within its activation delay"], - [REASON_VELOCITY_PRESSURE, "more than half of today's daily cap would be used"], - [REASON_MODE_ELEVATED, "the vault is in Elevated mode"], -]; - -export function explainReasons(mask: number): string[] { - const seen = new Set(); - const out: string[] = []; - for (const [bit, text] of REASON_TEXT) { - if (mask & bit && !seen.has(text)) { - seen.add(text); - out.push(text); - } - } - return out; -} diff --git a/web/src/lib/vaultReads.ts b/web/src/lib/vaultReads.ts deleted file mode 100644 index 4687d7d..0000000 --- a/web/src/lib/vaultReads.ts +++ /dev/null @@ -1,273 +0,0 @@ -/** Pure contract reads shared by the web and mobile interfaces. No React, no wagmi: a viem PublicClient in, plain data out. */ -import { erc20Abi, parseAbiItem, type PublicClient, type AbiEvent, type ReadContractReturnType } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { DEPLOYMENTS, NATIVE_ASSET } from "../config/chain"; -import { policyFromContract } from "./policy"; -import { - Kind, - Mode, - Status, - Trust, - type AssetLimits, - type AssetMeta, - type Policy, - type Proposal, - type Recipient, -} from "./types"; - -export type Member = { address: `0x${string}`; roles: number }; - -export type ProposalView = Proposal & { - id: bigint; - liveApprovals: number; - liveGuardians: number; - vetoable: boolean; - approvers: `0x${string}`[]; - guardianConfirmers: `0x${string}`[]; - memo: string; -}; - -export type VelocityView = { - daySpent: bigint; - dailyMax: bigint; - envelopeSpent: bigint; - envelope: bigint; - envelopeResetsAt: bigint; -}; - -export type RecipientView = Recipient & { address: `0x${string}` }; - -/** Fast path: everything needed to render balances, policy, members and limits, read concurrently. */ -export type VaultCore = { - address: `0x${string}`; - mode: Mode; - policyVersion: number; - policy: Policy; - members: Member[]; - counts: { owners: number; approvers: number; executors: number; guardians: number }; - assets: AssetMeta[]; - velocity: Record; - proposalCount: number; - /** Head block at the time of the core read; the activity scan uses it so it needs no extra round trip. */ - blockNumber: bigint; - pendingCount: number; - executedCount: number; -}; - -/** Slow path: proposals, recipients and event history. Depends on the log queries, which the devnet serves slowly. */ -export type VaultActivity = { - proposals: ProposalView[]; - recipients: RecipientView[]; - /** True when the event scan failed; proposals still come from contract state but memos and histories are missing. */ - logsFailed: boolean; - policyHistory: Array<{ version: number; activatedAt: bigint; txHash: `0x${string}` }>; - modeHistory: Array<{ previous: Mode; mode: Mode; by: `0x${string}`; reason: string; txHash: `0x${string}`; block: bigint }>; -}; - -export type VaultData = VaultCore & VaultActivity & { activityLoading: boolean; fetchedAt: number }; - -export const MAX_PROPOSALS = 60; - -/** Proposals in a terminal status never change again, so their reads are kept for the session. */ -type ContractProposal = ReadContractReturnType; -type ProposalRaw = { id: bigint; p: ContractProposal; live: readonly [number, number] | readonly [bigint, bigint]; vetoable: boolean; approvers: readonly `0x${string}`[]; guardianConfirmers: readonly `0x${string}`[] }; -const terminalCache = new Map(); - -const proposalCreatedEvent = parseAbiItem( - "event ProposalCreated(uint256 indexed id, uint8 indexed kind, address indexed proposer, address asset, address target, uint256 amount, uint8 tier, uint16 riskReasons, uint8 requiredApprovals, uint8 requiredGuardians, uint64 executableAfter, uint64 expiresAt, bool securityReducing, string memo)", -); -const recipientRegisteredEvent = parseAbiItem("event RecipientRegistered(address indexed recipient, uint64 activatesAt)"); -const recipientTrustEvent = parseAbiItem("event RecipientTrustSet(address indexed recipient, uint8 previous, uint8 trust)"); -const policyActivatedEvent = parseAbiItem( - "event PolicyActivated(uint32 indexed version, uint64 activatedAt, (uint8 approvalsLow, uint8 approvalsHigh, uint8 approvalsCritical, uint8 governanceThreshold, uint8 guardianThreshold, bool guardianRequiredCritical, uint32 delayHigh, uint32 delayCritical, uint32 recipientActivationDelay, uint32 policyChangeDelay, uint32 recoveryDelay, uint32 proposalTtl, uint16 highExposureBps, uint16 criticalExposureBps, uint16 hardBlockExposureBps, uint16 envelopeBps, uint32 envelopeWindow) policy)", -); -const modeChangedEvent = parseAbiItem("event ModeChanged(uint8 indexed previous, uint8 indexed mode, address indexed by, bytes32 reason)"); - -function bytes32ToString(hex: `0x${string}`): string { - const bytes = hex.slice(2).match(/.{2}/g) ?? []; - let out = ""; - for (const b of bytes) { - const c = parseInt(b, 16); - if (c === 0) break; - out += String.fromCharCode(c); - } - return out; -} - -export async function fetchCore(client: PublicClient, address: `0x${string}`): Promise { - const vault = { address, abi: SkurVaultAbi } as const; - const [modeRaw, policyVersion, policyRaw, membersRaw, assetsRaw, proposalCountRaw, pendingCountRaw, executedCountRaw, nativeBalance, blockNumber] = - await Promise.all([ - client.readContract({ ...vault, functionName: "mode" }), - client.readContract({ ...vault, functionName: "policyVersion" }), - client.readContract({ ...vault, functionName: "getPolicy" }), - client.readContract({ ...vault, functionName: "getMembers" }), - client.readContract({ ...vault, functionName: "getAssets" }), - client.readContract({ ...vault, functionName: "proposalCount" }), - client.readContract({ ...vault, functionName: "pendingCount" }), - client.readContract({ ...vault, functionName: "executedCount" }), - client.getBalance({ address }), - client.getBlockNumber(), - ]); - - const members: Member[] = membersRaw[0].map((a, i) => ({ address: a, roles: Number(membersRaw[1][i]) })); - const counts = members.reduce( - (acc, m) => ({ - owners: acc.owners + (m.roles & 1 ? 1 : 0), - approvers: acc.approvers + (m.roles & 2 ? 1 : 0), - executors: acc.executors + (m.roles & 4 ? 1 : 0), - guardians: acc.guardians + (m.roles & 8 ? 1 : 0), - }), - { owners: 0, approvers: 0, executors: 0, guardians: 0 }, - ); - - // Second wave of concurrent reads: per-asset limits, velocity and ERC-20 metadata. - const perAsset = await Promise.all( - assetsRaw.map(async (asset) => { - const [limitsRaw, v, symbol, decimals, balance] = await Promise.all([ - client.readContract({ ...vault, functionName: "getAssetLimits", args: [asset] }), - client.readContract({ ...vault, functionName: "velocityOf", args: [asset] }), - asset === NATIVE_ASSET ? Promise.resolve("KASH") : client.readContract({ address: asset, abi: erc20Abi, functionName: "symbol" }).catch(() => "TOKEN"), - asset === NATIVE_ASSET ? Promise.resolve(18) : client.readContract({ address: asset, abi: erc20Abi, functionName: "decimals" }).catch(() => 18), - asset === NATIVE_ASSET ? Promise.resolve(nativeBalance) : client.readContract({ address: asset, abi: erc20Abi, functionName: "balanceOf", args: [address] }).catch(() => 0n), - ]); - const limits: AssetLimits = { approved: limitsRaw.approved, lowMax: limitsRaw.lowMax, highMax: limitsRaw.highMax, perTxMax: limitsRaw.perTxMax, dailyMax: limitsRaw.dailyMax }; - const meta: AssetMeta = { address: asset, symbol, decimals: Number(decimals), limits, balance }; - const velocity: VelocityView = { daySpent: v[0], dailyMax: v[1], envelopeSpent: v[2], envelope: v[3], envelopeResetsAt: v[4] }; - return { meta, velocity }; - }), - ); - const velocity: Record = {}; - for (const { meta, velocity: v } of perAsset) velocity[meta.address.toLowerCase()] = v; - - return { - address, - mode: Number(modeRaw) as Mode, - policyVersion: Number(policyVersion), - policy: policyFromContract(policyRaw as unknown as Record), - members, - counts, - assets: perAsset.map((x) => x.meta), - velocity, - proposalCount: Number(proposalCountRaw), - blockNumber, - pendingCount: Number(pendingCountRaw), - executedCount: Number(executedCountRaw), - }; -} - -/** The devnet RPC caps eth_getLogs at 10,000 blocks per call, so the scan runs in parallel windows. */ -const LOG_WINDOW = 9_000n; -type RawLog = { eventName?: string; args?: unknown; transactionHash: `0x${string}`; blockNumber: bigint }; -async function getLogsChunked(client: PublicClient, address: `0x${string}`, events: readonly AbiEvent[], fromBlock: bigint, head: bigint): Promise<{ logs: RawLog[]; failed: boolean }> { - try { - // `head` comes from the core read and may be a few blocks stale, so the last window runs to "latest" - // rather than to `head`; that keeps an event mined between the two reads from being missed. - const windows: Array<[bigint, bigint | "latest"]> = []; - for (let a = fromBlock; a <= head; a += LOG_WINDOW + 1n) windows.push([a, a + LOG_WINDOW > head ? head : a + LOG_WINDOW]); - if (windows.length === 0) windows.push([fromBlock, "latest"]); - else windows[windows.length - 1][1] = "latest"; - const chunks = await Promise.all(windows.map(([from, to]) => client.getLogs({ address, events, fromBlock: from, toBlock: to }) as unknown as Promise)); - return { logs: chunks.flat(), failed: false }; - } catch { - return { logs: [], failed: true }; - } -} - -export async function fetchActivity(client: PublicClient, address: `0x${string}`, proposalCount: number, head: bigint): Promise { - const vault = { address, abi: SkurVaultAbi } as const; - const fromBlock = BigInt(DEPLOYMENTS.deployedAtBlock || 0); - - const firstId = Math.max(1, proposalCount - MAX_PROPOSALS + 1); - const ids: bigint[] = []; - for (let i = proposalCount; i >= firstId; i--) ids.push(BigInt(i)); - - // One log query for every event we index; the devnet serves each getLogs call slowly, so five - // separate queries were the long pole of the page load. - const [{ logs: allLogs, failed: logsFailed }, proposalsRaw] = await Promise.all([ - getLogsChunked(client, address, [proposalCreatedEvent, recipientRegisteredEvent, recipientTrustEvent, policyActivatedEvent, modeChangedEvent], fromBlock, head), - Promise.all( - ids.map(async (id): Promise => { - const cached = terminalCache.get(`${address}:${id}`); - if (cached) return cached; - const p = await client.readContract({ ...vault, functionName: "getProposal", args: [id] }); - const pending = Number(p.status) === Status.PENDING; - const [live, vetoable, approvers, guardianConfirmers] = await Promise.all([ - pending ? client.readContract({ ...vault, functionName: "liveApprovals", args: [id] }) : ([0, 0] as const), - pending ? client.readContract({ ...vault, functionName: "isVetoable", args: [id] }) : false, - client.readContract({ ...vault, functionName: "getApprovers", args: [id] }), - client.readContract({ ...vault, functionName: "getGuardianConfirmers", args: [id] }), - ]); - // Terminal proposals keep the confirmations they had; the live recount only matters while pending. - const raw: ProposalRaw = { id, p, live: pending ? live : ([approvers.length, guardianConfirmers.length] as const), vetoable, approvers, guardianConfirmers }; - if (!pending) terminalCache.set(`${address}:${id}`, raw); - return raw; - }), - ), - ]); - // viem types the args of a multi-event query as a union; narrow per event name explicitly. - type LogWith = { args: A; transactionHash: `0x${string}`; blockNumber: bigint }; - const byName = (name: string): LogWith[] => allLogs.filter((l) => l.eventName === name) as unknown as LogWith[]; - const createdLogs = byName<{ id?: bigint; memo?: string }>("ProposalCreated"); - const registeredLogs = byName<{ recipient?: `0x${string}` }>("RecipientRegistered"); - const trustLogs = byName<{ recipient?: `0x${string}` }>("RecipientTrustSet"); - const policyLogs = byName<{ version?: number; activatedAt?: bigint }>("PolicyActivated"); - const modeLogs = byName<{ previous?: number; mode?: number; by?: `0x${string}`; reason?: `0x${string}` }>("ModeChanged"); - - const memos = new Map(); - for (const l of createdLogs) memos.set(String(l.args.id), l.args.memo ?? ""); - - const proposals: ProposalView[] = proposalsRaw.map(({ id, p, live, vetoable, approvers, guardianConfirmers }) => ({ - id, - kind: Number(p.kind) as Kind, - status: Number(p.status) as Status, - tier: Number(p.tier), - requiredApprovals: Number(p.requiredApprovals), - requiredGuardians: Number(p.requiredGuardians), - securityReducing: p.securityReducing, - riskReasons: Number(p.riskReasons), - policyVersion: Number(p.policyVersion), - proposer: p.proposer, - asset: p.asset, - target: p.target, - amount: p.amount, - createdAt: p.createdAt, - executableAfter: p.executableAfter, - expiresAt: p.expiresAt, - data: p.data, - liveApprovals: Number(live[0]), - liveGuardians: Number(live[1]), - vetoable, - approvers: [...approvers], - guardianConfirmers: [...guardianConfirmers], - memo: memos.get(String(id)) ?? "", - })); - - const recipientSet = new Set(); - for (const l of registeredLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); - for (const l of trustLogs) if (l.args.recipient) recipientSet.add(l.args.recipient); - for (const p of proposals) if (p.kind === Kind.TRANSFER) recipientSet.add(p.target); - const recipients: RecipientView[] = await Promise.all( - [...recipientSet].map(async (r) => { - const rec = await client.readContract({ ...vault, functionName: "getRecipient", args: [r as `0x${string}`] }); - return { address: r as `0x${string}`, trust: Number(rec.trust) as Trust, registeredAt: rec.registeredAt, activatesAt: rec.activatesAt, paymentCount: rec.paymentCount, totalPaid: rec.totalPaid }; - }), - ); - recipients.sort((a, b) => Number(b.registeredAt - a.registeredAt)); - - return { - proposals, - recipients, - logsFailed, - policyHistory: policyLogs.map((l) => ({ version: Number(l.args.version), activatedAt: l.args.activatedAt ?? 0n, txHash: l.transactionHash })), - modeHistory: modeLogs.map((l) => ({ - previous: Number(l.args.previous) as Mode, - mode: Number(l.args.mode) as Mode, - by: l.args.by as `0x${string}`, - reason: bytes32ToString(l.args.reason as `0x${string}`), - txHash: l.transactionHash, - block: l.blockNumber, - })), - }; -} - diff --git a/web/src/main.tsx b/web/src/main.tsx deleted file mode 100644 index 1497151..0000000 --- a/web/src/main.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { WagmiProvider } from "wagmi"; -import App from "./App"; -import { wagmiConfig } from "./wagmi"; -import "./styles.css"; - -const queryClient = new QueryClient(); -if (import.meta.env.DEV) (window as unknown as { __qc: QueryClient }).__qc = queryClient; - -createRoot(document.getElementById("root")!).render( - - - - - - - , -); diff --git a/web/src/pages/AddressBook.tsx b/web/src/pages/AddressBook.tsx deleted file mode 100644 index 590bba0..0000000 --- a/web/src/pages/AddressBook.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { useState } from "react"; -import { useAccount } from "wagmi"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { Address, Button, Empty, Field, Modal, TrustBadge, TxStatus } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { IconBook, IconPlus } from "../components/icons"; -import { useTx } from "../hooks/useTx"; -import type { VaultData } from "../hooks/useVault"; -import { fmtDate, fmtDuration, fmtRelative, nowSec } from "../lib/format"; -import { ROLE_APPROVER, ROLE_OWNER, Trust, TRUST_LABEL } from "../lib/types"; - -/** app.safe.global/address-book: "New entry" action row, then the table. Entries here are onchain recipient records. */ -export function AddressBook({ vault, onChanged }: { vault: VaultData; onChanged: () => void }) { - const { address } = useAccount(); - const me = vault.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const roles = me?.roles ?? 0; - const tx = useTx(() => { onChanged(); setDialog(null); }); - const [dialog, setDialog] = useState(null); - const [target, setTarget] = useState(""); - const [trust, setTrust] = useState(Trust.VERIFIED); - const now = nowSec(); - - const openTrust = (addr: string, current: Trust) => { - setTarget(addr); - setTrust(current === Trust.UNKNOWN || current === Trust.NEW ? Trust.VERIFIED : current); - setDialog("trust"); - }; - - return ( - <> -
      - - - A new recipient waits {fmtDuration(vault.policy.recipientActivationDelay)} before normal policy applies to it. -
      - -
      - {vault.activityLoading ? ( - Reading recipients from the chain… - ) : vault.recipients.length === 0 ? ( - }>No recipients yet. Register one to start its activation clock. - ) : ( - - - - - - {vault.recipients.map((r) => { - const probation = r.trust === Trust.NEW && Number(r.activatesAt) > now; - return ( - - - - - - - - - ); - })} - -
      RecipientTrustActivationPaymentsRegistered
      {r.trust === Trust.NEW ? (probation ? `activates ${fmtRelative(r.activatesAt)}` : "activated") : "—"}{String(r.paymentCount)}{fmtDate(r.registeredAt)}
      - )} -
      - - {dialog === "register" && ( - setDialog(null)} footer={<>}> - - setTarget(e.target.value.trim())} placeholder="0x…" autoFocus /> - - - - )} - {dialog === "trust" && ( - setDialog(null)} footer={<>}> - setTarget(e.target.value.trim())} placeholder="0x…" /> - - - - - - )} - - ); -} diff --git a/web/src/pages/Assets.tsx b/web/src/pages/Assets.tsx deleted file mode 100644 index 957b11c..0000000 --- a/web/src/pages/Assets.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { useState } from "react"; -import { tokenMark } from "../lib/tokens"; -import { NATIVE_ASSET } from "../config/chain"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, fmtRelative } from "../lib/format"; -import { Mode } from "../lib/types"; -import { Address, Button, TokenIcon } from "../components/ui"; -import { IconSend } from "../components/icons"; -import type { AppPage } from "../components/AppShell"; - -/** app.safe.global/balances: Tokens tab, total assets value, table with per-row actions. */ -export function Assets({ vault, onSend, onNavigate }: { vault: VaultData; onSend: (asset: `0x${string}`) => void; onNavigate: (p: AppPage) => void }) { - const [tab, setTab] = useState<"tokens" | "limits">("tokens"); - const canSend = vault.mode !== Mode.LOCKDOWN; - const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; - - return ( - <> -
      - - -
      - -
      -
      -
      Total assets value
      -
      {stable ? fmtAmount(stable.balance, stable.decimals, stable.symbol) : "—"}
      -
      -
      - Read from the chain {fmtRelative(Math.floor(vault.fetchedAt / 1000))} - -
      -
      - -
      - {tab === "tokens" ? ( - - - - - - - - - - - - {vault.assets.map((a) => { - const v = vault.velocity[a.address.toLowerCase()]; - return ( - - - - - - - - ); - })} - -
      AssetBalanceShare of holdingsToday's outflowActions
      -
      - -
      -
      {tokenMark(a.symbol).name}
      -
      {a.address === NATIVE_ASSET ? "native token" :
      }
      -
      -
      -
      {fmtAmount(a.balance, a.decimals)} {a.symbol}{a.limits.approved ? "approved" : "not approved"}{v && v.dailyMax ? `${fmtAmount(v.daySpent, a.decimals)} / ${fmtAmount(v.dailyMax, a.decimals)}` : v ? fmtAmount(v.daySpent, a.decimals) : "—"} - -
      - ) : ( - - - - - - - - - - - - - {vault.assets.map((a) => { - const v = vault.velocity[a.address.toLowerCase()]; - return ( - - - - - - - - - ); - })} - -
      AssetRoutine up toHigh up toPer transactionDaily capLoss envelope
      {a.symbol}
      {fmtAmount(a.limits.lowMax, a.decimals)}{fmtAmount(a.limits.highMax, a.decimals)}{a.limits.perTxMax ? fmtAmount(a.limits.perTxMax, a.decimals) : "no cap"}{a.limits.dailyMax ? fmtAmount(a.limits.dailyMax, a.decimals) : "no cap"}{v && v.envelope ? `${fmtAmount(v.envelopeSpent, a.decimals)} / ${fmtAmount(v.envelope, a.decimals)}${v.envelopeResetsAt > 0n ? ` · resets ${fmtRelative(v.envelopeResetsAt)}` : ""}` : "off"}
      - )} -
      - Payments above the routine threshold need more approvals. Above the high threshold they also need a guardian and a delay. Exposure is measured per asset; V1 has no price oracle. -
      -
      - - ); -} diff --git a/web/src/pages/CreateVault.tsx b/web/src/pages/CreateVault.tsx deleted file mode 100644 index 81f3e72..0000000 --- a/web/src/pages/CreateVault.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import { useMemo, useState } from "react"; -import { useAccount, useConnect, useDisconnect, usePublicClient } from "wagmi"; -import { isAddress, keccak256, stringToHex } from "viem"; -import { SkurFactoryAbi } from "../abi/SkurFactory"; -import { Button, Field, KV, TxStatus } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { NetworkGuard } from "../components/NetworkGuard"; -import { IconWallet } from "../components/icons"; -import { useTx } from "../hooks/useTx"; -import { DEPLOYMENTS, NATIVE_ASSET } from "../config/chain"; -import { fmtAmount, fmtDuration } from "../lib/format"; -import { policyToContract, validateCounts, validatePolicy } from "../lib/policy"; -import { TEMPLATES, type TemplateId } from "../lib/templates"; -import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER } from "../lib/types"; -import { useVaultLabel } from "../state/vaultLabel"; - -type MemberRow = { address: string; roles: number }; - -/** app.safe.global/new-safe/create: numbered step card on the left, account preview on the right. */ -export function CreateVault({ onCreated, onCancel }: { onCreated: (a: `0x${string}`) => void; onCancel: () => void }) { - const { address, isConnected } = useAccount(); - const { connectors, connect, isPending } = useConnect(); - const { disconnect } = useDisconnect(); - const client = usePublicClient(); - const [step, setStep] = useState<1 | 2 | 3>(1); - const [name, setName] = useState(""); - const [templateId, setTemplateId] = useState("startup"); - const template = TEMPLATES.find((t) => t.id === templateId)!; - const [members, setMembers] = useState([{ address: address ?? "", roles: ROLE_OWNER | ROLE_APPROVER | ROLE_EXECUTOR }, { address: "", roles: ROLE_OWNER | ROLE_APPROVER }, { address: "", roles: ROLE_GUARDIAN }]); - const salt = useMemo(() => `vault-${Date.now()}`, []); - const predicted = useMemo(() => (address ? keccak256(stringToHex(salt)) : null), [address, salt]); - const [, setLabel] = useVaultLabel(null); - const tx = useTx(async () => { - if (!client || !address || !predicted) return; - const v = await client.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "predictVaultAddress", args: [address, predicted] }); - try { - const labels = JSON.parse(window.localStorage.getItem("skur.vaultLabels") ?? "{}"); - labels[v.toLowerCase()] = name || "Treasury vault"; - window.localStorage.setItem("skur.vaultLabels", JSON.stringify(labels)); - } catch { - /* ignore */ - } - setLabel(name); - onCreated(v); - }); - - const counts = members.reduce( - (a, m) => ({ owners: a.owners + (m.roles & 1 ? 1 : 0), approvers: a.approvers + (m.roles & 2 ? 1 : 0), executors: a.executors + (m.roles & 4 ? 1 : 0), guardians: a.guardians + (m.roles & 8 ? 1 : 0) }), - { owners: 0, approvers: 0, executors: 0, guardians: 0 }, - ); - const errors = useMemo(() => { - const e = [...validatePolicy(template.policy), ...validateCounts(template.policy, counts.owners, counts.approvers, counts.executors, counts.guardians)]; - const addrs = members.map((m) => m.address.toLowerCase()); - if (members.some((m) => !isAddress(m.address))) e.push("Every member needs a valid address."); - if (new Set(addrs).size !== addrs.length) e.push("Duplicate member address."); - if (members.some((m) => m.roles === 0)) e.push("Every member needs at least one role."); - return e; - }, [template, counts, members]); - - const setRow = (i: number, patch: Partial) => setMembers((ms) => ms.map((m, j) => (j === i ? { ...m, ...patch } : m))); - const toggleRole = (i: number, b: number) => - setRow(i, { roles: b === ROLE_GUARDIAN ? (members[i].roles & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((members[i].roles & b ? members[i].roles & ~b : members[i].roles | b) & ~ROLE_GUARDIAN) }); - - const create = () => { - if (!predicted) return; - tx.send({ - address: DEPLOYMENTS.factory, - abi: SkurFactoryAbi, - functionName: "createVault", - args: [predicted, members.map((m) => m.address as `0x${string}`), members.map((m) => m.roles), policyToContract(template.policy), [DEPLOYMENTS.testUsd, NATIVE_ASSET], [template.stable, template.native]], - }); - }; - - const titles = ["Name and template", "Signers and guardians", "Review and sign"]; - const descs = ["Name the vault and choose the policy it starts with. Every number can be changed later through governance.", "Owners govern, approvers confirm payments, executors execute. Guardians can only freeze, veto and recover, and the contract will not let them hold a treasury role.", "This is the policy the vault will enforce from its first block. Check it, then sign once."]; - - return ( -
      -
      - -
      - - {isConnected && address ? ( - - ) : ( - connectors.slice(0, 1).map((c) => ) - )} -
      -
      -
      -

      Create new Skur vault

      -
      -
      -
      -
      - {step} -
      -

      {titles[step - 1]}

      -

      {descs[step - 1]}

      -
      -
      -
      - {step === 1 && ( - <> - - setName(e.target.value)} placeholder="Main treasury" maxLength={40} /> - -
      Policy template
      -

      Pick the profile closest to your organisation. Every value can be tuned under Policies afterwards.

      -
      - {TEMPLATES.map((t) => ( - - ))} -
      - {!isConnected && ( -
      -
      -
      No wallet connected
      -
      Creating a vault is a transaction your wallet signs.
      -
      - {connectors.slice(0, 1).map((c) => )} -
      -
      -
      - )} - - )} - {step === 2 && ( - <> - - - - - - {members.map((m, i) => ( - - - {[ROLE_OWNER, ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN].map((b) => ( - - ))} - - - ))} - -
      MemberOwnerApproverExecutorGuardian
      -
      - {isAddress(m.address) ? : ?} - setRow(i, { address: e.target.value.trim() })} placeholder="0x…" style={{ height: 40 }} /> -
      -
      toggleRole(i, b)} />
      -
      - -
      -

      - {counts.owners} owners · {counts.approvers} approvers · {counts.executors} executors · {counts.guardians} guardians. The {template.name} template needs {template.minSigners}+ signers and {template.minGuardians}+ guardian{template.minGuardians === 1 ? "" : "s"}. -

      - {errors.length > 0 &&
      {errors.map((e) =>
      {e}
      )}
      } - - )} - {step === 3 && ( - <> - -

      The vault is a minimal proxy over the verified implementation. The factory that creates it keeps no authority over it; only the members listed above can act.

      - - - )} -
      -
      - - {step < 3 ? ( - - ) : ( - - )} -
      -
      - - -
      -
      -
      - ); -} diff --git a/web/src/pages/Docs.tsx b/web/src/pages/Docs.tsx deleted file mode 100644 index 81b4dd9..0000000 --- a/web/src/pages/Docs.tsx +++ /dev/null @@ -1,291 +0,0 @@ -import { useEffect } from "react"; -import { MarketingShell } from "../components/MarketingShell"; -import { DEPLOYMENTS, ARK_DEVNET_EXPLORER, ARK_DEVNET_RPC } from "../config/chain"; -import { POLICY_GROUPS } from "../lib/policyFields"; -import { TEMPLATES } from "../lib/templates"; -import { fmtDuration } from "../lib/format"; - -export type DocSlug = - | "introduction" | "quick-start" | "roles" | "risk-tiers" | "policy" | "recipients" - | "limits" | "modes" | "changes" | "recovery" | "mobile" | "contracts" | "invariants" | "limitations"; - -type Doc = { slug: DocSlug; title: string; group: string; body: () => React.ReactNode }; - -const H = ({ children }: { children: React.ReactNode }) =>

      {children}

      ; -const Note = ({ children }: { children: React.ReactNode }) =>
      {children}
      ; - -function Table({ head, rows }: { head: string[]; rows: React.ReactNode[][] }) { - return ( -
      - - {head.map((h) => )} - {rows.map((r, i) => {r.map((c, j) => )})} -
      {h}
      {c}
      -
      - ); -} - -const DOCS: Doc[] = [ - { - slug: "introduction", title: "Introduction", group: "Start", - body: () => ( - <> -

      Skur is a self-custodial treasury vault whose security requirements rise and fall with the risk of each transaction.

      -

      A multisignature wallet asks one question: did enough people sign? Skur asks a second one: should this transaction be allowed right now? Between a valid approval and the money sit amount tiers, recipient trust, velocity caps, a loss envelope, guardian veto and a firewall around policy changes. Every one is enforced by the vault contract, not by a server.

      - What Skur does not claim -

      Skur does not make signer compromise harmless. It limits and delays the damage when authorised credentials are misused. A stolen key alone cannot reach a tier's threshold unless you set that tier to one, and even then it is bounded by the per-transaction cap, the daily cap and the loss envelope.

      - Skur V1 runs on the Ark Constellation devnet, chain 9000. It has not been audited. Do not put real value behind it until an independent audit is complete. - - ), - }, - { - slug: "quick-start", title: "Quick start", group: "Start", - body: () => ( - <> -

      Three ways in, none of which require a deployment of your own.

      - Read the demo vault -

      Open the app and choose the demo vault. No wallet is needed to read a vault: balances, the queue, the policy and the security posture all come from the chain.

      - Create your own -
        -
      1. Connect a wallet on the Ark devnet. The app will offer to switch networks if you are on another chain.
      2. -
      3. Name the vault and pick the template closest to your organisation. Every value can be changed later through governance.
      4. -
      5. List the members and their roles. Owners govern, approvers confirm payments, executors execute, guardians hold the brake.
      6. -
      7. Review the policy the vault will enforce from its first block, then sign once.
      8. -
      - Send a payment -

      Enter the recipient, asset and amount. Before the wallet opens, the vault itself classifies the payment: the tier, the approvals it needs, whether a guardian must sign, how long it waits and why. Approvals are recounted against live membership at execution, and the caps are checked again.

      - - ), - }, - { - slug: "roles", title: "Roles", group: "Model", - body: () => ( - <> -

      Four roles, held as a bitmask. A member can hold several treasury roles; a guardian can hold none.

      - - Why guardians are exclusive -

      The contract refuses to give a guardian a treasury role, and refuses to give a treasury member the guardian role. That makes guardians a second control plane an attacker must breach separately, and one they cannot profit from: there is no withdrawal path from guardian authority.

      - - ), - }, - { - slug: "risk-tiers", title: "Risk tiers", group: "Model", - body: () => ( - <> -

      Every transfer is scored when it is proposed. The score sets the requirements, and the requirements are pinned to the proposal.

      - What the vault reads -
      - What the tier decides -

      The number of approvals, whether a guardian must confirm, and how long the proposal waits before it can execute. A proposal carries its requirements from the moment it is created, so a later policy change cannot lower the bar for something already in the queue.

      - The same rules run in the interface only to preview. The contract classifies independently at proposal time and checks the caps again at execution. - - ), - }, - { - slug: "policy", title: "Policy reference", group: "Reference", - body: () => ( - <> -

      Every control a vault enforces, and the rules a policy must satisfy to be valid.

      - {POLICY_GROUPS.map((g) => ( -
      - {g.title} -

      {g.sub}

      -
      [f.label, f.unit === "bps" ? "percent" : f.unit === "hours" ? "duration" : f.unit === "bool" ? "on or off" : "count", f.hint || "—"])} /> - - ))} - Validation -

      A policy the contract will not accept:

      -
        -
      • Routine approvals below one, or a tier requiring fewer approvals than the tier beneath it.
      • -
      • A governance threshold of zero, or above the number of owners.
      • -
      • A guardian requirement for critical transfers with a guardian threshold of zero.
      • -
      • A critical delay shorter than the high delay.
      • -
      • Exposure thresholds above 100%, out of order, or a hard block below the critical threshold.
      • -
      • An envelope window under one hour, or a proposal lifetime that does not exceed the longest delay by at least one hour.
      • -
      - Templates -
      [t.name, t.tagline, fmtDuration(t.policy.delayCritical), fmtDuration(t.policy.recipientActivationDelay), `${t.policy.envelopeBps / 100}% per ${fmtDuration(t.policy.envelopeWindow)}`])} /> - - ), - }, - { - slug: "recipients", title: "Recipients and trust", group: "Reference", - body: () => ( - <> -

      A recipient is a security object, not a string in a form.

      -
      -

      Registering a supplier early starts its activation clock, so its first real payment does not have to wait. Raising a recipient's trust loosens security: it waits out the policy-change delay and any guardian can veto it. Restricting or blocking takes effect as soon as owners approve.

      - - ), - }, - { - slug: "limits", title: "Limits and the circuit breaker", group: "Reference", - body: () => ( - <> -

      Caps are per asset and cumulative, so splitting a payment changes nothing.

      -
      - The breaker latches -

      The transfer that would cross the envelope is not paid. Instead the vault moves to Lockdown, where outgoing execution stops and only tightening changes, deposits, recovery and guardian actions still work. Leaving Lockdown needs owners and guardians together, and waits out the policy-change delay.

      - Buckets are anchored to a fixed window rather than a rolling one. An attacker who waits for a boundary gets two windows' worth in quick succession; the envelope is the backstop for that case. - - ), - }, - { - slug: "modes", title: "Security modes", group: "Reference", - body: () => ( - <> -
      -

      Raising the mode is instant and unilateral by design: in an incident, the cost of a false alarm is far lower than the cost of a delay. Lowering it is governance.

      - - ), - }, - { - slug: "changes", title: "Changing the policy", group: "Reference", - body: () => ( - <> -

      Changing the rules is as dangerous as moving the money, so it goes through its own firewall.

      -

      Every proposed change is classified. If it loosens any control, it is security-reducing and:

      -
        -
      • waits out the policy-change delay before it can execute,
      • -
      • can be vetoed by any single guardian at any point,
      • -
      • cannot be proposed at all while the vault is in Lockdown.
      • -
      -

      A change that tightens or keeps every control applies as soon as owners approve. Loosening includes fewer approvals, shorter delays, higher caps, a wider envelope, a higher exposure threshold, raising a recipient's trust, approving a new asset, adding authority to a member and weakening the guardian layer.

      - Proposals in flight keep the requirements pinned when they were created, so a loosening that activates later cannot lower the bar for something already queued. - - ), - }, - { - slug: "recovery", title: "Recovery", group: "Reference", - body: () => ( - <> -

      Replacing a lost or compromised signer without giving anyone a backdoor.

      -
        -
      1. Guardians propose replacing an address with a new one holding the same roles.
      2. -
      3. The proposal waits out the recovery delay. Any owner can cancel it during that window.
      4. -
      5. On execution the roles move across. The policy is untouched, and the vault moves to Elevated.
      6. -
      -

      Recovery cannot change thresholds, delays, caps or anyone else's roles. It is the narrowest possible operation: one address for another.

      - - ), - }, - { - slug: "mobile", title: "The phone app", group: "Reference", - body: () => ( - <> -

      iOS and Android, sharing this site's risk engine, policy rules and contract reads.

      -

      There is no wallet connection. A signer key is created on the phone or imported, kept in the device keychain, and used after a Face ID or Touch ID prompt. Give that address a role in a vault and it signs; without a role the app is a reader.

      -

      Everything the desktop does is there: balances, the queue, the confirm screen with the vault's own review, the policy editor, members, the address book, the attack simulator, security modes and recovery. Notifications are local: when the app reads the vault and finds a proposal that newly needs you, it raises one. Nothing is sent to a server.

      -

      It is not on the app stores. Build it from the repository with Expo.

      - - ), - }, - { - slug: "contracts", title: "Contracts and addresses", group: "Reference", - body: () => ( - <> -

      Skur V1 on the Ark Constellation devnet, chain 9000. Every address below is verified on the explorer.

      -
      {DEPLOYMENTS.factory}], - ["Vault implementation", {DEPLOYMENTS.vaultImplementation}], - ["Demo vault", {DEPLOYMENTS.demoVault}], - ["Skur Test USD", {DEPLOYMENTS.testUsd}], - ]} /> - Endpoints -
      {ARK_DEVNET_RPC}], ["Explorer", {ARK_DEVNET_EXPLORER.replace("https://", "")}]]} /> -

      Each vault is a minimal proxy over one verified implementation. The factory keeps no authority over the vaults it creates, and a vault has no admin and no upgrade path. Moving to a new version means creating a new vault and transferring funds under the old vault's own policy.

      - - ), - }, - { - slug: "invariants", title: "Invariants and testing", group: "Assurance", - body: () => ( - <> -

      Twelve properties, each with a test.

      -
        - {["No proposal executes before every active condition is met", "A guardian cannot move treasury assets through guardian authority alone", "Lockdown blocks ordinary outgoing execution", "Security-reducing policy changes never take effect immediately", "Cumulative outflow accounting cannot be bypassed by splitting", "A proposal cannot execute twice", "Removed signers cannot approve new actions", "Approvals cannot be duplicated or replayed", "New recipients cannot skip their activation delay", "Recovery cannot quietly weaken the policy", "Native and ERC-20 accounting reconciles", "External calls cannot re-enter an unsafe state"].map((t) =>
      1. {t}
      2. )} -
      -

      The suite is 95 tests: a unit test per control, fuzzed monotonicity properties, and a stateful handler driving random actors against the vault. Static analysis reports nothing above informational, sources are verified on the explorer, and the repository builds to byte-identical runtime bytecode.

      - - ), - }, - { - slug: "limitations", title: "Known limitations", group: "Assurance", - body: () => ( - <> -

      What Skur V1 does not do, stated plainly.

      -
        -
      • No audit. The contracts have not been reviewed by an independent firm.
      • -
      • No price oracle. Exposure is measured per asset, as a share of that asset's holdings, not of the treasury's value.
      • -
      • Anchored windows. Velocity and envelope buckets are anchored rather than rolling, so a boundary allows two windows in quick succession.
      • -
      • The breaker latches. Crossing the envelope stops the payment and freezes the vault; it does not reverse anything already paid.
      • -
      • Single-guardian vaults. Permitted, and a single point of failure for veto and recovery. Use more than one.
      • -
      • Devnet only. Endpoints and deployments target the Ark Constellation devnet.
      • -
      - - ), - }, -]; - -const GROUPS = ["Start", "Model", "Reference", "Assurance"]; - -export function Docs({ slug, onLaunch, onNavigate }: { slug: DocSlug; onLaunch: () => void; onNavigate: (s: DocSlug) => void }) { - const doc = DOCS.find((d) => d.slug === slug) ?? DOCS[0]; - const i = DOCS.indexOf(doc); - useEffect(() => { window.scrollTo(0, 0); }, [slug]); - return ( - -
      - -
      -
      Docs / {doc.group}
      -

      {doc.title}

      - {doc.body()} - -
      -
      -
      - ); -} - -export const DOC_SLUGS = DOCS.map((d) => d.slug); diff --git a/web/src/pages/Landing.tsx b/web/src/pages/Landing.tsx deleted file mode 100644 index 04b814c..0000000 --- a/web/src/pages/Landing.tsx +++ /dev/null @@ -1,299 +0,0 @@ -import { useEffect } from "react"; -import { MarketingShell } from "../components/MarketingShell"; -import { AppMockup } from "../components/Mockup"; -import { PhoneMockup } from "../components/PhoneMockup"; -import { ScoreTicker } from "../components/Ticker"; -import { Reveal } from "../components/Reveal"; -import { IconArrowRight, IconCheck, IconChevronRight } from "../components/icons"; -import { useCountUp } from "../lib/motion"; - -function Stat({ n, label }: { n: number; label: string }) { - const { ref, value } = useCountUp(n, 1400); - return ( -
      - {value} -
      {label}
      -
      - ); -} - -const FAQ: Array<[string, string]> = [ - ["What is Skur?", "A self-custodial treasury vault whose security requirements rise and fall with the risk of each transaction. It keeps multisignature approval and adds onchain rules about how much can move, where it can go and how long risky payments wait."], - ["How is that different from a multisig?", "A multisig asks one question: did enough people sign? Skur asks a second one: should this transaction be allowed right now? Amount tiers, recipient trust, daily caps, a loss envelope, guardian veto and a firewall around policy changes all sit between a valid approval and the money."], - ["Does Skur ever hold my funds or keys?", "No. The vault contract holds the assets and your wallets hold the keys. No Skur server is in the execution path. If this website disappears, the vault and its policy are still there and still reachable through the verified contracts."], - ["What happens if one of our signers is compromised?", "Alone, a stolen key cannot reach any tier's threshold unless you set that tier to one. Even then it is bounded by the routine cap, the daily cap and the loss envelope. If several keys are stolen, the larger payments still wait out a delay any guardian can use to veto, and the envelope freezes the vault on the first over-limit attempt."], - ["What can a guardian do?", "Freeze the vault, veto critical or security-reducing proposals, confirm the largest transfers and propose replacing a lost signer after a delay. Guardians hold no treasury role, so a stolen guardian key cannot move a single token."], - ["Which network does it run on?", "Skur V1 runs on the Ark Constellation devnet, chain 9000. Every endpoint lives in one configuration module, so testnet and mainnet are a configuration change rather than a rewrite."], - ["Has it been audited?", "Not yet. The contracts are verified on the explorer, covered by 95 tests including stateful invariant tests, and clean under static analysis. Do not put real value behind Skur before an independent audit."], -]; - -const HERO_CELLS: Array<[number, number]> = [[0, 130], [130, 260], [1180, 0], [1310, 0], [1310, 130], [910, 390], [1050, 260], [520, 0]]; - -/** Public landing page. */ -export function Landing({ onLaunch }: { onLaunch: () => void }) { - useEffect(() => { - const m = window.location.hash.match(/#\/#(.+)$/); - if (m) setTimeout(() => document.getElementById(m[1])?.scrollIntoView({ behavior: "smooth" }), 50); - }, []); - const words = "Treasury security that".split(" "); - - return ( - - - -
      -
      - {HERO_CELLS.map(([x, y], i) => )} -
      -
      12 invariants enforced by the vault, not by a server
      -

      - {words.map((w, i) => ( - {w}{" "} - ))} - - {["assumes", "compromise"].map((w, i) => ( - {w}{i === 0 ? " " : ""} - ))} - -

      -

      An approval proves someone was authorised. Skur decides whether the payment is safe: how much can move, where it can go, and how long the risky ones wait, even when your signers are compromised.

      -
      - - See how it works -
      -
      Self-custodialArk Constellation devnet · 9000Verified source
      -
      -
      -
      -
      -
      -
      -
      - -
      -
      - -

      Made for teams that hold real money onchain

      -

      Startups, DAOs, funds, nonprofits and family offices that need more than a signature count between a stolen key and the treasury.

      -
      -
      -
      - {[...Array(2)].flatMap((_, k) => ["Startups", "Protocols & DAOs", "Venture funds", "Nonprofits", "Family offices", "Finance teams", "Onchain service providers", "Grant programmes"].map((t) => ( - {t} - )))} -
      -
      -
      -
      - -
      -
      - -
      01 / Controls
      -

      Your treasury, under control

      -

      Every rule below is contract code, not a setting on our server. If Skur disappeared tomorrow, your vault and its policy would not.

      -
      - -
      -

      Risk-tiered approvals

      -

      The vault scores every payment from its amount, its share of holdings, who receives it, what already left today and the current security mode. The score sets how many approvals it needs, whether a guardian must sign, and how long it waits.

      -
      -
      - {["1,000 sUSD to a known supplier", "12,000 sUSD to a new address", "60,000 sUSD, 24% of holdings"].map((t) => {t})} -
      -
      S
      -
      - Low · 1 approval · executes now - High · 2 approvals · waits 1 day - Critical · 2 + a guardian · 1 day · vetoable -
      -
      -
      -
      -

      Recipient trust

      -

      Recipients are security objects, not strings. A never-seen address serves an activation delay and is treated as higher risk until it has. Owners can verify, trust, restrict or block anyone.

      -
      - {[["New", "activates in 23h", "#1b3a5c", "#cfe2ff", "0x7c4f…41e2"], ["Verified", "normal policy", "#1b4332", "#d1e7dd", "0x3a91…c0de"], ["Restricted", "always critical", "#4d3a05", "#fff3cd", "0xe2b7…9f10"], ["Blocked", "refused", "#4a1c22", "#f8d7da", "0x0d55…77aa"]].map(([s, d, bg, fg, addr]) => ( -
      {addr}{s} · {d}
      - ))} -
      -
      -
      -

      Velocity limits and a circuit breaker

      -

      Outflow is counted cumulatively, so a drain split into twenty small transfers hits the same wall as one large one. Cross the loss envelope and the vault freezes instead of paying.

      -
      -
      Left the vault today98,000 of 100,000 sUSD
      -
      -
      Loss envelope, 24 hours25,000 sUSD, then Lockdown
      -
      -
      -
      -
      -

      Independent guardians

      -

      A second control plane that can freeze, veto, confirm and recover, and that can never withdraw. Stealing one role is not enough.

      -
      -
      Treasury signers
      Propose · Approve · Execute
      -
      Guardians
      Freeze · Veto · Recover
      never withdraw
      -
      -
      -
      -

      Policy simulator

      -

      Run your policy against the attacks that actually happen, before you activate it. Verdicts come from the same rules the contract enforces, so the simulator cannot promise what the vault will refuse.

      -
      -
      - -
      -
      - -
      -
      - -
      02 / Guarantees
      -

      Security a finance team can read

      -

      Every control fits in one sentence, and every one is checked at execution, not only at approval.

      -
      - -

      No single point of failure

      Thresholds scale with risk, and guardians hold no treasury role. One stolen key, or one compromised role, cannot empty the vault.

      -

      Enforced onchain

      Limits, delays, vetoes and modes live in the vault contract. Requirements are pinned when a proposal is created and checked again when it executes.

      -

      Open source and verified

      Source is verified on the Ark explorer and the repository builds to byte-identical bytecode. Twelve invariants are proven with fuzz and stateful tests.

      -

      Recovery without a backdoor

      Guardians can replace a lost signer after a delay any owner can cancel. Recovery never touches the policy and leaves the vault in Elevated mode.

      -
      - - Verified with - Foundry fuzz and invariant tests - Slither - Blockscout source verification - OpenZeppelin 5 - -
      -
      - -
      -
      - -
      -
      03 / Policy firewall
      -

      A firewall around the policy itself

      -

      Changing the rules is as dangerous as moving the money. An attacker who can lower a threshold never needs to touch the withdrawal path.

      -
        -
      • Loosening any control waits; it never applies instantly
      • -
      • Any guardian can veto the change
      • -
      • Lockdown refuses it outright
      • -
      -
      -
      -
      -
      -
      - -
      -
      -
      04 / Compared

      Not every multisig is the same

      - -
      - - - - - - - - - - -
      SkurPlain multisigCustodial policy engine
      AuthorizationThreshold follows transaction riskFixed N-of-MConfigurable, off-chain
      Enough signers compromisedCaps, delays, guardian veto and a circuit breakerFunds goneDepends on the provider
      Policy tamperingDelayed, vetoable, blocked in LockdownImmediateProvider-controlled
      CustodySelf-custodial, no server in the pathSelf-custodialProvider holds keys or approvals
      TransparencyEvery rule and every version onchainOnchainLimited
      - -
      - - -
      - -
      "Control not only who can move treasury funds, but how much can move, where it can go, and what happens when risk changes."
      - The Skur thesis -
      - - - -
      -
      -
      - -
      -
      - -
      05 / Who it is for
      -

      Two roles. Two kinds of power.

      -

      Finance teams move the money. Guardians hold the brake. Neither can do the other's job.

      -
      - -
      -

      For finance teams

      -

      Tiered approvals, trusted recipients, daily caps and a plain-language review before every signature.

      - How teams use Skur -
      -
      -
      -

      For guardians

      -

      Freeze the vault, veto the risky and the security-reducing, confirm the largest transfers, recover a lost signer. Never touch a coin.

      - What a guardian can do -
      -
      -
      -
      -
      - -
      -
      - -
      06 / Lifecycle
      -

      How a payment moves

      -

      Requirements are fixed at step one. Limits are checked again at step four.

      -
      - -
      1

      Proposed and scored

      The vault reads the amount, its share of holdings, the recipient's trust, today's outflow and the security mode, then pins the tier and its requirements to the proposal.

      -
      2

      Reviewed in plain language

      Approvers see what leaves, what remains, who receives it and why the tier was assigned, before their wallet opens.

      -
      3

      Confirmed, or vetoed

      Approvals are recounted against live membership. Any guardian can veto a critical, probationary or security-reducing proposal at any time.

      -
      4

      Executed only if still safe

      Caps, exposure, recipient state and the loss envelope are checked again at execution. Over the envelope, the vault freezes instead of paying.

      -
      -
      -
      - -
      -
      - -
      -
      07 / On the phone
      -

      Skur goes with you

      -

      Read the treasury, review what is waiting and sign with a key kept in the phone's keychain, behind Face ID. iOS and Android, sharing this site's risk engine and policy rules.

      -
        -
      • Notified the moment a payment needs you
      • -
      • Checked against the policy before you sign
      • -
      • Guardians can freeze from anywhere
      • -
      - See the mobile app -
      -
      -
      -
      -
      - -
      -
      -
      08 / Questions

      Questions, answered plainly

      - -
      - {FAQ.map(([q, a]) => ( -
      - {q}+ -
      {a}
      -
      - ))} -
      -
      -
      -
      - - ); -} diff --git a/web/src/pages/Members.tsx b/web/src/pages/Members.tsx deleted file mode 100644 index cc48f37..0000000 --- a/web/src/pages/Members.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { useState } from "react"; -import { useAccount } from "wagmi"; -import { isAddress } from "viem"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { Badge, Button, CopyButton, Field, Modal, Section, TxStatus } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { IconPlus } from "../components/icons"; -import { useTx } from "../hooks/useTx"; -import type { VaultData } from "../hooks/useVault"; -import { fmtDuration } from "../lib/format"; -import { ROLE_APPROVER, ROLE_EXECUTOR, ROLE_GUARDIAN, ROLE_OWNER, roleNames } from "../lib/types"; - -/** Mirrors Safe's Settings › Setup: "Members" and "Required confirmations" as label/content sections. */ -export function Members({ vault, onChanged }: { vault: VaultData; onChanged: () => void }) { - const { address } = useAccount(); - const me = vault.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const isOwner = Boolean((me?.roles ?? 0) & ROLE_OWNER); - const tx = useTx(() => { onChanged(); setDialog(false); }); - const [dialog, setDialog] = useState(false); - const [target, setTarget] = useState(""); - const [bits, setBits] = useState(ROLE_APPROVER); - const signers = vault.members.filter((m) => !(m.roles & ROLE_GUARDIAN)); - const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); - const existing = vault.members.find((m) => m.address.toLowerCase() === target.toLowerCase()); - const adds = existing ? bits & ~existing.roles : bits; - const reducing = adds !== 0 || Boolean(existing && existing.roles & ROLE_GUARDIAN && !(bits & ROLE_GUARDIAN)); - const toggle = (b: number) => setBits((x) => (b === ROLE_GUARDIAN ? (x & ROLE_GUARDIAN ? 0 : ROLE_GUARDIAN) : ((x & b ? x & ~b : x | b) & ~ROLE_GUARDIAN))); - const edit = (addr: string, roles: number) => { setTarget(addr); setBits(roles); setDialog(true); }; - - const Row = ({ m }: { m: { address: `0x${string}`; roles: number } }) => ( -
      - - ark:{m.address} - - {roleNames(m.roles).map((r) => {r})} - - - - -
      - ); - - return ( - <> -
      -

      Signers

      -

      Owners govern, approvers confirm payments, executors execute once every condition holds. A member may hold several of these roles.

      -
      - -
      - {signers.map((m) => )} - -

      Guardians

      -

      Guardians can freeze the vault, veto risky or security-reducing proposals, confirm critical transfers and start a recovery. The contract will not let them hold a treasury role, so they can never move funds.

      - {guardians.length === 0 ?
      No guardian configured. Nobody independent can veto a proposal or freeze the vault.
      : guardians.map((m) => )} -
      - -
      -

      A routine transfer requires the confirmation of:

      -
      {vault.policy.approvalsLow} out of {vault.counts.approvers} approvers.
      -
      -
      High-risk transfer
      {vault.policy.approvalsHigh} of {vault.counts.approvers} approvers, then {fmtDuration(vault.policy.delayHigh)}
      -
      Critical transfer
      {vault.policy.approvalsCritical} of {vault.counts.approvers} approvers{vault.policy.guardianRequiredCritical ? ` + ${vault.policy.guardianThreshold} of ${vault.counts.guardians} guardians` : ""}, then {fmtDuration(vault.policy.delayCritical)}
      -
      Governance change
      {vault.policy.governanceThreshold} of {vault.counts.owners} owners{" "}(+ {fmtDuration(vault.policy.policyChangeDelay)} if security-reducing)
      -
      Recovery
      {vault.policy.guardianThreshold} of {vault.counts.guardians} guardians, then {fmtDuration(vault.policy.recoveryDelay)}; any owner can cancel
      -
      -

      Thresholds are part of the policy. Lowering any of them waits {fmtDuration(vault.policy.policyChangeDelay)}, and any guardian can veto the change.

      -
      - - {dialog && ( - setDialog(false)} footer={<>}> - setTarget(e.target.value.trim())} placeholder="0x…" /> -
      Roles (none = remove)
      -
      - {[[ROLE_OWNER, "Owner"], [ROLE_APPROVER, "Approver"], [ROLE_EXECUTOR, "Executor"], [ROLE_GUARDIAN, "Guardian"]].map(([b, label]) => ( - - ))} -
      - {isAddress(target) && ( -
      - {bits === 0 ? "Removing a member takes effect as soon as owners approve." : reducing ? `Adding authority or weakening the guardian layer loosens security: it waits ${fmtDuration(vault.policy.policyChangeDelay)} and any guardian can veto it.` : "Reducing a member's authority takes effect as soon as owners approve."} -
      - )} - -
      - )} - - ); -} diff --git a/web/src/pages/Mobile.tsx b/web/src/pages/Mobile.tsx deleted file mode 100644 index 1e85a10..0000000 --- a/web/src/pages/Mobile.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { MarketingShell, SubHero } from "../components/MarketingShell"; -import { PhoneMockup } from "../components/PhoneMockup"; -import { Reveal } from "../components/Reveal"; -import { IconBook, IconClock, IconGuard, IconLab, IconShield, IconTx } from "../components/icons"; - -export function Mobile({ onLaunch }: { onLaunch: () => void }) { - return ( - - The vault
      in your pocket} sub="Read the treasury, review what is waiting, and sign with the key on your phone. The same contracts, the same policy, no server in between." onLaunch={onLaunch}> - Build it yourself -
      - -
      -
      - - - - - -
      -
      - -
      -
      - -
      01 / On the phone
      -

      Everything the desktop does

      -

      Balances, the queue, the policy editor, members, the address book, the attack simulator and recovery. Nothing is read-only because you are on a phone.

      -
      - -

      Sign where you are

      A key created on the phone and kept in its keychain, behind Face ID or Touch ID. Nothing leaves the device but a signed transaction.

      -

      Checked before you sign

      Every payment is simulated against the vault first, so a refusal reads as plain language rather than a failed transaction.

      -

      Told when you are needed

      A notification when a proposal newly needs your confirmation, and a tap takes you straight to it.

      -

      Freeze from anywhere

      Guardians can raise the mode or veto a proposal from the phone the moment something looks wrong.

      -

      Scan, do not type

      The camera reads a vault or recipient address, so a 42-character address is never typed on a phone keyboard.

      -

      Test the policy

      The same attack scenarios as the desktop simulator, run against the live policy or any template.

      -
      -
      -
      - -
      -
      - -
      02 / Keys
      -

      No wallet connection to lose

      -

      The phone holds its own signer. Give that address a role in the vault and it signs; without a role the app is a reader.

      -
      - -

      Created on the device

      Generated on the phone or imported, stored in the keychain, never synced anywhere.

      -

      Several keys, one phone

      Hold an approver key and a guardian key side by side and choose which one signs.

      -

      Biometrics before every signature

      Face ID or Touch ID gates each signature, and can be turned off for a device you keep offline.

      -

      Losing the phone is recoverable

      Guardians replace a lost signer after a delay any owner can cancel. The policy is untouched.

      -
      -
      -
      - -
      -
      - -

      Built with Expo and React Native

      -

      iOS and Android from one codebase, sharing the risk engine, policy rules and contract reads with this website. Not on the stores yet: build it from the repository.

      - Read the mobile README -
      -
      -
      -
      - ); -} diff --git a/web/src/pages/Overview.tsx b/web/src/pages/Overview.tsx deleted file mode 100644 index 21ddf4b..0000000 --- a/web/src/pages/Overview.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { useState } from "react"; -import { tokenMark } from "../lib/tokens"; -import { NATIVE_ASSET } from "../config/chain"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, fmtDuration } from "../lib/format"; -import { Mode, Status } from "../lib/types"; -import { TxRow } from "../components/TxRow"; -import { Skeleton } from "../components/Reveal"; -import { Address, Button, Card, Empty, TokenIcon } from "../components/ui"; -import { IconArrowRight, IconBank, IconClock, IconGuard, IconLab, IconReceive, IconSend, IconShield } from "../components/icons"; -import { postureItems } from "./Security"; -import type { AppPage } from "../components/AppShell"; - -function splitAmount(s: string): [string, string] { - const [int, frac] = s.split("."); - return [int, frac ? `.${frac}` : ".00"]; -} - -/** app.safe.global/home: Total balance card, promo banner, Top assets, "Explore what's possible", Pending transactions. */ -export function Overview({ vault, onChanged, onNavigate, onNewTransaction }: { vault: VaultData; onChanged: () => void; onNavigate: (p: AppPage) => void; onNewTransaction: () => void }) { - const [showReceive, setShowReceive] = useState(false); - const [bannerClosed, setBannerClosed] = useState(false); - const pending = vault.proposals.filter((p) => p.status === Status.PENDING); - const stable = vault.assets.find((a) => a.address !== NATIVE_ASSET) ?? vault.assets[0]; - const native = vault.assets.find((a) => a.address === NATIVE_ASSET); - const items = postureItems(vault); - const weakest = items.find((i) => i.ok === "bad") ?? items.find((i) => i.ok === "warn"); - const [intPart, decPart] = stable ? splitAmount(fmtAmount(stable.balance, stable.decimals, undefined, 2)) : ["0", ".00"]; - const canPropose = vault.mode !== Mode.LOCKDOWN; - - return ( -
      -
      - -
      -
      -
      Total balance
      -
      - {intPart} - {decPart} {stable?.symbol} -
      -
      {native ? `+ ${fmtAmount(native.balance, native.decimals, native.symbol)}` : ""} · policy v{vault.policyVersion} · {vault.members.length} members
      -
      -
      - - - -
      -
      - {showReceive && ( -
      -
      Send KASH or any approved token to
      . Deposits are accepted in every mode, including Lockdown.
      -
      - )} -
      - - {weakest && !bannerClosed && ( -
      - -
      -

      {weakest.ok === "bad" ? "Strengthen your vault before funds arrive" : "Your vault is in good shape"}

      -

      {weakest.text}. {weakest.ok === "bad" ? "Fix it under Policies or Members." : "Everything else is confirmed; the details are under Security."}

      - -
      - -
      - )} - - onNavigate("assets")}>View all ›}> -
        - {vault.assets.map((a) => { - const v = vault.velocity[a.address.toLowerCase()]; - return ( -
      • - -
        -
        {tokenMark(a.symbol).name}
        -
        {fmtAmount(a.balance, a.decimals)} {a.symbol}
        -
        -
        -
        {fmtAmount(a.balance, a.decimals)}
        -
        {v && v.dailyMax ? `${fmtAmount(v.daySpent, a.decimals)} of ${fmtAmount(v.dailyMax, a.decimals)} today` : "no daily cap"}
        -
        -
      • - ); - })} -
      -
      - - -
      - - - - -
      -
      -
      - -
      - 0 ? : undefined}> - {vault.activityLoading ? ( -
      - - - -
      - ) : pending.length === 0 ? ( - Nothing waiting for a signature - ) : ( -
      - {pending.slice(0, 5).map((p) => )} -
      - )} -
      - onNavigate("policies")}>Edit ›}> -
      -
      Approvals
      Low {vault.policy.approvalsLow} · High {vault.policy.approvalsHigh} · Critical {vault.policy.approvalsCritical}{vault.policy.guardianRequiredCritical ? ` + ${vault.policy.guardianThreshold} guardian` : ""}
      -
      Delays
      High {fmtDuration(vault.policy.delayHigh)} · Critical {fmtDuration(vault.policy.delayCritical)}
      -
      New recipients wait
      {fmtDuration(vault.policy.recipientActivationDelay)}
      -
      Circuit breaker
      {vault.policy.envelopeBps ? `${vault.policy.envelopeBps / 100}% per ${fmtDuration(vault.policy.envelopeWindow)}` : "off"}
      -
      -
      -
      -
      - ); -} diff --git a/web/src/pages/Policies.tsx b/web/src/pages/Policies.tsx deleted file mode 100644 index 3129def..0000000 --- a/web/src/pages/Policies.tsx +++ /dev/null @@ -1,195 +0,0 @@ -import { useMemo, useRef, useState } from "react"; -import { useAccount } from "wagmi"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { Badge, Button, Section, TxLink, TxStatus } from "../components/ui"; -import { TokenIcon } from "../components/ui"; -import { useTx } from "../hooks/useTx"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, fmtBps, fmtDate, fmtDuration, parseAmount } from "../lib/format"; -import { limitReductions, policyReductions, policyToContract, validateCounts, validateLimits, validatePolicy } from "../lib/policy"; -import { TEMPLATES, type TemplateId } from "../lib/templates"; -import { ROLE_OWNER, type AssetLimits, type Policy } from "../lib/types"; - -import { H, POLICY_GROUPS, type PolicyField as F } from "../lib/policyFields"; -const GROUPS = POLICY_GROUPS; - -function Control({ f, value, onChange }: { f: F; value: number | boolean; onChange: (v: number | boolean) => void }) { - if (f.unit === "bool") { - return ( - - ); - } - if (f.unit === "count") { - const n = Number(value); - return ( - - - onChange(Math.max(0, Number(e.target.value)))} /> - - - ); - } - if (f.unit === "hours") { - return ( - - onChange(Math.round(Number(e.target.value) * H))} /> - hours - - ); - } - return ( - - onChange(Math.round(Number(e.target.value) * 100))} /> - % - - ); -} - -/** Policy editor laid out like Safe's settings: a label column, then grouped controls with live validation. */ -export function Policies({ vault, onChanged }: { vault: VaultData; onChanged: () => void }) { - const { address } = useAccount(); - const me = vault.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const isOwner = Boolean((me?.roles ?? 0) & ROLE_OWNER); - const [draft, setDraft] = useState(vault.policy); - // When a new version activates while the editor is untouched, follow the live policy instead of showing the stale one. - const lastPolicyRef = useRef(vault.policy); - const [seenVersion, setSeenVersion] = useState(vault.policyVersion); - if (vault.policyVersion !== seenVersion) { - setSeenVersion(vault.policyVersion); - if (JSON.stringify(draft) === JSON.stringify(lastPolicyRef.current)) setDraft(vault.policy); - lastPolicyRef.current = vault.policy; - } - const [template, setTemplate] = useState(null); - const tx = useTx(() => { onChanged(); }); - const errors = useMemo(() => [...validatePolicy(draft), ...validateCounts(draft, vault.counts.owners, vault.counts.approvers, vault.counts.executors, vault.counts.guardians)], [draft, vault.counts]); - const reductions = useMemo(() => policyReductions(vault.policy, draft), [vault.policy, draft]); - const changed = JSON.stringify(draft) !== JSON.stringify(vault.policy); - const set = (k: keyof Policy, v: number | boolean) => setDraft((d) => ({ ...d, [k]: v })); - const changedKeys = new Set((Object.keys(draft) as Array).filter((k) => draft[k] !== vault.policy[k])); - - return ( - <> -
      -
      v{vault.policyVersion}
      Active policy version
      -
      {vault.policy.approvalsLow}·{vault.policy.approvalsHigh}·{vault.policy.approvalsCritical}
      Approvals low · high · critical
      -
      {fmtDuration(vault.policy.delayCritical)}
      Critical delay & veto window
      -
      {vault.policy.envelopeBps ? fmtBps(vault.policy.envelopeBps) : "off"}
      Loss envelope per {fmtDuration(vault.policy.envelopeWindow)}
      -
      - -
      TemplatesStart from a profile instead of designing a policy from scratch. Choosing one only fills the editor; nothing is proposed until you say so.}> -
      - {TEMPLATES.map((t) => ( - - ))} -
      -
      - - {GROUPS.map((g) => ( -
      {g.title}{g.sub}}> - {g.fields.map((f) => ( -
      -
      -
      {f.label}
      - {f.hint &&
      {f.hint}
      } - {changedKeys.has(f.key) &&
      was {f.unit === "bool" ? (vault.policy[f.key] ? "Yes" : "No") : f.unit === "hours" ? fmtDuration(Number(vault.policy[f.key])) : f.unit === "bps" ? fmtBps(Number(vault.policy[f.key])) : String(vault.policy[f.key])}
      } -
      - set(f.key, v)} /> -
      - ))} -
      - ))} - -
      ProposeThe checks here mirror the contract's own validation. The contract has the final say.}> - {errors.length > 0 &&
      {errors.map((e) =>
      {e}
      )}
      } - {changed && errors.length === 0 && ( -
      -
      - {reductions.length ? ( - <>Security-reducing change. It waits {fmtDuration(vault.policy.policyChangeDelay)} after {vault.policy.governanceThreshold} owner approval{vault.policy.governanceThreshold === 1 ? "" : "s"} and any guardian can veto it: {reductions.join("; ")}. - ) : ( - <>Tightening-only change. It activates as soon as {vault.policy.governanceThreshold} owner{vault.policy.governanceThreshold === 1 ? "" : "s"} approve. - )} -
      -
      - )} - {!changed &&

      Nothing has changed yet. Edit a value above or pick a template.

      } -
      - - - {!isOwner && Connect an owner wallet to propose.} -
      - -
      - - - -
      HistoryEvery activated policy version is recorded onchain.}> - {vault.policyHistory.length === 0 ? ( -

      No policy versions recorded yet.

      - ) : ( -
      - {[...vault.policyHistory].reverse().map((h) => ( -
      Version {h.version}
      {fmtDate(h.activatedAt)} ·
      - ))} -
      - )} -
      - - ); -} - -function AssetLimitsSection({ vault, onChanged, isOwner }: { vault: VaultData; onChanged: () => void; isOwner: boolean }) { - const tx = useTx(onChanged); - const [assetAddr, setAssetAddr] = useState(vault.assets[0]?.address ?? ""); - const meta = vault.assets.find((a) => a.address === assetAddr); - const decimals = meta?.decimals ?? 18; - const fresh = (m?: typeof meta) => ({ - approved: m?.limits.approved ?? true, - lowMax: m ? fmtAmount(m.limits.lowMax, m.decimals, undefined, 6) : "", - highMax: m ? fmtAmount(m.limits.highMax, m.decimals, undefined, 6) : "", - perTxMax: m ? fmtAmount(m.limits.perTxMax, m.decimals, undefined, 6) : "0", - dailyMax: m ? fmtAmount(m.limits.dailyMax, m.decimals, undefined, 6) : "0", - }); - const [text, setText] = useState(() => fresh(meta)); - const pick = (addr: string) => { setAssetAddr(addr); setText(fresh(vault.assets.find((a) => a.address === addr))); }; - const parsed: AssetLimits | null = (() => { - const l = parseAmount(text.lowMax || "0", decimals), h = parseAmount(text.highMax || "0", decimals), p = parseAmount(text.perTxMax || "0", decimals), d = parseAmount(text.dailyMax || "0", decimals); - if (l === null || h === null || p === null || d === null) return null; - return { approved: text.approved, lowMax: l, highMax: h, perTxMax: p, dailyMax: d }; - })(); - const errors = parsed ? validateLimits(parsed) : ["Enter valid amounts."]; - const current = meta?.limits ?? { approved: false, lowMax: 0n, highMax: 0n, perTxMax: 0n, dailyMax: 0n }; - const reductions = parsed ? limitReductions(current, parsed) : []; - - return ( -
      Asset limitsTiers and caps for each asset, in that asset's own units. Approving a new asset loosens security and goes through the delayed path.}> -
      - {vault.assets.map((a) => ( - - ))} - pick(e.target.value.trim())} placeholder="or paste a token address" style={{ maxWidth: 320, height: 40 }} /> -
      -
      Approved
      Unapproved assets cannot be paid out.
      -
      Routine up to
      At or below this amount a payment is Low tier.
      setText((t) => ({ ...t, lowMax: e.target.value }))} />
      -
      High up to
      Above this a payment is Critical.
      setText((t) => ({ ...t, highMax: e.target.value }))} />
      -
      Per-transaction cap
      0 = no cap.
      setText((t) => ({ ...t, perTxMax: e.target.value }))} />
      -
      Daily cap
      Cumulative per 24h bucket. 0 = no cap.
      setText((t) => ({ ...t, dailyMax: e.target.value }))} />
      - {errors.length > 0 ?
      {errors.join(" ")}
      : ( -
      {reductions.length ? <>Security-reducing: {reductions.join("; ")}. Delayed {fmtDuration(vault.policy.policyChangeDelay)} and vetoable. : <>Tightening-only: applies once owners approve.}
      - )} -
      - - {reductions.length > 0 && Delayed {fmtDuration(vault.policy.policyChangeDelay)}} -
      - -
      - ); -} diff --git a/web/src/pages/Product.tsx b/web/src/pages/Product.tsx deleted file mode 100644 index f33ee29..0000000 --- a/web/src/pages/Product.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { MarketingShell, SubHero } from "../components/MarketingShell"; -import { AppMockup } from "../components/Mockup"; -import { Reveal } from "../components/Reveal"; -import { IconBank, IconBook, IconClock, IconGuard, IconLab, IconLayers, IconShield, IconTrend, IconTx } from "../components/icons"; - -export function Product({ onLaunch }: { onLaunch: () => void }) { - return ( - - Multisig approvals,
      plus a firewall} sub="Keep the N-of-M you already trust. Add the controls that decide whether a valid approval should move money right now." onLaunch={onLaunch}> - Read the security model -
      - -
      -
      - -

      Six controls between an approval and the money

      -

      Each one is contract code you can read on the explorer. The interface never shows a rule the vault does not enforce.

      -
      - -

      Risk-tiered approvals

      Amount, share of holdings, recipient trust, today's outflow and the security mode set the tier. The tier sets the approvals, the guardian sign-off and the wait.

      -

      Recipient trust

      A never-seen address waits out an activation delay and is treated as higher risk until then. Owners can verify, trust, restrict or block any recipient through governance.

      -

      Velocity limits

      Per-transaction and 24-hour caps, counted cumulatively. Splitting a payment into pieces changes nothing.

      -

      Circuit breaker

      A loss envelope per window. The transfer that would cross it is not paid; the vault enters Lockdown instead, and leaving Lockdown takes owners, guardians and time.

      -

      Guardians

      An independent role that can freeze, veto, confirm critical transfers and recover a lost signer, and that has no path to withdraw.

      -

      Policy-change firewall

      Loosening any control waits for a delay, can be vetoed by a guardian, and cannot even be proposed while the vault is in Lockdown.

      -
      -
      -
      - -
      -
      - -

      Know exactly what you are signing

      -

      Before the wallet opens, the vault itself describes the payment: what leaves, what remains, who receives it, why it was scored the way it was, and what it needs to execute.

      -
      - -
      -

      A review written by the contract

      -

      The preview is the vault's own classification, read live. The interface cannot promise something the vault would later refuse.

      -
        -
      • Amount, treasury impact and remaining balance
      • -
      • Every reason the tier was assigned
      • -
      • Approvals, guardian sign-off and delay, exactly as pinned
      • -
      -
      -
      -
      -
      -
      - -
      -
      - -

      Test the policy before it is live

      -

      The simulator runs the attacks that actually happen against your policy, using the same deterministic rules the contract applies.

      -
      - -

      Attack scenarios

      One stolen key paying a new address. Three stolen keys taking 40%. A drain split into twenty transfers. A policy weakened before a withdrawal. A stolen guardian key.

      -

      Maximum possible loss

      One conservative number per asset: what could leave with no delay, what could leave within a day, and how long the largest transfers wait. Assumptions stated, never a guarantee.

      -

      Posture indicator

      Confirmed controls and obvious weaknesses, in plain words. It does not claim to measure absolute security.

      -
      - -
      -
      -
      -
      -
      - ); -} diff --git a/web/src/pages/Security.tsx b/web/src/pages/Security.tsx deleted file mode 100644 index dea85db..0000000 --- a/web/src/pages/Security.tsx +++ /dev/null @@ -1,166 +0,0 @@ -import { useState } from "react"; -import { useAccount, usePublicClient } from "wagmi"; -import { isAddress, stringToHex } from "viem"; -import { useQuery } from "@tanstack/react-query"; -import { SkurVaultAbi } from "../abi/SkurVault"; -import { Address, Badge, Button, CopyButton, Field, KV, Section, TxLink, TxStatus } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { useTx } from "../hooks/useTx"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, fmtDuration } from "../lib/format"; -import { computeMaxLoss } from "../lib/maxLoss"; -import { postureItems, type PostureItem } from "../lib/posture"; -export { postureItems, type PostureItem }; -import { Mode, MODE_LABEL, ROLE_GUARDIAN, ROLE_OWNER } from "../lib/types"; - -export function Security({ vault, onChanged }: { vault: VaultData; onChanged: () => void }) { - const { address } = useAccount(); - const me = vault.members.find((m) => m.address.toLowerCase() === address?.toLowerCase()); - const roles = me?.roles ?? 0; - const tx = useTx(onChanged); - const [reason, setReason] = useState(""); - const [oldSigner, setOldSigner] = useState(""); - const [newSigner, setNewSigner] = useState(""); - const guardians = vault.members.filter((m) => m.roles & ROLE_GUARDIAN); - const call = (functionName: string, args: readonly unknown[]) => tx.send({ address: vault.address, abi: SkurVaultAbi, functionName, args }); - const r32 = stringToHex(reason.slice(0, 31) || "manual", { size: 32 }); - const items = postureItems(vault); - const okCount = items.filter((i) => i.ok === "ok").length; - const pct = Math.round((okCount / items.length) * 100); - - return ( - <> -
      -
      -
      -
      {pct}%
      -
      Posture
      {okCount} of {items.length} controls confirmed
      -
      -
      -
      {MODE_LABEL[vault.mode]}
      Security mode
      -
      {guardians.length}
      Guardian{guardians.length === 1 ? "" : "s"} · {vault.policy.guardianThreshold} to confirm
      -
      {fmtDuration(vault.policy.delayCritical)}
      Critical veto window
      -
      - -
      Security modeAny owner or guardian can raise the mode at once. Lowering it needs owners and guardians together, and leaving Lockdown also waits out the policy-change delay.}> -
      - {[ - [Mode.NORMAL, "Normal", "Routine policy, standard approvals."], - [Mode.ELEVATED, "Elevated", "Every transfer one tier higher; per-transaction and daily caps halved."], - [Mode.LOCKDOWN, "Lockdown", "No outgoing execution, no loosening. Deposits, tightening, recovery and guardians keep working."], - ].map(([m, name, desc]) => ( -
      - {vault.mode === m && Current} -
      {name as string}
      -
      {desc as string}
      -
      - ))} -
      -
      - - setReason(e.target.value)} placeholder="phishing incident" maxLength={31} /> - -
      - {vault.mode < Mode.ELEVATED && } - {vault.mode < Mode.LOCKDOWN && } - {vault.mode > Mode.NORMAL && } - {!(roles & (ROLE_OWNER | ROLE_GUARDIAN)) && Connect an owner or guardian wallet to change the mode.} -
      - -
      - -
      GuardiansAn independent control plane. Guardians can freeze, veto, confirm and recover, and they can never move funds.}> - {guardians.length === 0 ? ( -
      No guardian configured. Critical transfers cannot be confirmed and nobody independent can veto or freeze.
      - ) : ( - guardians.map((g) => ( -
      - - ark:{g.address} - - Guardian -
      - )) - )} -
      -
      Veto
      any single guardian, any time before execution
      -
      Critical confirmation
      {vault.policy.guardianRequiredCritical ? `${vault.policy.guardianThreshold} of ${guardians.length}` : "not required"}
      -
      Leaving Lockdown
      {vault.policy.guardianThreshold} of {guardians.length} plus {vault.policy.governanceThreshold} owner{vault.policy.governanceThreshold === 1 ? "" : "s"}, after {fmtDuration(vault.policy.policyChangeDelay)}
      -
      -
      - -
      RecoveryReplace a lost or compromised signer with a new address holding the same roles. It executes after {fmtDuration(vault.policy.recoveryDelay)}, any owner can cancel it, and the vault moves to Elevated when it completes.}> -
      - - setOldSigner(e.target.value.trim())} placeholder="0x…" list="members" /> - {vault.members.map((m) => - - setNewSigner(e.target.value.trim())} placeholder="0x…" /> -
      -
      - - {!(roles & ROLE_GUARDIAN) && Only guardians can start a recovery.} -
      -
      - -
      Maximum possible lossA conservative upper bound for each asset under the stated assumptions. A bound, never a guarantee.}> - {vault.assets.map((a) => { - const l = computeMaxLoss(vault.policy, a.limits, a.balance, vault.mode); - const share = a.balance > 0n ? Number((l.immediate * 100n) / a.balance) : 0; - return ( -
      -
      -
      {share}%
      -
      -
      {fmtAmount(l.immediate, a.decimals, a.symbol)} could leave with no delay
      -
      bounded by {l.immediateBinding}
      -
      -
      - -
      - ); - })} -
        {computeMaxLoss(vault.policy, vault.assets[0]?.limits ?? { approved: false, lowMax: 0n, highMax: 0n, perTxMax: 0n, dailyMax: 0n }, 0n, vault.mode).assumptions.map((s) =>
      • {s}
      • )}
      -
      - -
      Security postureConfirmed controls and obvious weaknesses, in plain words. Not a measure of absolute security.}> - -
      - -
      Mode historyEvery mode change is recorded onchain with its reason.}> - {vault.modeHistory.length === 0 ?

      The mode has never changed.

      : ( -
      - {[...vault.modeHistory].reverse().map((h, i) => ( -
      {MODE_LABEL[h.previous]} → {MODE_LABEL[h.mode]}{h.reason ? ` · ${h.reason}` : ""}
      ·
      - ))} -
      - )} -
      - - ); -} - -export function Posture({ vault, compact = false }: { vault: VaultData; compact?: boolean }) { - const client = usePublicClient(); - const signers = vault.members.filter((m) => !(m.roles & ROLE_GUARDIAN)); - const { data: codeMap } = useQuery({ - queryKey: ["codes", vault.address, signers.map((s) => s.address).join(",")], - queryFn: async () => { - const out: Record = {}; - await Promise.all(signers.map(async (s) => { const code = await client!.getCode({ address: s.address }).catch(() => undefined); out[s.address.toLowerCase()] = Boolean(code && code !== "0x"); })); - return out; - }, - enabled: Boolean(client), - staleTime: 60_000, - }); - const eoa = codeMap ? signers.filter((s) => !codeMap[s.address.toLowerCase()]).length : null; - const items = postureItems(vault); - if (eoa !== null) items.push({ ok: eoa === 0 ? "ok" : "warn", text: eoa === 0 ? "All signers are smart-contract accounts" : `${eoa} of ${signers.length} signers are externally-owned keys` }); - return ( -
        - {items.map((i) => ( -
      • {i.text}
      • - ))} -
      - ); -} diff --git a/web/src/pages/SecurityPage.tsx b/web/src/pages/SecurityPage.tsx deleted file mode 100644 index 36f36d7..0000000 --- a/web/src/pages/SecurityPage.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { MarketingShell, SubHero } from "../components/MarketingShell"; -import { Reveal } from "../components/Reveal"; -import { IconCheck } from "../components/icons"; -import { DEPLOYMENTS } from "../config/chain"; - -const INVARIANTS = [ - ["No proposal executes before every active condition is met", "execution ordering · timelock · live recount"], - ["A guardian cannot move treasury assets through guardian authority alone", "role exclusivity · no withdrawal path"], - ["Lockdown blocks ordinary outgoing execution", "mode gate at execution"], - ["Security-reducing policy changes never take effect immediately", "policyReduces · timelock · veto"], - ["Cumulative outflow accounting cannot be bypassed by splitting", "24-hour bucket · loss envelope"], - ["A proposal cannot execute twice", "status written before any external call"], - ["Removed signers cannot approve new actions", "approvals recounted against live roles"], - ["Approvals cannot be duplicated or replayed", "one approval per signer per proposal"], - ["New recipients cannot skip their activation delay", "executable time ≥ activation · re-checked"], - ["Recovery cannot quietly weaken the policy", "same roles · policy untouched · Elevated after"], - ["Native and ERC-20 accounting reconciles", "SafeERC20 · totalOutflow matches balances"], - ["External calls cannot re-enter an unsafe state", "nonReentrant · effects before interactions"], -]; - -export function SecurityPage({ onLaunch }: { onLaunch: () => void }) { - return ( - - Built for the day
      a key is stolen} sub="A stolen key, a compromised laptop or a rogue signer should be a bad day, not the end of the treasury. This page is what holds, and what has not been proven yet." onLaunch={onLaunch}> - Verified source -
      - -
      -
      - -

      What we claim, and what we do not

      -

      Skur does not make signer compromise harmless. It adds independent, programmable controls that limit or delay the damage when authorised credentials are misused.

      -
      - -
      1

      One signer compromised

      Cannot reach any tier's threshold alone unless you set that tier to one, and even then is bounded by the routine cap, the daily cap and the loss envelope.

      -
      2

      Enough signers compromised

      High and critical delays give guardians a veto window, critical transfers need a guardian, and the envelope freezes the vault on the first over-limit attempt.

      -
      3

      An admin weakens the policy

      Loosening waits for the policy-change delay, can be vetoed by any guardian, and cannot be proposed at all while the vault is in Lockdown.

      -
      4

      A guardian is compromised

      There is no withdrawal path. Recovery is delayed and any owner can cancel it. A guardian can only freeze or veto.

      -
      -
      -
      - -
      -
      - -

      Twelve invariants, each with a test

      -

      Every control is enforced by the contract and proven by a unit, fuzz or stateful invariant test. The mapping is public in the security model.

      -
      - - {INVARIANTS.map(([t, how], i) => ( -
      -
      {i + 1}
      -

      {t}

      -

      {how}

      -
      - ))} -
      -
      -
      - -
      -
      - -

      Verification, honestly stated

      -

      What has been done, and what has not.

      -
      - -

      95 contract tests

      A unit test per control, fuzzed monotonicity properties, and a stateful handler that drives random actors against the vault.

      -

      Static analysis

      Slither reports nothing above informational. The linter is clean. Every narrowing cast is bounded and documented in place.

      -

      Verified and reproducible

      Sources are verified on Blockscout, and the repository builds to byte-identical runtime bytecode.

      -
      –

      Independent audit

      Not yet. Do not put real value behind Skur until one has been completed.

      -
      –

      Private pilot

      Not yet. The devnet deployment exists for evaluation.

      -

      Known limitations, listed

      Anchored 24-hour buckets, per-asset exposure without an oracle, a breaker that latches rather than refunds, single-guardian vaults. All in the model.

      -
      -
      -
      -
      - ); -} diff --git a/web/src/pages/Settings.tsx b/web/src/pages/Settings.tsx deleted file mode 100644 index d988973..0000000 --- a/web/src/pages/Settings.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useState } from "react"; -import { Address, Button, Field, Section, Switch } from "../components/ui"; -import { Identicon } from "../components/Identicon"; -import { ARK_DEVNET_EXPLORER, ARK_DEVNET_FAUCET, ARK_DEVNET_RPC, ARK_DEVNET_WS, DEPLOYMENTS } from "../config/chain"; -import type { VaultData } from "../hooks/useVault"; -import { useTheme } from "../state/theme"; -import { useVaultLabel } from "../state/vaultLabel"; - -type Tab = "setup" | "appearance" | "environment"; - -/** app.safe.global/settings: horizontal tabs, then label/content sections. */ -export function Settings({ vault, vaultAddress, onSwitchVault }: { vault?: VaultData; vaultAddress: `0x${string}` | null; onSwitchVault: () => void }) { - const [tab, setTab] = useState("setup"); - const { theme, toggle } = useTheme(); - const [label, setLabel] = useVaultLabel(vaultAddress); - - return ( - <> -
      - {(["setup", "appearance", "environment"] as Tab[]).map((t) => ( - - ))} -
      - - {tab === "setup" && ( - <> -
      - {vaultAddress ? ( - <> -
      - -
      -
      {label}
      -
      -
      -
      - - setLabel(e.target.value)} maxLength={40} /> - -
      -
      Policy version
      v{vault?.policyVersion ?? "—"}
      -
      Members
      {vault ? `${vault.members.length} (${vault.counts.guardians} guardians)` : "—"}
      -
      Proposals
      {vault ? `${vault.proposalCount} total · ${vault.pendingCount} pending · ${vault.executedCount} executed` : "—"}
      -
      Implementation
      -
      Factory
      -
      -
      - - ) : ( - - )} -
      -
      -
      Skur V1 · immutable
      -

      Every vault is a minimal proxy over one verified implementation, with no admin and no upgrade path. Moving to a new version means creating a new vault and transferring funds under this vault's own policy.

      - View source ↗ -
      - - )} - - {tab === "appearance" && ( -
      -

      Theme

      -

      Light is the default. Your choice is kept in this browser.

      - -
      - )} - - {tab === "environment" && ( -
      -

      If this interface ever disappears, the vault stays reachable through these endpoints and the verified contracts on the explorer.

      -
      -
      Chain
      Ark Constellation devnet · 9000 · KASH
      -
      RPC
      {ARK_DEVNET_RPC}
      -
      WebSocket
      {ARK_DEVNET_WS}
      - - -
      Test stablecoin (sUSD)
      -
      -
      - )} - - ); -} diff --git a/web/src/pages/Simulator.tsx b/web/src/pages/Simulator.tsx deleted file mode 100644 index 432c1b6..0000000 --- a/web/src/pages/Simulator.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useMemo, useState } from "react"; -import { Badge, Section } from "../components/ui"; -import { Reveal } from "../components/Reveal"; -import type { VaultData } from "../hooks/useVault"; -import { fmtAmount, parseAmount } from "../lib/format"; -import { runScenarios, type Verdict } from "../lib/simulator"; -import { TEMPLATES, type TemplateId } from "../lib/templates"; -import type { Policy } from "../lib/types"; - -const TONE: Record = { blocked: "ok", impossible: "ok", delayed: "info", escalated: "warn", allowed: "bad" }; -const TEXT: Record = { blocked: "Blocked", impossible: "Not possible", delayed: "Delayed", escalated: "Escalated", allowed: "Would succeed" }; - -/** Policy simulator: run a configured policy against the blueprint's attack scenarios. */ -export function Simulator({ vault }: { vault: VaultData | undefined }) { - const [source, setSource] = useState<"vault" | TemplateId>(vault ? "vault" : "startup"); - const [balanceText, setBalanceText] = useState("1,000,000"); - const [approvers, setApprovers] = useState(3); - const [guardians, setGuardians] = useState(1); - const stable = vault?.assets.find((a) => a.address !== "0x0000000000000000000000000000000000000000") ?? vault?.assets[0]; - const decimals = stable?.decimals ?? 6; - const symbol = stable?.symbol ?? "USD"; - const { policy, limits } = useMemo(() => { - if (source === "vault" && vault && stable) return { policy: vault.policy as Policy, limits: stable.limits }; - const t = TEMPLATES.find((x) => x.id === source) ?? TEMPLATES[0]; - return { policy: t.policy, limits: t.stable }; - }, [source, vault, stable]); - const balance = source === "vault" && stable ? stable.balance : (parseAmount(balanceText, decimals) ?? 0n); - const approverCount = source === "vault" && vault ? vault.counts.approvers : approvers; - const guardianCount = source === "vault" && vault ? vault.counts.guardians : guardians; - const results = useMemo(() => runScenarios({ policy, limits, balance, decimals, symbol, approverCount, guardianCount }), [policy, limits, balance, decimals, symbol, approverCount, guardianCount]); - const stopped = results.filter((r) => r.verdict !== "allowed").length; - const pct = Math.round((stopped / results.length) * 100); - - return ( - <> -
      -
      -
      -
      {stopped}/{results.length}
      -
      Scenarios stopped or delayed
      verdicts use the contract's own rules
      -
      -
      -
      {results.filter((r) => r.verdict === "blocked" || r.verdict === "impossible").length}
      Blocked outright
      -
      {results.filter((r) => r.verdict === "delayed").length}
      Delayed with a veto window
      -
      r.verdict === "allowed") ? "" : ""}`} style={{ color: results.some((r) => r.verdict === "allowed") ? "var(--error)" : undefined }}>{results.filter((r) => r.verdict === "allowed").length}
      Would succeed
      -
      - -
      Configuration under testPick the live policy or a template, then adjust the treasury size and team to see how the verdicts move.}> -
      -
      - Policy - -
      - {source === "vault" && stable ? ( -
      Treasury balance
      - ) : ( - <> -
      Treasury balance ({symbol}) setBalanceText(e.target.value)} />
      -
      Approvers setApprovers(Number(e.target.value))} />
      -
      Guardians setGuardians(Number(e.target.value))} />
      - - )} -
      -
      - - - {results.map((r) => ( -
      -
      - {r.title} - {TEXT[r.verdict]} -
      -

      {r.narrative}

      -
        {r.detail.map((d, i) =>
      • {d}
      • )}
      -
      - ))} -
      -

      Blocked and Not possible mean the contract refuses. Delayed means guardians get a veto window. Escalated means more approvals are needed but nothing waits. Would succeed is a gap to close before the policy goes live.

      - - ); -} diff --git a/web/src/pages/Solutions.tsx b/web/src/pages/Solutions.tsx deleted file mode 100644 index a6b40fd..0000000 --- a/web/src/pages/Solutions.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { MarketingShell, SubHero } from "../components/MarketingShell"; -import { AppMockup } from "../components/Mockup"; -import { Reveal } from "../components/Reveal"; -import { IconArrowRight, IconBank, IconClock, IconGuard, IconLayers, IconShield, IconUsers } from "../components/icons"; -import { TEMPLATES } from "../lib/templates"; -import { fmtDuration } from "../lib/format"; - -export function Solutions({ onLaunch }: { onLaunch: () => void }) { - return ( - - Treasury control
      for onchain teams} sub="Approvals that scale with risk, recipients that earn trust, and guardians who can stop a bad day without ever being able to cause one." onLaunch={onLaunch} /> - -
      -
      - -

      Three steps to a protected treasury

      -

      Nobody designs a policy from first principles. Pick a template, name the people, sign once.

      -
      - -

      Name signers and guardians

      Owners govern, approvers confirm payments, executors execute. Guardians hold the brake and nothing else; the contract will not let them hold both.

      -

      Pick a policy template

      Six profiles, from Startup to Family Office, set the tiers, delays, caps and loss envelope. Every number can be tuned later through governance.

      -

      Operate behind a firewall

      Every payment is scored and reviewed in plain language. Every loosening of the policy waits, and any guardian can stop it.

      -
      -
      -
      - -
      -
      - -

      One vault, six starting points

      -

      Each template is a complete, valid policy. Start with the closest fit and tighten from there.

      -
      - - {TEMPLATES.map((t) => ( -
      -
      -

      {t.name}

      -

      {t.tagline}

      -

      - Critical transfers wait {fmtDuration(t.policy.delayCritical)} · new recipients wait {fmtDuration(t.policy.recipientActivationDelay)} · loss envelope {t.policy.envelopeBps / 100}% a day -

      -
      - ))} -
      -
      -
      - -
      -
      - -

      For guardians

      -

      A cold key in a drawer, a board member, a security firm: anyone who should be able to stop money but must never be able to move it.

      -
      - -
      -

      Hold the brake, not the wheel

      -

      The contract refuses to give a guardian any treasury role. That makes guardians the second control plane an attacker has to breach, and the one they cannot profit from.

      -
        -
      • Freeze the vault the moment something looks wrong
      • -
      • Veto critical and security-reducing proposals
      • -
      • Replace a lost signer after a delay owners can cancel
      • -
      -
      -
      -
      -
      -
      - -
      -
      - -

      No custody. No fees on assets. No lock-in.

      -

      Skur never holds a key and never takes a percentage. The vault is an immutable contract you can reach with any compatible interface.

      -
      - -
      -

      Self-custodial by construction

      -

      The vault contract holds the assets. Your wallets hold the keys. The factory that created the vault has no authority over it.

      - Read the security model -
      -
      -

      Reachable without Skur

      -

      The contracts are verified on the Ark explorer and every endpoint lives in one configuration file. If this site disappears, your vault does not.

      - Open the explorer -
      -
      -
      -
      -
      -
      - ); -} diff --git a/web/src/pages/Transactions.tsx b/web/src/pages/Transactions.tsx deleted file mode 100644 index c925752..0000000 --- a/web/src/pages/Transactions.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { useMemo, useState } from "react"; -import { TxRow } from "../components/TxRow"; -import { Button, Empty } from "../components/ui"; -import { IconTx } from "../components/icons"; -import type { ProposalView, VaultData } from "../hooks/useVault"; -import { Kind, Mode, Status } from "../lib/types"; - -type Tab = "queue" | "history"; -type Filter = "all" | "transfers" | "governance"; - -function dayLabel(ts: bigint): string { - return new Date(Number(ts) * 1000).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }).toUpperCase(); -} - -function groupByDay(list: ProposalView[]): Array<[string, ProposalView[]]> { - const out: Array<[string, ProposalView[]]> = []; - for (const p of list) { - const label = dayLabel(p.createdAt); - const last = out[out.length - 1]; - if (last && last[0] === label) last[1].push(p); - else out.push([label, [p]]); - } - return out; -} - -/** app.safe.global/transactions: Queue / History tabs, date-grouped card rows. */ -export function Transactions({ vault, onChanged, onNewTransaction }: { vault: VaultData; onChanged: () => void; onNewTransaction: () => void }) { - const [tab, setTab] = useState("queue"); - const [filter, setFilter] = useState("all"); - const queue = useMemo(() => vault.proposals.filter((p) => p.status === Status.PENDING), [vault.proposals]); - const history = useMemo(() => vault.proposals.filter((p) => p.status !== Status.PENDING), [vault.proposals]); - const list = (tab === "queue" ? queue : history).filter((p) => (filter === "all" ? true : filter === "transfers" ? p.kind === Kind.TRANSFER : p.kind !== Kind.TRANSFER)); - const groups = groupByDay(list); - - return ( - <> -
      -
      - - -
      -
      - - -
      -
      - - {vault.logsFailed &&
      The chain's event log could not be read, so purposes and history details are missing. Proposals below come straight from contract state.
      } - {vault.activityLoading ? ( - Reading proposals and history from the chain… - ) : list.length === 0 ? ( -
      - }>{tab === "queue" ? "Proposals waiting for confirmation or execution will appear here" : "Executed, cancelled and vetoed proposals will appear here"} -
      - ) : ( - groups.map(([label, items]) => ( -
      -
      {label}
      - {items.map((p) => )} -
      - )) - )} - {tab === "queue" && queue.length > 0 &&

      Governance proposals need owner confirmations. Security-reducing ones also wait out their timelock, and any guardian can veto them.

      } - - ); -} diff --git a/web/src/pages/Welcome.tsx b/web/src/pages/Welcome.tsx deleted file mode 100644 index 78497ef..0000000 --- a/web/src/pages/Welcome.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { useState } from "react"; -import { useAccount, useConnect, useDisconnect, usePublicClient } from "wagmi"; -import { isAddress } from "viem"; -import { SkurFactoryAbi } from "../abi/SkurFactory"; -import { DEPLOYMENTS } from "../config/chain"; -import { Button, Field } from "../components/ui"; -import { NetworkGuard } from "../components/NetworkGuard"; -import { Identicon } from "../components/Identicon"; -import { IconArrowRight, IconWallet } from "../components/icons"; -import { short } from "../lib/format"; - -/** app.safe.global/welcome: a centred "Get started" card on a dark canvas. */ -export function Welcome({ onOpen, onCreate, onLanding }: { onOpen: (a: `0x${string}`) => void; onCreate: () => void; onLanding: () => void }) { - const { address, isConnected } = useAccount(); - const { connectors, connect, isPending } = useConnect(); - const { disconnect } = useDisconnect(); - const client = usePublicClient(); - const [tab, setTab] = useState<"accounts" | "watch">("accounts"); - const [watch, setWatch] = useState(""); - const [mine, setMine] = useState<`0x${string}`[] | null>(null); - - const loadMine = async () => { - if (!client || !address) return; - const v = await client.readContract({ address: DEPLOYMENTS.factory, abi: SkurFactoryAbi, functionName: "vaultsOf", args: [address] }).catch(() => []); - setMine([...v]); - }; - - return ( -
      -
      - -
      - - {isConnected && address ? ( - - ) : ( - connectors.slice(0, 1).map((c) => ( - - )) - )} -
      -
      - -
      -
      - - -
      -
      - New Skur V1 is live on the Ark Constellation devnet -
      - - {tab === "accounts" ? ( -
      -
      SSkur
      -

      Get started

      -

      Connect a wallet to create a vault, or open one you belong to.

      - {isConnected && address ? ( - <> - -
      OR
      - {mine === null ? ( - - ) : mine.length === 0 ? ( -

      This wallet is not a member of any vault yet. You can still open any vault by address.

      - ) : ( -
      - {mine.map((v) => ( - - ))} -
      - )} - {DEPLOYMENTS.demoVault && ( -

      - or open the -

      - )} - - ) : ( - <> - {connectors.slice(0, 1).map((c) => ( - - ))} -
      OR
      - - - )} -
      - ) : ( -
      -
      SSkur
      -

      Watch a vault

      -

      Read any vault's balances, policy and queue. No wallet needed.

      - - setWatch(e.target.value.trim())} placeholder="0x…" style={{ textAlign: "left" }} /> - - - {DEPLOYMENTS.demoVault && ( -

      - or open the -

      - )} -
      - )} -

      You interact directly with verified contracts on the Ark Constellation devnet. Skur never holds keys or funds.

      -
      - -
      - Skur V1 · Ark devnet - GitHub - Documentation - Explorer - Faucet -
      -
      - ); -} diff --git a/web/src/state/theme.ts b/web/src/state/theme.ts deleted file mode 100644 index 024ee9e..0000000 --- a/web/src/state/theme.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { createContext, useCallback, useContext, useEffect, useState } from "react"; - -export type Theme = "light" | "dark"; -const KEY = "skur.theme"; - -/** Dark by default, like the Safe app. */ -function initial(): Theme { - try { - const stored = window.localStorage.getItem(KEY); - if (stored === "light" || stored === "dark") return stored; - } catch { - /* ignore */ - } - return "light"; -} - -export function useThemeState(): { theme: Theme; toggle: () => void } { - const [theme, setTheme] = useState(initial); - useEffect(() => { - document.documentElement.setAttribute("data-theme", theme); - try { - window.localStorage.setItem(KEY, theme); - } catch { - /* ignore */ - } - }, [theme]); - const toggle = useCallback(() => setTheme((t) => (t === "light" ? "dark" : "light")), []); - return { theme, toggle }; -} - -export const ThemeContext = createContext<{ theme: Theme; toggle: () => void }>({ theme: "dark", toggle: () => {} }); -export const useTheme = () => useContext(ThemeContext); diff --git a/web/src/state/vaultAddress.ts b/web/src/state/vaultAddress.ts deleted file mode 100644 index d7389d6..0000000 --- a/web/src/state/vaultAddress.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useCallback, useEffect, useState } from "react"; -import { isAddress } from "viem"; -import { DEPLOYMENTS } from "../config/chain"; - -const KEY = "skur.vault"; - -function readInitial(): `0x${string}` | null { - try { - const fromHash = new URLSearchParams(window.location.hash.split("?")[1] ?? "").get("vault"); - if (fromHash && isAddress(fromHash)) return fromHash as `0x${string}`; - const stored = window.localStorage.getItem(KEY); - if (stored && isAddress(stored)) return stored as `0x${string}`; - } catch { - /* storage unavailable */ - } - if (DEPLOYMENTS.demoVault && DEPLOYMENTS.demoVault !== "0x0000000000000000000000000000000000000000") { - return DEPLOYMENTS.demoVault; - } - return null; -} - -/** The selected vault. Persisted per browser; the contracts are the source of truth for everything else. */ -export function useVaultAddress(): [`0x${string}` | null, (a: `0x${string}` | null) => void] { - const [addr, setAddr] = useState<`0x${string}` | null>(readInitial); - useEffect(() => { - try { - if (addr) window.localStorage.setItem(KEY, addr); - else window.localStorage.removeItem(KEY); - } catch { - /* ignore */ - } - }, [addr]); - const set = useCallback((a: `0x${string}` | null) => setAddr(a), []); - return [addr, set]; -} diff --git a/web/src/state/vaultLabel.ts b/web/src/state/vaultLabel.ts deleted file mode 100644 index eec26ef..0000000 --- a/web/src/state/vaultLabel.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useCallback, useEffect, useState } from "react"; - -const KEY = "skur.vaultLabels"; - -function readAll(): Record { - try { - return JSON.parse(window.localStorage.getItem(KEY) ?? "{}"); - } catch { - return {}; - } -} - -/** A private, browser-local display name for a vault. Never leaves the device; the chain only knows the address. */ -export function useVaultLabel(address: string | null): [string, (label: string) => void] { - const [labels, setLabels] = useState>(readAll); - useEffect(() => { - try { - window.localStorage.setItem(KEY, JSON.stringify(labels)); - } catch { - /* ignore */ - } - }, [labels]); - const key = address?.toLowerCase() ?? ""; - const set = useCallback((label: string) => setLabels((l) => ({ ...l, [key]: label })), [key]); - return [labels[key] ?? "Treasury vault", set]; -} diff --git a/web/src/styles.css b/web/src/styles.css deleted file mode 100644 index 9bcba5b..0000000 --- a/web/src/styles.css +++ /dev/null @@ -1,846 +0,0 @@ -/* Skur. Identity: charcoal #212529 with #FFD000 used the way hazard tape and a highlighter are used: sparingly, to mark what matters. - Space Grotesk for display, DM Sans for text, DM Mono for numbers and labels. Sharp 4-8px radii, hairlines, numbered sections. - Light: charcoal primary, yellow accent on white. Dark: #212529 canvas, #2b3035 panels, yellow primary with charcoal text. - Motion: entrance reveals, staggered lists, live scorer, tape that runs in Lockdown, reduced-motion aware. */ -@import url("https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700;800&family=DM+Mono:wght@400;500&family=Space+Grotesk:wght@500;600;700&display=swap"); - -:root { - --text: #212529; - --text-2: #6c757d; - --text-3: #adb5bd; - --canvas: #f1f3f5; - --panel: #ffffff; - --panel-2: #e9ecef; - --panel-3: #f8f9fa; - --border: #dee2e6; - --border-2: #adb5bd; - --brand: #212529; - --brand-hover: #343a40; - --brand-contrast: #ffffff; - --brand-bg: #e9ecef; - --brand-bg-2: #dee2e6; - --accent: #ffd000; - --accent-hover: #e6bb00; - --accent-contrast: #212529; - --accent-bg: #fff6c2; - --accent-bg-2: #ffec85; - --accent-soft: rgba(255, 208, 0, 0.35); - --success: #198754; - --success-bg: #d1e7dd; - --success-text: #0f5132; - --warning: #e5850b; - --warning-bg: #fff3cd; - --warning-text: #664d03; - --error: #dc3545; - --error-bg: #f8d7da; - --error-text: #842029; - --info: #0a58ca; - --info-bg: #cfe2ff; - --info-text: #052c65; - --review: #c2410c; - --review-bg: #ffe8d6; - --radius: 8px; - --radius-sm: 6px; - --sidebar: 236px; - --ease: cubic-bezier(0.22, 1, 0.36, 1); - --shadow-1: 0 1px 2px rgba(33, 37, 41, 0.06), 0 0 0 1px rgba(33, 37, 41, 0.04); - --shadow-2: 0 12px 32px rgba(33, 37, 41, 0.12); -} -[data-theme="dark"] { - --text: #f8f9fa; - --text-2: #adb5bd; - --text-3: #6c757d; - --canvas: #212529; - --panel: #2b3035; - --panel-2: #343a40; - --panel-3: #30353a; - --border: #343a40; - --border-2: #6c757d; - --brand: #ffd000; - --brand-hover: #ffdc33; - --brand-contrast: #212529; - --brand-bg: #3d3400; - --brand-bg-2: #4f4400; - --accent: #ffd000; - --accent-hover: #ffdc33; - --accent-contrast: #212529; - --accent-bg: #3d3400; - --accent-bg-2: #4f4400; - --accent-soft: rgba(255, 208, 0, 0.3); - --success: #75b798; - --success-bg: #1b4332; - --success-text: #d1e7dd; - --warning: #ffa94d; - --warning-bg: #4d2e05; - --warning-text: #fff3cd; - --error: #ea868f; - --error-bg: #4a1c22; - --error-text: #f8d7da; - --info: #6ea8fe; - --info-bg: #1b3a5c; - --info-text: #cfe2ff; - --review: #ffa94d; - --review-bg: #4a2a0b; - --shadow-1: 0 0 0 1px rgba(255, 255, 255, 0.04); - --shadow-2: 0 12px 32px rgba(0, 0, 0, 0.4); -} - -* { box-sizing: border-box; } -html, body { margin: 0; } -html { scroll-behavior: smooth; } -body { font-family: "DM Sans", system-ui, sans-serif; font-size: 14px; line-height: 20px; color: var(--text); background: var(--canvas); -webkit-font-smoothing: antialiased; transition: background 0.25s var(--ease), color 0.25s var(--ease); } -h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; } -h1 { font-size: 32px; line-height: 36px; } -h2 { font-size: 27px; line-height: 34px; } -h3 { font-size: 20px; line-height: 26px; } -h4 { font-size: 16px; line-height: 22px; } -p { margin: 0; } -a { color: inherit; text-decoration: none; } -code, .mono { font-family: "DM Mono", ui-monospace, Menlo, monospace; font-size: 12.5px; } -button, input, select, textarea { font-family: inherit; } -h1, h2, h3, .display, .balance-card .amount, .scorecard .v, .stats .v { font-family: "Space Grotesk", "DM Sans", system-ui, sans-serif; } -.muted { color: var(--text-2); } -.faint { color: var(--text-3); } -.small { font-size: 12px; line-height: 16px; } -.caption { font-size: 12px; line-height: 16px; color: var(--text-2); } -.overline { font-size: 11px; line-height: 14px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--text-2); } -.strong { font-weight: 700; } -.num { font-variant-numeric: tabular-nums; } -.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.accent { color: var(--text); background: var(--accent); padding: 0 4px; } -[data-theme="dark"] .accent { color: var(--accent); background: none; padding: 0; } - -/* ================================================================== motion */ -@keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } } -@keyframes fade { from { opacity: 0; } to { opacity: 1; } } -@keyframes pop { from { opacity: 0; transform: scale(0.96) translateY(8px); } to { opacity: 1; transform: none; } } -@keyframes shimmer { from { background-position: -600px 0; } to { background-position: 600px 0; } } -@keyframes cell { 0%, 100% { opacity: 0.15; } 50% { opacity: 0.6; } } -@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } } -@keyframes pulse-ring { 0% { box-shadow: 0 0 0 0 var(--accent-soft); } 70% { box-shadow: 0 0 0 14px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } -@keyframes spin { to { transform: rotate(360deg); } } -@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } -@keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } - -.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); } -.reveal.in { opacity: 1; transform: none; } -.reveal-stagger > * { opacity: 0; transform: translateY(16px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); } -.reveal-stagger.in > * { opacity: 1; transform: none; } -.reveal-stagger.in > *:nth-child(1) { transition-delay: 0.05s; } -.reveal-stagger.in > *:nth-child(2) { transition-delay: 0.12s; } -.reveal-stagger.in > *:nth-child(3) { transition-delay: 0.19s; } -.reveal-stagger.in > *:nth-child(4) { transition-delay: 0.26s; } -.reveal-stagger.in > *:nth-child(5) { transition-delay: 0.33s; } -.reveal-stagger.in > *:nth-child(6) { transition-delay: 0.40s; } -.reveal-stagger.in > *:nth-child(n+7) { transition-delay: 0.47s; } -.enter { animation: rise 0.5s var(--ease) both; } -.enter-2 { animation: rise 0.5s var(--ease) 0.08s both; } -.enter-3 { animation: rise 0.5s var(--ease) 0.16s both; } -.enter-4 { animation: rise 0.5s var(--ease) 0.24s both; } -.page-enter { animation: fade 0.35s var(--ease) both; } -.page-enter > * { animation: rise 0.45s var(--ease) both; } -.page-enter > *:nth-child(2) { animation-delay: 0.06s; } -.page-enter > *:nth-child(3) { animation-delay: 0.12s; } -.page-enter > *:nth-child(4) { animation-delay: 0.18s; } -.lift { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); } -.lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); } -.skeleton { position: relative; overflow: hidden; background: var(--panel-2); border-radius: 6px; color: transparent !important; } -.skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent); background-size: 600px 100%; animation: shimmer 1.4s linear infinite; } -[data-theme="dark"] .skeleton::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent); background-size: 600px 100%; } -.spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--border-2); border-top-color: var(--brand); animation: spin 0.8s linear infinite; display: inline-block; vertical-align: middle; } -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } - .reveal, .reveal-stagger > * { opacity: 1; transform: none; } -} - -/* ================================================================== buttons */ -.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 20px; border-radius: var(--radius-sm); border: 1px solid transparent; font-size: 14px; font-weight: 700; cursor: pointer; white-space: nowrap; transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease), box-shadow 0.15s var(--ease); } -.btn:active:not(:disabled) { transform: scale(0.98); } -.btn:disabled { opacity: 0.4; cursor: not-allowed; } -.btn-primary { background: var(--brand); color: var(--brand-contrast); } -.btn-primary:hover:not(:disabled) { background: var(--brand-hover); box-shadow: var(--shadow-2); } -.btn-secondary { background: transparent; color: var(--text); border-color: var(--border-2); } -.btn-secondary:hover:not(:disabled) { background: var(--panel-2); } -.btn-dark { background: var(--panel-2); color: var(--text); } -.btn-dark:hover:not(:disabled) { background: var(--brand-bg-2); } -.btn-danger { background: transparent; color: var(--error); border-color: var(--error); } -.btn-danger:hover:not(:disabled) { background: var(--error-bg); } -.btn-ghost { background: transparent; color: var(--text); } -.btn-ghost:hover:not(:disabled) { background: var(--panel-2); } -.btn-accent { background: var(--accent); color: var(--accent-contrast); } -.btn-accent:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 10px 28px rgba(255,208,0,0.35); } -.btn-white { background: #fff; color: #212529; border-color: #dee2e6; } -.btn-white:hover:not(:disabled) { background: #f1f3f5; } -.btn-black { background: #212529; color: #fff; } -.btn-black:hover:not(:disabled) { background: #343a40; } -.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; } -.btn-lg { height: 52px; padding: 0 28px; font-size: 16px; } -.btn-block { width: 100%; } -.icon-btn { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 999px; border: 0; background: var(--panel-2); color: var(--text-2); cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.15s; } -.icon-btn:hover { color: var(--text); background: var(--brand-bg-2); } -.icon-btn:active { transform: scale(0.94); } -.icon-btn.small { width: 28px; height: 28px; background: transparent; } -.icon-btn.small:hover { background: var(--panel-2); } - -/* ================================================================== app shell */ -.shell { display: flex; min-height: 100vh; } -.shell.collapsed { --sidebar: 68px; } -.shell.collapsed .sidebar { padding: 12px 8px 16px; } -.shell.collapsed .lbl, .shell.collapsed .nav-group, .shell.collapsed .promo, .shell.collapsed .nav .count, .shell.collapsed .tag-new { display: none; } -.shell.collapsed .home-pill { padding: 0 8px; } -.shell.collapsed .sidebar-top { flex-direction: column; gap: 6px; } -.shell.collapsed .nav button { justify-content: center; padding: 0; } -.shell.collapsed .nav button.active::before { left: -6px; } -.shell.collapsed .newtx .btn { font-size: 0; gap: 0; padding: 0; } -.shell.collapsed .newtx .btn svg { width: 16px; height: 16px; } -.sidebar { transition: width 0.25s var(--ease), padding 0.25s var(--ease); } -.sidebar { width: var(--sidebar); flex: none; background: var(--panel); border-right: 1px solid var(--border); padding: 12px 10px 16px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; overflow-y: auto; } -.home-pill { display: inline-flex; align-items: center; gap: 10px; height: 40px; padding: 0 14px 0 8px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; background: var(--accent-bg); color: var(--text); font-weight: 700; cursor: pointer; border: 0; align-self: flex-start; transition: background 0.15s; } -.home-pill:hover { background: var(--accent-bg-2); } -.home-pill .mark { width: 24px; height: 24px; border-radius: 4px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 13px; } -.sidebar-top { display: flex; align-items: center; justify-content: space-between; padding: 4px 4px 8px; } -.newtx { margin: 4px 0 16px; } -.newtx .btn { width: 100%; justify-content: center; border-color: var(--border-2); background: transparent; color: var(--text-2); font-weight: 500; } -.newtx .btn:not(:disabled) { color: var(--text); border-color: var(--accent); } -.newtx .btn:hover:not(:disabled) { background: var(--accent); color: var(--accent-contrast); } -.nav { display: flex; flex-direction: column; gap: 2px; position: relative; } -.nav button { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; height: 38px; padding: 0 12px; border-radius: var(--radius-sm); border: 0; background: transparent; color: var(--text); font-size: 14px; font-weight: 500; cursor: pointer; position: relative; transition: background 0.15s, color 0.15s; } -.nav button:hover { background: var(--panel-2); } -.nav button.active { background: var(--accent-bg); font-weight: 700; } -.nav button.active::before { content: ""; position: absolute; left: -10px; top: 8px; bottom: 8px; width: 3px; border-radius: 2px; background: var(--accent); animation: grow 0.3s var(--ease); transform-origin: center; } -.nav button .ico { width: 18px; height: 18px; color: var(--text-2); display: inline-grid; place-items: center; transition: color 0.15s, transform 0.2s var(--ease); } -.nav button:hover .ico { transform: translateX(2px); } -.nav button.active .ico { color: var(--text); } -[data-theme="dark"] .nav button.active .ico { color: var(--accent); } -.nav .count { margin-left: auto; font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; background: var(--review-bg); color: var(--review); } -.nav-group { font-size: 12px; color: var(--text-2); padding: 14px 12px 6px; } -.sidebar-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 2px; } -.promo { border-radius: 10px; padding: 16px; background: linear-gradient(180deg, var(--brand-bg) 0%, var(--panel) 100%); margin: 0 4px 12px; animation: pop 0.4s var(--ease); } -.promo .tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); margin-bottom: 8px; } -.promo h4 { font-size: 14px; margin-bottom: 4px; } -.promo p { font-size: 12px; color: var(--text-2); margin-bottom: 10px; } -.tag-new { display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); font-size: 11px; font-weight: 700; } - -.main { flex: 1; min-width: 0; padding: 20px 24px 48px; } -.main-inner { max-width: 1160px; } -.header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; animation: fade 0.4s var(--ease); } -.acct-pill { display: inline-flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px 0 8px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); cursor: pointer; border: 0; color: var(--text); text-align: left; max-width: 100%; transition: box-shadow 0.2s; } -.acct-pill:hover { box-shadow: var(--shadow-2); } -.acct-pill .name { font-size: 14px; font-weight: 700; } -.acct-pill .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 11.5px; color: var(--text-2); } -.acct-pill .addr b { color: var(--text); font-weight: 600; } -.acct-pill .meta { display: inline-flex; align-items: center; gap: 12px; margin-left: 8px; padding-left: 12px; border-left: 1px solid var(--border); font-size: 14px; } -.acct-pill .meta .chip-s { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 6px; background: var(--panel-2); font-size: 12px; color: var(--text-2); } -.tools-pill { display: inline-flex; align-items: center; gap: 6px; height: 56px; padding: 0 10px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); } -.tools-pill .btn { height: 36px; border-radius: 6px; } -.tools-pill .btn-secondary { border-color: var(--border-2); color: var(--text-2); } -.tools-pill .btn-secondary.on { color: var(--text); } - -/* ================================================================== cards, lists, tables */ -.card { background: var(--panel); border-radius: 10px; padding: 24px; margin-bottom: 24px; box-shadow: var(--shadow-1); } -.card.flush { padding: 0; overflow: hidden; } -.card.flush .card-head { padding: 20px 24px 8px; } -.card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } -.card-head h4 { font-size: 16px; } -.card-head .sub { color: var(--text-2); font-size: 14px; margin-top: 4px; } -.card-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } -.link { color: var(--text); font-weight: 500; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; display: inline-flex; align-items: center; gap: 4px; } -.link:hover { text-decoration: underline; } -.link.accent { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } -[data-theme="dark"] .link.accent { color: var(--accent); box-shadow: none; } -.grid { display: grid; gap: 24px; } -.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } -.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } -.overview-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 24px; align-items: start; } -@media (max-width: 1000px) { .overview-grid { grid-template-columns: 1fr; } } - -.balance-card .label { font-size: 15px; font-weight: 500; margin-bottom: 4px; color: var(--text-2); } -.balance-card .amount { font-size: 42px; line-height: 46px; font-weight: 800; letter-spacing: -0.03em; } -.balance-card .amount .dec { color: var(--text-3); font-weight: 600; } -.balance-card .actions { display: flex; gap: 8px; flex-wrap: wrap; } -.balance-card .actions .btn { background: var(--panel-2); color: var(--text); border: 0; height: 38px; font-weight: 600; } -.balance-card .actions .btn.hi { background: var(--brand); color: var(--brand-contrast); } -.balance-card .actions .btn:hover:not(:disabled) { background: var(--brand-bg-2); } -.balance-card .actions .btn.hi:hover:not(:disabled) { background: var(--brand-hover); } -.balance-row { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; } - -.banner { border-radius: 10px; padding: 20px 24px; display: flex; gap: 20px; align-items: center; margin-bottom: 24px; background: linear-gradient(90deg, #dee2e6 0%, #e9ecef 60%, #f1f3f5 100%); color: #212529; position: relative; overflow: hidden; } -[data-theme="dark"] .banner { background: linear-gradient(90deg, #343a40 0%, #2b3035 70%); color: #f8f9fa; } -.banner .glyph { width: 52px; height: 52px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; flex: none; animation: pulse-ring 2.4s ease-out infinite; } -.banner h4 { font-size: 18px; margin-bottom: 4px; } -.banner p { color: var(--text-2); margin-bottom: 8px; } -.banner .cta { font-weight: 700; color: var(--text); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; } -.banner .cta svg { transition: transform 0.2s var(--ease); } -.banner .cta:hover svg { transform: translateX(4px); } -.banner.warn { background: linear-gradient(90deg, #ffe5b4 0%, #fff3cd 70%); color: #212529; } -[data-theme="dark"] .banner.warn { background: linear-gradient(90deg, #4d3a05 0%, #2b3035 70%); color: #f8f9fa; } -.banner.warn .glyph { background: var(--warning); color: #212529; } -.banner .close { margin-left: auto; align-self: flex-start; background: none; border: 0; cursor: pointer; color: inherit; opacity: 0.6; } -.banner .close:hover { opacity: 1; } - -.list { list-style: none; margin: 0; padding: 0; } -.list > li { display: flex; align-items: center; gap: 14px; padding: 14px 24px; border-top: 1px solid var(--border); transition: background 0.15s; } -.list > li:hover { background: var(--panel-3); } -.list > li:first-child { border-top: 0; } -.list .grow { flex: 1; min-width: 0; } -.list .title { font-weight: 700; } -.list .sub { font-size: 12px; color: var(--text-2); } -.list .right { text-align: right; } -/* Colour and glyph come from lib/tokens.ts, so both interfaces draw an asset the same way. */ -.token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; line-height: 1; } -table { width: 100%; border-collapse: collapse; } -th, td { text-align: left; padding: 14px 24px; border-top: 1px solid var(--border); vertical-align: middle; } -thead th { border-top: 0; color: var(--text-2); font-weight: 500; font-size: 13px; } -tbody tr { transition: background 0.15s; } -tbody tr:hover { background: var(--panel-3); } -td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; } -.card:not(.flush) table th, .card:not(.flush) table td { padding-left: 0; padding-right: 0; } -.explore { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; } -.explore button { border: 1px solid var(--border); border-radius: 10px; background: var(--panel-3); color: var(--text); padding: 20px 16px; text-align: left; font-weight: 700; font-size: 15px; cursor: pointer; display: flex; flex-direction: column; gap: 20px; transition: transform 0.25s var(--ease), border-color 0.25s, box-shadow 0.25s; } -.explore button:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow-2); } -.explore .ico { width: 56px; height: 56px; color: var(--text); transition: transform 0.3s var(--ease); } -[data-theme="dark"] .explore .ico { color: var(--accent); } -.explore button { position: relative; overflow: hidden; } -.explore button::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 0.3s var(--ease); } -.explore button:hover::after { transform: scaleX(1); } -.explore button:hover .ico { transform: scale(1.08) rotate(-4deg); } - -/* ================================================================== pills */ -.pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 6px; font-size: 12px; font-weight: 700; white-space: nowrap; } -.pill-neutral { background: var(--panel-2); color: var(--text-2); } -.pill-ok { background: var(--success-bg); color: var(--success-text); } -.pill-warn { background: var(--warning-bg); color: var(--warning-text); } -.pill-bad { background: var(--error-bg); color: var(--error-text); } -.pill-info { background: var(--info-bg); color: var(--info-text); } -.pill-review { background: var(--review-bg); color: var(--review); } -[data-theme="light"] .pill-review, :root:not([data-theme="dark"]) .pill-review { color: #7a5c00; } -.pill-brand { background: var(--accent); color: var(--accent-contrast); } -.pill svg { width: 12px; height: 12px; } - -/* ================================================================== tabs */ -.tabs { display: flex; gap: 8px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; } -.tabs button { background: none; border: 0; padding: 10px 16px; font-size: 14px; font-weight: 700; cursor: pointer; color: var(--text-2); border-bottom: 2px solid transparent; margin-bottom: -1px; display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; transition: color 0.15s, border-color 0.15s; } -.tabs button:hover { color: var(--text); } -.tabs button.active { color: var(--text); border-bottom-color: var(--accent); } -.tabs-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; border-bottom: 1px solid var(--border); margin-bottom: 20px; } -.tabs-row .tabs { margin-bottom: 0; border-bottom: 0; } - -/* ================================================================== transactions */ -.date-label { font-size: 12px; font-weight: 500; color: var(--text-2); letter-spacing: 0.06em; text-transform: uppercase; margin: 20px 0 10px; } -.txcard { background: var(--panel); border-radius: 10px; margin-bottom: 8px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) both; } -.txcard .row { display: grid; grid-template-columns: 24px minmax(120px, 1fr) minmax(0, 1.4fr) 110px auto 24px; align-items: center; gap: 16px; padding: 18px 20px; cursor: pointer; border-radius: 10px; transition: background 0.15s; } -.txcard .row:hover { background: var(--panel-3); } -.txcard .kind { font-weight: 600; } -.txcard .amt { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; } -.txcard .when { color: var(--text-2); font-size: 13px; } -.txcard .status { text-align: right; font-weight: 700; } -.status-success { color: var(--success); } -.status-cancel { color: var(--text-2); } -.status-veto { color: var(--error); } -.txcard .detail { padding: 8px 20px 20px 60px; border-top: 1px solid var(--border); display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr); gap: 24px; animation: rise 0.3s var(--ease); } -@media (max-width: 900px) { .txcard .row { grid-template-columns: 24px 1fr auto 24px; } .txcard .hide-sm { display: none; } .txcard .detail { grid-template-columns: 1fr; padding-left: 20px; } } -.chev { transition: transform 0.2s var(--ease); color: var(--text-2); } -.chev.open { transform: rotate(180deg); } -.timeline { list-style: none; margin: 0; padding: 0; } -.timeline li { position: relative; padding: 0 0 16px 24px; } -.timeline li::before { content: ""; position: absolute; left: 4px; top: 5px; width: 10px; height: 10px; border-radius: 50%; background: var(--border-2); transition: background 0.3s; } -.timeline li.done::before { background: var(--accent); } -.timeline li.active::before { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-bg); animation: pulse-ring 2s ease-out infinite; } -.timeline li:not(:last-child)::after { content: ""; position: absolute; left: 8px; top: 16px; bottom: 0; width: 2px; background: var(--border); } -.timeline .t-title { font-weight: 700; } -.timeline .t-sub { font-size: 12px; color: var(--text-2); } -.timeline .signers { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; font-size: 12px; } -.tx-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; } -.empty-illus { padding: 64px 24px; text-align: center; color: var(--text-2); animation: fade 0.5s var(--ease); } -.empty-illus .glyph { width: 96px; height: 96px; border-radius: 50%; background: var(--panel-2); display: grid; place-items: center; margin: 0 auto 16px; color: var(--accent); animation: float 4s ease-in-out infinite; } - -/* ================================================================== sections (settings-style) */ -.section { background: var(--panel); border-radius: 10px; padding: 28px 32px; margin-bottom: 20px; display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 24px; box-shadow: var(--shadow-1); } -.section > h3 { font-size: 20px; } -.section > h3 small { display: block; font-size: 13px; font-weight: 400; color: var(--text-2); margin-top: 6px; line-height: 18px; } -.section .body { min-width: 0; } -.section .body h4 { margin-bottom: 8px; } -.section .body p.desc { color: var(--text-2); margin-bottom: 16px; font-size: 15px; } -@media (max-width: 860px) { .section { grid-template-columns: 1fr; } } -.member-row { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-top: 1px solid var(--border); } -.member-row:first-of-type { border-top: 0; } -.member-row .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 13px; } -.member-row .addr b { font-family: "DM Sans", sans-serif; font-weight: 700; } -.member-row .roles { display: flex; gap: 6px; flex-wrap: wrap; } -.member-row .tools { margin-left: auto; display: flex; gap: 4px; } -.kv { display: grid; grid-template-columns: 1fr; margin: 0; } -.kv div { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px; } -.kv div:first-child { border-top: 0; } -.kv dt { color: var(--text-2); } -.kv dd { margin: 0; text-align: right; font-weight: 500; } -.addr { display: inline-flex; align-items: center; gap: 6px; color: var(--text); } -.addr code { font-size: 12.5px; } -.addr:hover code { text-decoration: underline; } - -/* policy editor controls */ -.pfield { display: grid; grid-template-columns: minmax(0, 1fr) 160px; gap: 16px; align-items: center; padding: 14px 0; border-top: 1px solid var(--border); } -.pfield:first-child { border-top: 0; } -.pfield .lbl { font-weight: 600; } -.pfield .hint { font-size: 12px; color: var(--text-2); margin-top: 2px; } -.pfield input, .pfield select { height: 40px; } -.pfield .unit { display: flex; align-items: center; gap: 8px; } -.pfield .unit span { color: var(--text-2); font-size: 12px; white-space: nowrap; } -.pfield.changed .lbl::after { content: " •"; color: var(--warning); } -.stepper { display: inline-flex; align-items: center; border: 1px solid var(--border-2); border-radius: 8px; overflow: hidden; height: 40px; } -.stepper button { width: 36px; height: 100%; border: 0; background: var(--panel-2); color: var(--text); cursor: pointer; font-size: 16px; } -.stepper button:hover { background: var(--brand-bg-2); } -.stepper input { border: 0; width: 64px; text-align: center; height: 100%; border-radius: 0; } -.mode-hero { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } -.mode-hero > div { border: 1px solid var(--border); border-radius: 10px; padding: 18px; position: relative; transition: border-color 0.25s, transform 0.25s var(--ease); } -.mode-hero > div.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); transform: translateY(-2px); } -.mode-hero .m { font-size: 18px; font-weight: 800; margin-bottom: 4px; } -.mode-hero .d { color: var(--text-2); font-size: 13px; } -.mode-hero .cur { position: absolute; top: 12px; right: 12px; } -@media (max-width: 860px) { .mode-hero { grid-template-columns: 1fr; } } -.gauge { display: flex; align-items: center; gap: 16px; } -.gauge .ring { width: 72px; height: 72px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 18px; background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--panel-2) 0); position: relative; } -.gauge .ring::after { content: ""; position: absolute; inset: 8px; border-radius: 50%; background: var(--panel); } -.gauge .ring span { position: relative; z-index: 1; font-size: 15px; } -.scorecard { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; } -.scorecard > div { background: var(--panel); border-radius: 10px; padding: 16px 18px; box-shadow: var(--shadow-1); } -.scorecard .v { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } -.scorecard .l { font-size: 12px; color: var(--text-2); } - -/* ================================================================== forms */ -.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } -.field-label { font-size: 14px; font-weight: 700; } -.field-hint { font-size: 12px; color: var(--text-2); } -input, select, textarea { height: 48px; padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--panel); color: var(--text); width: 100%; font-size: 14px; transition: border-color 0.15s, box-shadow 0.15s; } -select option { background: var(--panel); color: var(--text); } -input[type="checkbox"] { height: auto; width: auto; accent-color: var(--accent); } -input[type="range"] { height: auto; padding: 0; border: 0; accent-color: var(--accent); } -input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } -input:read-only { color: var(--text-2); } -.row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; } -.row > .field { flex: 1; min-width: 180px; } -.inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } -.stack { display: flex; flex-direction: column; gap: 8px; } -.notice { padding: 14px 16px; border-radius: var(--radius-sm); margin: 12px 0; font-size: 14px; display: flex; gap: 10px; align-items: flex-start; animation: rise 0.3s var(--ease); } -.notice-ok { background: var(--success-bg); color: var(--success-text); } -.notice-bad { background: var(--error-bg); color: var(--error-text); } -.notice-warn { background: var(--warning-bg); color: var(--warning-text); } -.notice-info { background: var(--info-bg); color: var(--info-text); } -.empty { padding: 40px 24px; text-align: center; color: var(--text-2); } -.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; } -.switch .track { width: 40px; height: 22px; border-radius: 999px; background: var(--border-2); position: relative; transition: background 0.2s; } -.switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform 0.2s var(--ease); } -.switch.on .track { background: var(--accent); } -.switch.on .track::after { transform: translateX(18px); } -.segmented { display: inline-flex; padding: 4px; border-radius: 999px; background: var(--panel); gap: 4px; box-shadow: var(--shadow-1); } -.segmented button { border: 0; background: transparent; color: var(--text-2); font-weight: 700; padding: 10px 28px; border-radius: 999px; cursor: pointer; transition: background 0.2s, color 0.2s; } -.segmented button.active { background: var(--brand); color: var(--brand-contrast); } -.review { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel-3); padding: 4px 16px; } -.review-line { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); } -.review-line:first-child { border-top: 0; } -.review-line > span:first-child { color: var(--text-2); flex: none; } -.review-line > *:last-child { text-align: right; } -.reasons { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } -.bar { height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden; margin-top: 8px; } -.bar > i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: grow 0.8s var(--ease); } -.bar.warn > i { background: var(--warning); } -.bar.bad > i { background: var(--error); } -.templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; } -.template { border: 1px solid var(--border); border-radius: 10px; padding: 16px; cursor: pointer; background: var(--panel-3); text-align: left; color: var(--text); transition: border-color 0.2s, transform 0.2s var(--ease), box-shadow 0.2s; } -.template:hover { border-color: var(--border-2); transform: translateY(-2px); } -.template.active { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 3px var(--accent-soft); } -.template strong { display: block; margin-bottom: 4px; } -.scenario { border-radius: 10px; padding: 20px 24px; margin-bottom: 12px; background: var(--panel); border-left: 4px solid var(--border-2); box-shadow: var(--shadow-1); transition: transform 0.25s var(--ease), box-shadow 0.25s; } -.scenario:hover { transform: translateX(4px); box-shadow: var(--shadow-2); } -.scenario.blocked, .scenario.impossible { border-left-color: var(--success); } -.scenario.delayed { border-left-color: var(--info); } -.scenario.escalated { border-left-color: var(--warning); } -.scenario.allowed { border-left-color: var(--error); } -.scenario ul { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } -.posture { list-style: none; margin: 0; padding: 0; } -.posture li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; } -.posture .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-3); } -.posture .dot.ok { background: var(--success); } -.posture .dot.warn { background: var(--warning); } -.posture .dot.bad { background: var(--error); } -.assumptions { font-size: 12px; color: var(--text-2); margin: 12px 0 0; padding-left: 18px; } - -/* modal */ -.modal-backdrop { position: fixed; inset: 0; background: rgba(33, 37, 41, 0.55); backdrop-filter: blur(4px); z-index: 50; display: flex; align-items: flex-start; justify-content: center; padding: 48px 16px; overflow-y: auto; animation: fade 0.2s var(--ease); } -.modal { width: 100%; max-width: 640px; background: var(--panel); border-radius: 14px; box-shadow: 0 24px 64px rgba(0,0,0,0.35); animation: pop 0.3s var(--ease); } -.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px; border-bottom: 1px solid var(--border); } -.modal-body { padding: 24px; } -.modal-foot { display: flex; justify-content: space-between; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--border); } -.steps { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--text-2); } -.steps .step { display: inline-flex; align-items: center; gap: 6px; } -.steps .n { width: 20px; height: 20px; border-radius: 50%; display: inline-grid; place-items: center; background: var(--panel-2); font-weight: 700; font-size: 11px; transition: background 0.2s, color 0.2s; } -.steps .step.on .n { background: var(--accent); color: var(--accent-contrast); } -.steps .step.on { color: var(--text); font-weight: 700; } - -/* ================================================================== welcome / create */ -.entry { min-height: 100vh; background: radial-gradient(60% 40% at 50% 28%, var(--panel-2) 0%, var(--canvas) 60%); display: flex; flex-direction: column; } -.entry-top { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; animation: fade 0.4s var(--ease); } -.entry-top .logo { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 18px; } -.entry-top .logo .mark { width: 28px; height: 28px; border-radius: 7px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; } -.entry-center { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 40px 16px; gap: 16px; } -.entry-card { width: 100%; max-width: 440px; background: var(--panel); border-radius: 16px; padding: 32px; text-align: center; box-shadow: var(--shadow-2); animation: pop 0.45s var(--ease) both; } -.entry-card h2 { font-size: 24px; margin: 12px 0 8px; } -.entry-card p { color: var(--text-2); margin-bottom: 20px; } -.entry-card .or { display: flex; align-items: center; gap: 12px; color: var(--text-2); font-size: 12px; margin: 16px 0; } -.entry-card .or::before, .entry-card .or::after { content: ""; flex: 1; height: 1px; background: var(--border-2); } -.entry-note { max-width: 440px; width: 100%; background: var(--panel); border-radius: 10px; padding: 10px 16px; display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 14px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) 0.1s both; } -.entry-foot { display: flex; gap: 16px; justify-content: center; padding: 24px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; } -.entry-foot a { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } -[data-theme="dark"] .entry-foot a { color: var(--accent); box-shadow: none; } -.wordmark-lg { font-size: 28px; font-weight: 800; letter-spacing: -0.02em; display: inline-flex; align-items: center; gap: 10px; justify-content: center; } -.wordmark-lg .brace { color: var(--text-2); font-weight: 500; } -.create { max-width: 1160px; margin: 0 auto; padding: 24px; } -.create-grid { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 24px; align-items: start; } -@media (max-width: 960px) { .create-grid { grid-template-columns: 1fr; } } -.stepcard { background: var(--panel); border-radius: 10px; overflow: hidden; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease); } -.stepcard .progress { height: 4px; background: var(--border); } -.stepcard .progress i { display: block; height: 100%; background: var(--accent); transition: width 0.5s var(--ease); } -.stepcard .step-head { display: flex; gap: 16px; align-items: flex-start; padding: 24px 28px; border-bottom: 1px solid var(--border); } -.stepcard .step-head .n { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 12px; flex: none; margin-top: 2px; } -.stepcard .step-head h3 { font-size: 20px; } -.stepcard .step-head p { color: var(--text-2); margin-top: 2px; } -.stepcard .step-body { padding: 28px; animation: fade 0.3s var(--ease); } -.stepcard .step-foot { display: flex; justify-content: space-between; padding: 20px 28px; border-top: 1px solid var(--border); } -.preview { background: var(--panel); border-radius: 10px; padding: 24px; text-align: center; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease) 0.1s both; position: sticky; top: 24px; } -.preview h4 { font-size: 18px; margin: 8px 0 16px; } -.preview .kv div { text-align: left; } - -/* ================================================================== marketing site (safe.global) */ -.land { --lt: #212529; --ls: #6c757d; font-size: 16px; line-height: 24px; color: #212529; background: #fff; overflow-x: hidden; } -.land .wrap { max-width: 1216px; margin: 0 auto; padding: 0 24px; } -.land-nav { position: sticky; top: 0; z-index: 30; background: rgba(255,255,255,0.85); backdrop-filter: blur(12px); border-bottom: 1px solid transparent; transition: border-color 0.2s, box-shadow 0.2s; } -.land-nav.scrolled { border-bottom-color: #e9ecef; box-shadow: 0 4px 24px rgba(33,37,41,0.06); } -.land-nav .nav-right { display: flex; align-items: center; gap: 14px; } -.netchip { display: inline-flex; align-items: center; gap: 8px; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #6c757d; border: 1px solid #dee2e6; padding: 7px 10px; border-radius: 4px; } -.netchip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #ffd000; box-shadow: 0 0 0 3px rgba(255,208,0,0.25); } -.land-nav .wrap { height: 72px; display: flex; align-items: center; justify-content: space-between; gap: 24px; } -.land-nav .logo { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 22px; letter-spacing: -0.02em; font-family: "Space Grotesk", sans-serif; } -.land-nav .logo .mark { width: 28px; height: 28px; border-radius: 4px; background: #ffd000; color: #212529; display: grid; place-items: center; font-weight: 800; font-size: 14px; } -.land-nav .logo .brace { color: #6c757d; font-weight: 500; } -.land-nav nav { display: flex; gap: 32px; } -.land-nav nav a { color: #6c757d; font-weight: 500; position: relative; z-index: 0; transition: color 0.15s; } -.land-nav nav a::after { content: ""; position: absolute; left: -4px; right: -4px; bottom: 1px; height: 9px; z-index: -1; background: #ffd000; transform: scaleX(0); transform-origin: left; transition: transform 0.25s var(--ease); } -.land-nav nav a:hover, .land-nav nav a.on { color: #212529; } -.land-nav nav a:hover::after, .land-nav nav a.on::after { transform: scaleX(1); } -.land .announce { background: #212529; color: #fff; text-align: center; padding: 12px 24px; font-size: 14px; } -.land .announce a { font-weight: 500; } -.land .announce a span { color: #ffd000; } -.land .announce a span { display: inline-block; transition: transform 0.2s var(--ease); } -.land .announce a:hover span { transform: translateX(4px); } -.hero { position: relative; overflow: hidden; background: #f8f9fa; padding: 104px 0 0; text-align: center; } -.hero.sub-hero { padding: 88px 0 72px; } -.hero .grid-bg { position: absolute; inset: 0; background-image: linear-gradient(#e9ecef 1px, transparent 1px), linear-gradient(90deg, #e9ecef 1px, transparent 1px); background-size: 131px 131px; } -.hero .cell { position: absolute; width: 130px; height: 130px; background: linear-gradient(180deg, rgba(255,208,0,0) 0%, rgba(255,208,0,0.55) 100%); animation: cell 6s ease-in-out infinite; } -.hero .wrap { position: relative; } -.hero .eyebrow { font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 24px; animation: rise 0.6s var(--ease) both; display: flex; align-items: center; justify-content: center; gap: 12px; } -.hero .eyebrow b { background: #ffd000; color: #212529; padding: 3px 7px; font-weight: 500; } -.hero h1 { font-size: 84px; line-height: 84px; letter-spacing: -0.035em; font-weight: 700; max-width: 960px; margin: 0 auto 24px; animation: rise 0.7s var(--ease) 0.08s both; } -.hero h1 .w { display: inline-block; } -.hero .sub { font-size: 19px; line-height: 28px; color: #6c757d; max-width: 600px; margin: 0 auto 32px; animation: rise 0.7s var(--ease) 0.18s both; } -.hero .cta-row { animation: rise 0.7s var(--ease) 0.26s both; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } -.hero .mockwrap { position: relative; max-width: 960px; margin: 72px auto 0; text-align: left; animation: rise 0.9s var(--ease) 0.35s both; } -.hero .mock { border-radius: 8px 8px 0 0; box-shadow: 0 -8px 60px rgba(33,37,41,0.18); overflow: hidden; border: 1px solid #dee2e6; border-bottom: 0; } -.hero .float { position: absolute; right: -56px; bottom: 36px; width: 400px; animation: rise 0.9s var(--ease) 0.7s both; } -.hero .float .ticker { box-shadow: 0 30px 80px rgba(33,37,41,0.35), 0 0 0 1px rgba(255,255,255,0.06); } -@media (max-width: 1120px) { .hero .float { position: static; width: auto; margin: 24px 0 0; } .hero .mock { border-bottom: 1px solid #dee2e6; border-radius: 8px; } } -@media (max-width: 900px) { .hero h1 { font-size: 48px; line-height: 50px; } } -.land .light { background: #f8f9fa; padding: 96px 0; } -.land .white { background: #fff; padding: 96px 0; } -.land .dark { background: #212529; color: #fff; padding: 96px 0; } -.land h2 { font-size: 44px; line-height: 48px; letter-spacing: -0.03em; text-align: left; margin-bottom: 12px; font-weight: 700; max-width: 760px; } -.land .lead { text-align: left; color: #adb5bd; font-size: 17px; max-width: 640px; margin: 0 0 56px; } -.land .center h2, .land .center .lead { text-align: center; margin-left: auto; margin-right: auto; } -.land .light .lead, .land .white .lead { color: #6c757d; } -.marquee { overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); } -.marquee .track { display: flex; gap: 12px; width: max-content; animation: marquee 28s linear infinite; } -.marquee .track:hover { animation-play-state: paused; } -.marquee .chip-l { padding: 12px 22px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; border: 1px solid #dee2e6; background: #fff; font-weight: 600; white-space: nowrap; color: #212529; } -.bento { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } -.bento .big { grid-column: 1 / -1; } -.bcard { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 32px; min-height: 340px; background-image: radial-gradient(60% 40% at 50% 0%, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 100%); transition: transform 0.35s var(--ease), border-color 0.35s, box-shadow 0.35s; } -.bcard:hover { transform: translateY(-4px); border-color: #ffd000; box-shadow: 0 24px 60px rgba(0,0,0,0.35); } -.bcard h3 { font-size: 24px; margin-bottom: 8px; } -.bcard p { color: #adb5bd; margin-bottom: 24px; } -.bcard.center { text-align: center; } -.bcard .art { margin-top: 8px; } -@media (max-width: 860px) { .bento { grid-template-columns: 1fr; } } -.dashed { display: grid; grid-template-columns: 1fr 1fr; max-width: 900px; margin: 0 auto; } -.dashed > div { padding: 40px 32px 40px 48px; border-left: 1px dashed #495057; border-top: 1px dashed #495057; } -.dashed > div:nth-child(-n+2) { border-top: 0; } -.dashed > div:nth-child(odd) { border-left: 0; } -.dashed h4 { font-size: 18px; margin-bottom: 8px; } -.dashed p { color: #adb5bd; } -.badges { display: flex; gap: 40px; justify-content: center; align-items: center; flex-wrap: wrap; padding: 40px 0; border-top: 1px solid #343a40; color: #adb5bd; font-weight: 700; font-size: 18px; } -.badges .lbl { font-weight: 400; font-size: 14px; } -.shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; } -.shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; } -.shield p { color: #adb5bd; margin-bottom: 32px; max-width: 320px; } -.shield ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; font-size: 20px; font-weight: 700; } -.shield ul li { display: flex; gap: 12px; align-items: center; } -.shield ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 26px; height: 26px; } -.shield .tilt { transform: perspective(1200px) rotateY(-12deg) rotateX(4deg) rotate(6deg) scale(1.05); transform-origin: left center; border-radius: 10px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,0.5); transition: transform 0.6s var(--ease); } -.shield:hover .tilt { transform: perspective(1200px) rotateY(-6deg) rotateX(2deg) rotate(3deg) scale(1.03); } -@media (max-width: 900px) { .shield { grid-template-columns: 1fr; } .shield .tilt { transform: none; } } -.compare { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 12px; max-width: 1000px; margin: 0 auto; overflow-x: auto; } -.compare table { border-collapse: separate; border-spacing: 8px 0; } -.compare th, .compare td { border: 0; padding: 20px 20px; vertical-align: top; background: #343a40; border-radius: 0; font-size: 15px; color: #adb5bd; } -.compare th { font-weight: 500; font-size: 16px; } -.compare td:first-child { color: #fff; font-weight: 500; } -.compare .hl { background: #ffd000; color: #212529 !important; font-weight: 700; } -.compare th.hl { border-radius: 8px 8px 0 0; } -.compare tr:last-child td.hl { border-radius: 0 0 8px 8px; } -.quote { text-align: center; max-width: 960px; margin: 0 auto; } -.quote blockquote { font-size: 36px; line-height: 44px; font-style: italic; color: #dee2e6; margin: 0 0 32px; font-weight: 400; letter-spacing: -0.01em; } -.quote cite { font-style: normal; font-weight: 700; font-size: 20px; } -.stats { display: flex; gap: 96px; justify-content: center; flex-wrap: wrap; margin-top: 56px; } -.stats .v { font-size: 64px; line-height: 68px; color: #ffd000; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; } -.stats .l { color: #adb5bd; margin-top: 8px; font-size: 14px; } -.audiences { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; } -.acard { background: #212529; color: #fff; border-radius: 8px; padding: 28px; min-height: 420px; transition: transform 0.35s var(--ease), box-shadow 0.35s; } -.acard:hover { transform: translateY(-4px); box-shadow: 0 24px 60px rgba(33,37,41,0.3); } -.acard h3 { font-size: 22px; margin-bottom: 8px; } -.acard p { color: #adb5bd; margin-bottom: 20px; max-width: 320px; } -.acard a, .acard .link { color: #ffd000; font-weight: 700; } -.acard .art { margin-top: 24px; } -@media (max-width: 860px) { .audiences { grid-template-columns: 1fr; } } -.steps4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } -.steps4 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } -.steps4 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } -.steps4 .n { width: 32px; height: 32px; border-radius: 4px; background: #ffd000; color: #212529; font-family: "DM Mono", monospace; display: grid; place-items: center; font-weight: 800; margin-bottom: 20px; } -.steps4 h4 { font-size: 18px; margin-bottom: 8px; } -.steps4 p { color: #6c757d; } -@media (max-width: 900px) { .steps4 { grid-template-columns: 1fr 1fr; } } -.feat6 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } -.feat6 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } -.feat6 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } -.feat6 .ico { width: 44px; height: 44px; border-radius: 10px; background: #212529; color: #fff; display: grid; place-items: center; margin-bottom: 20px; } -.feat6 h4 { font-size: 18px; margin-bottom: 8px; } -.feat6 p { color: #6c757d; } -.dark .feat6 > div { background: #2b3035; border-color: #343a40; } -.dark .feat6 .ico { background: #ffd000; color: #212529; } -.dark .feat6 p { color: #adb5bd; } -@media (max-width: 900px) { .feat6 { grid-template-columns: 1fr; } } -.faq { max-width: 770px; margin: 0 auto; } -.faq details { border-bottom: 1px solid #e9ecef; } -.faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 20px 0; font-weight: 700; font-size: 17px; } -.faq summary::-webkit-details-marker { display: none; } -.faq summary .plus { width: 24px; height: 24px; border-radius: 4px; border: 1.5px solid #6c757d; display: grid; place-items: center; color: #6c757d; font-weight: 400; transition: transform 0.3s var(--ease), background 0.2s, color 0.2s; } -.faq details[open] summary .plus { transform: rotate(45deg); background: #ffd000; color: #212529; border-color: #ffd000; } -.faq .ans { padding: 0 0 20px; color: #6c757d; max-width: 680px; animation: rise 0.3s var(--ease); } -.cta { position: relative; overflow: hidden; background: #fff; background-image: radial-gradient(#d9dde2 1.2px, transparent 1.2px); background-size: 26px 26px; padding: 120px 0; text-align: center; } -.cta h2 { font-size: 56px; line-height: 60px; text-align: center; margin: 0 auto 12px; } -.cta h2 span { color: #6c757d; } -.cta .sub { color: #6c757d; font-size: 18px; margin: 20px 0 32px; } -.land-footer { background: #212529; color: #fff; padding: 72px 0 0; overflow: hidden; } -.land-footer .cols { display: grid; grid-template-columns: 2fr repeat(5, 1fr); gap: 24px; padding-bottom: 56px; border-bottom: 1px solid #343a40; } -.land-footer h5 { margin: 0 0 16px; font-size: 14px; color: #adb5bd; font-weight: 700; } -.land-footer ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; font-size: 15px; } -.land-footer ul a { transition: color 0.15s; } -.land-footer ul a:hover { color: #adb5bd; } -.land-footer .legal { display: flex; justify-content: space-between; padding: 32px 0; color: #6c757d; font-size: 14px; } -.land-footer .giant { font-size: 30vw; line-height: 0.8; font-weight: 800; letter-spacing: -0.05em; color: transparent; -webkit-text-stroke: 1.5px #ffd000; text-align: left; margin-top: 24px; user-select: none; } -@media (max-width: 900px) { .land-footer .cols { grid-template-columns: 1fr 1fr; } .land-nav nav { display: none; } } - -/* mini app mockup used on the marketing pages */ -.mock-app { background: #212529; color: #fff; font-size: 12px; display: grid; grid-template-columns: 180px 1fr; min-height: 420px; } -.mock-app .sb { background: #2b3035; padding: 12px; border-right: 1px solid #343a40; } -.mock-app .sb .pill { height: 26px; border-radius: 4px; background: #3d3400; padding: 0 10px; font-weight: 700; margin-bottom: 8px; } -.mock-app .sb .ntx { border: 1px solid #6c757d; border-radius: 6px; padding: 6px; color: #adb5bd; text-align: center; margin-bottom: 12px; } -.mock-app .sb .it { padding: 6px 8px; color: #fff; border-radius: 6px; } -.mock-app .sb .it.on { background: #3d3400; font-weight: 700; } -.mock-app .ct { padding: 14px; display: grid; gap: 12px; grid-template-columns: 1.7fr 1fr; align-items: start; } -.mock-app .acct { grid-column: 1 / -1; background: #2b3035; border-radius: 10px; padding: 8px 12px; display: flex; align-items: center; gap: 10px; } -.mock-app .pn { background: #2b3035; border-radius: 10px; padding: 14px; } -.mock-app .big { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } -.mock-app .big span { color: #6c757d; } -.mock-app .mb { display: inline-block; background: #343a40; border-radius: 6px; padding: 4px 10px; margin-right: 6px; margin-top: 8px; } -.mock-app .li { display: flex; justify-content: space-between; padding: 8px 0; border-top: 1px solid #343a40; } -.mock-app .ok { color: #75b798; font-weight: 700; } -.mock-app .rv { color: #ffcd39; font-weight: 700; } -.mock-app .ident { width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(#ffd000, #6c757d, #adb5bd, #ffd000); } - -@media (max-width: 860px) { - .shell { flex-direction: column; } - .sidebar { width: auto; height: auto; position: static; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px 12px; } - .newtx { margin: 0; flex: 1 1 100%; } - .nav { flex-direction: row; flex-wrap: wrap; } - .nav button.active::before { display: none; } - .nav-group, .sidebar-bottom { display: none; } - .main { padding: 16px; } -} - -/* ================================================================== identity: tape, section index, marker, live scorer, mode strip */ -.tape { height: 10px; background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } -.tape.thin { height: 6px; } -.tape.run { animation: tape 0.9s linear infinite; } -@keyframes tape { to { background-position: 45.25px 0; } } -.secno { display: flex; align-items: center; gap: 12px; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 18px; } -.secno::before { content: ""; width: 28px; height: 3px; background: #ffd000; flex: none; } -.dark .secno { color: #adb5bd; } -.mark-hl { background-image: linear-gradient(180deg, transparent 60%, #ffd000 60%, #ffd000 92%, transparent 92%); background-repeat: no-repeat; background-size: 0% 100%; -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: hlin 0.8s var(--ease) 0.7s forwards; } -@keyframes hlin { to { background-size: 100% 100%; } } -.hero-meta { margin-top: 32px; display: flex; gap: 24px; flex-wrap: wrap; justify-content: center; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: #6c757d; animation: rise 0.7s var(--ease) 0.4s both; } -.hero-meta span { display: inline-flex; align-items: center; gap: 8px; } -.hero-meta span::before { content: ""; width: 8px; height: 3px; background: #ffd000; } - -.ticker { background: #212529; color: #fff; border-radius: 8px; box-shadow: 0 30px 80px rgba(33,37,41,0.28); overflow: hidden; font-size: 14px; } -.ticker .head { display: flex; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #343a40; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #adb5bd; } -.ticker .head b { color: #ffd000; font-weight: 500; } -.ticker .body { padding: 20px 18px 16px; display: grid; gap: 14px; } -.ticker .row { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; } -.ticker .row > span:first-child { color: #adb5bd; font-size: 13px; } -.ticker .amt { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.02em; } -.ticker .to { font-family: "DM Mono", monospace; font-size: 12.5px; color: #dee2e6; } -.ticker .prog { height: 6px; background: #343a40; border-radius: 3px; overflow: hidden; } -.ticker .prog i { display: block; height: 100%; background: #ffd000; width: 0; } -.ticker .prog.on i { animation: growx 1.1s var(--ease) both; } -.ticker .prog.done i { width: 100%; } -@keyframes growx { from { width: 0; } to { width: 100%; } } -.ticker .verdict { display: flex; align-items: center; gap: 10px; min-height: 34px; flex-wrap: wrap; } -.ticker .tier { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; padding: 7px 10px; border-radius: 4px; font-weight: 500; color: #212529; animation: pop 0.3s var(--ease) both; } -.ticker .tier.low { background: #ffd000; } -.ticker .tier.high { background: #ffa94d; } -.ticker .tier.critical { background: #ea868f; } -.ticker .tier.blocked { background: #fff; } -.ticker .scoring { color: #adb5bd; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; } -.ticker .why { list-style: none; padding: 0; margin: 0; display: grid; gap: 7px; color: #dee2e6; font-size: 13px; min-height: 66px; } -.ticker .why li { animation: rise 0.4s var(--ease) both; padding-left: 18px; position: relative; } -.ticker .why li::before { content: ""; position: absolute; left: 0; top: 8px; width: 9px; height: 3px; background: #ffd000; } -.ticker .foot { padding: 12px 18px; border-top: 1px solid #343a40; font-size: 12px; color: #adb5bd; display: flex; justify-content: space-between; gap: 12px; } -.ticker .dots { display: flex; gap: 6px; } -.ticker .dots i { width: 18px; height: 3px; background: #495057; } -.ticker .dots i.on { background: #ffd000; } -.mode-strip { height: 6px; margin: -20px -24px 16px; background: transparent; transition: background 0.3s; } -.mode-strip.elevated { background: #ffd000; } -.mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } -@media (prefers-reduced-motion: reduce) { .tape.run, .mark-hl, .ticker .prog.on i, .ticker .why li, .ticker .tier { animation: none; } .mark-hl { background-size: 100% 100%; } .ticker .prog.on i { width: 100%; } } - -/* ================================================================== phone mockups (marketing) - Authored at true device scale (393 x 852 points) and scaled as a unit, so the app's own type sizes - and spacing survive. --pwn is unitless: calc() dividing two lengths yields a length, which scale() - would reject. */ -.phone { --pwn: 268; --scale: calc(var(--pwn) / 417); position: relative; width: calc(var(--pwn) * 1px); height: calc(876px * var(--scale)); flex: none; } -.phone-device { position: absolute; top: 0; left: 0; width: 417px; height: 876px; transform: scale(var(--scale)); transform-origin: top left; background: #0b0d10; border-radius: 58px; padding: 12px; box-shadow: 0 40px 90px rgba(16,20,24,0.3), 0 0 0 1px rgba(255,255,255,0.08) inset; } -.ph-island { position: absolute; top: 24px; left: 50%; transform: translateX(-50%); width: 122px; height: 35px; background: #0b0d10; border-radius: 20px; z-index: 3; } -.phone-screen { position: relative; width: 100%; height: 100%; border-radius: 46px; background: #fff; overflow: hidden; display: flex; flex-direction: column; color: #101418; font-size: 15px; } -.ph-home-ind { position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%); width: 140px; height: 5px; border-radius: 3px; background: #101418; opacity: 0.85; } -.ph-status { height: 56px; padding: 16px 30px 0; display: flex; align-items: center; justify-content: space-between; font-size: 16px; } -.ph-status b { font-family: "DM Sans", sans-serif; font-weight: 700; letter-spacing: -0.2px; } -.ph-status-icons { display: flex; align-items: center; gap: 6px; fill: #101418; color: #101418; } -.ph-body { flex: 1; padding: 6px 16px 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; } - -.ph-top { display: flex; align-items: center; gap: 10px; height: 44px; } -.ph-top > b { font-size: 17px; font-weight: 700; } -.ph-ident { position: relative; width: 36px; height: 36px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #7dd3fc, #2ec27e); flex: none; } -.ph-ident i { position: absolute; top: -6px; left: 16px; background: #ffd000; color: #101418; font-style: normal; font-size: 10px; font-weight: 800; border-radius: 8px; padding: 1px 5px; border: 2px solid #fff; } -.ph-caret { color: #98a2b3; font-size: 13px; } -.ph-caret.r { margin-left: auto; } -.ph-top-btns { margin-left: auto; display: flex; gap: 8px; } -.ph-top-btns i { width: 40px; height: 40px; border-radius: 50%; background: #f6f7f9; display: block; position: relative; } -.ph-top-btns i::before { content: ""; position: absolute; inset: 13px; border: 2px solid #101418; border-radius: 3px; -webkit-mask: linear-gradient(#000 0 0) top/100% 4px no-repeat, linear-gradient(#000 0 0) bottom/100% 4px no-repeat, linear-gradient(#000 0 0) left/4px 100% no-repeat, linear-gradient(#000 0 0) right/4px 100% no-repeat; } -.ph-top-btns i.bell::before { inset: 11px 13px 12px; border: 0; background: #101418; -webkit-mask: none; border-radius: 7px 7px 2px 2px; } -.ph-top-btns i.bell::after { content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px; border-radius: 50%; background: #ffd000; } -.ph-pending { display: flex; align-items: center; gap: 10px; background: #fff6cc; color: #8a6d00; border-radius: 14px; padding: 0 14px; height: 48px; font-weight: 700; font-size: 15px; } -.ph-pending .n { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 12px; } -.ph-chain { display: flex; align-items: center; gap: 8px; font-size: 14px; } -.ph-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-size: 13px; } -.ph-ark { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 11px; font-weight: 800; } -.ph-balance { font-family: "Space Grotesk", sans-serif; font-size: 44px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } -.ph-balance small { font-size: 20px; color: #667085; margin-left: 8px; letter-spacing: -0.02em; } -.ph-actions { display: flex; gap: 10px; } -.ph-actions span { flex: 1; height: 48px; display: grid; place-items: center; border-radius: 14px; background: #f6f7f9; font-weight: 700; font-size: 15px; } -.ph-actions .go { background: #ffd000; } -.ph-label { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 4px; } -.ph-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #eceef2; } -.ph-row.last, .ph-card .ph-row:last-child { border-bottom: 0; } -.ph-card { background: #f6f7f9; border-radius: 16px; padding: 0 14px; } -.ph-card.pad { padding: 4px 14px; } -.ph-mark, .ph-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } -.ph-circle { width: 40px; height: 40px; background: #eceef2; font-size: 16px; } -.ph-circle.sm { width: 34px; height: 34px; font-size: 15px; } -.ph-name { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } -.ph-name b { font-size: 15px; font-weight: 700; } -.ph-name small { font-size: 13px; color: #667085; } -.ph-amt { font-size: 15px; font-weight: 700; } -.ph-badge { background: #eceef2; color: #667085; border-radius: 99px; padding: 4px 9px; font-weight: 700; font-size: 12px; } -.ph-badge.warn { background: #fff3d6; color: #a86a00; } -.ph-title { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 700; display: flex; align-items: center; gap: 10px; height: 44px; } -.ph-title.back { font-size: 18px; } -.ph-title .ph-plus { margin-left: auto; width: 40px; height: 40px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 20px; } -.ph-tabsline { display: flex; gap: 22px; border-bottom: 1px solid #eceef2; font-size: 15px; } -.ph-tabsline b { border-bottom: 2px solid #ffd000; padding-bottom: 9px; } -.ph-tabsline span { color: #98a2b3; padding-bottom: 9px; } -.ph-chips { display: flex; gap: 8px; } -.ph-chips b, .ph-chips span { border-radius: 99px; padding: 6px 12px; font-size: 12px; font-weight: 700; background: #f6f7f9; color: #667085; } -.ph-chips b { background: #ffd000; color: #101418; } -.ph-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0 4px; } -.ph-hero-mark { position: relative; } -.ph-hero-mark i { position: absolute; right: -4px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #b42318; color: #fff; font-style: normal; font-size: 12px; display: grid; place-items: center; border: 3px solid #fff; } -.ph-hero b { font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -0.03em; } -.ph-hero small { color: #667085; font-size: 14px; } -.ph-kv { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eceef2; font-size: 14px; } -.ph-kv.last { border-bottom: 0; } -.ph-kv span { color: #667085; } -.ph-sign { margin-top: auto; margin-bottom: 12px; background: #ffd000; border-radius: 16px; height: 56px; padding: 0 18px; display: flex; align-items: center; gap: 10px; font-size: 16px; } -.ph-sign b { font-weight: 700; } -.ph-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 5px 10px; font-family: "DM Mono", monospace; font-size: 12px; } -.ph-tabs { height: 84px; border-top: 1px solid #eceef2; display: flex; align-items: flex-start; padding-top: 14px; } -.ph-tabs span { flex: 1; text-align: center; font-size: 24px; color: #98a2b3; position: relative; } -.ph-tabs span.on { color: #ffd000; } -.ph-tab-badge { position: absolute; top: -4px; left: 55%; background: #ffd000; color: #101418; font-style: normal; font-size: 11px; font-weight: 800; border-radius: 99px; padding: 1px 6px; } -.phones { display: flex; gap: 30px; justify-content: center; align-items: flex-start; flex-wrap: wrap; } -.phones .phone:nth-child(2) { margin-top: -26px; } -@media (max-width: 900px) { .phones .phone:nth-child(2) { margin-top: 0; } .phone { --pwn: 240; } } - -/* The landing's mobile strip: copy on the left, two phones on the right, the card sized by both. */ -.mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } -.mstrip h2 { text-align: left; margin-bottom: 16px; } -.mstrip p { color: #6c757d; max-width: 380px; margin-bottom: 26px; } -.mstrip ul { list-style: none; padding: 0; margin: 0 0 26px; display: flex; flex-direction: column; gap: 14px; font-size: 17px; font-weight: 700; color: #212529; } -.mstrip ul li { display: flex; gap: 12px; align-items: center; } -.mstrip ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 24px; height: 24px; flex: none; } -.phones.two { display: flex; gap: 16px; align-items: flex-start; } -.phones.two .phone { --pwn: 196; } -.phones.two .phone:nth-child(2) { margin-top: 30px; } -@media (max-width: 980px) { .mstrip { grid-template-columns: 1fr; } .phones.two { justify-content: center; } .phones.two .phone:nth-child(2) { display: none; } } - -/* ================================================================== documentation */ -.docs { max-width: 1216px; margin: 0 auto; padding: 0 24px; display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; align-items: start; } -.docs-nav { position: sticky; top: 96px; padding: 40px 0 60px; display: flex; flex-direction: column; gap: 22px; } -.docs-group { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 8px; } -.docs-nav button { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 7px 12px; margin-left: -12px; border-radius: 8px; font: inherit; font-size: 15px; color: #6c757d; cursor: pointer; } -.docs-nav button:hover { background: #f1f3f5; color: #212529; } -.docs-nav button.on { background: #fff6cc; color: #212529; font-weight: 700; } -.docs-body { padding: 40px 0 96px; min-width: 0; } -.docs-crumb { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 12px; } -.docs-body h1 { font-family: "Space Grotesk", sans-serif; font-size: 44px; line-height: 48px; letter-spacing: -0.03em; margin-bottom: 20px; } -.docs-body h3 { font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -0.02em; margin: 40px 0 10px; scroll-margin-top: 96px; } -.docs-body p { font-size: 17px; line-height: 27px; color: #495057; margin-bottom: 16px; max-width: 70ch; } -.docs-body .doc-lead { font-size: 20px; line-height: 30px; color: #212529; margin-bottom: 24px; } -.docs-body ul, .docs-body ol { margin: 0 0 20px 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 26px; color: #495057; max-width: 70ch; } -.docs-body li b { color: #212529; } -.docs-body ol.doc-inv { counter-reset: inv; list-style: none; margin-left: 0; } -.docs-body ol.doc-inv li { counter-increment: inv; padding-left: 40px; position: relative; color: #212529; font-weight: 500; } -.docs-body ol.doc-inv li::before { content: counter(inv); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; border-radius: 6px; background: #ffd000; color: #212529; display: grid; place-items: center; font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; } -.doc-note { border-left: 3px solid #ffd000; background: #fffdf2; padding: 14px 18px; border-radius: 0 8px 8px 0; font-size: 16px; line-height: 25px; color: #495057; margin: 22px 0; max-width: 70ch; } -.doc-table { overflow-x: auto; margin: 0 0 24px; } -.doc-table table { border-collapse: collapse; width: 100%; font-size: 15px; } -.doc-table th { text-align: left; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #98a2b3; font-weight: 400; padding: 0 16px 10px 0; border-bottom: 1px solid #e9ecef; } -.doc-table td { padding: 12px 16px 12px 0; border-bottom: 1px solid #f1f3f5; color: #495057; vertical-align: top; line-height: 23px; } -.doc-table td:first-child { color: #212529; font-weight: 700; white-space: nowrap; } -.doc-table code { font-family: "DM Mono", monospace; font-size: 13px; background: #f1f3f5; padding: 2px 6px; border-radius: 4px; color: #212529; } -.docs-paging { display: flex; justify-content: space-between; gap: 16px; margin-top: 56px; padding-top: 24px; border-top: 1px solid #e9ecef; } -.docs-paging button { background: none; border: 0; font: inherit; font-weight: 700; color: #212529; cursor: pointer; padding: 8px 0; } -.docs-paging button:hover { color: #6c757d; } -@media (max-width: 900px) { - .docs { grid-template-columns: 1fr; gap: 0; } - .docs-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 24px 0 0; } - .docs-nav > div { display: contents; } - .docs-group { display: none; } - .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } - .docs-body h1 { font-size: 34px; line-height: 38px; } -} diff --git a/web/src/wagmi.ts b/web/src/wagmi.ts deleted file mode 100644 index 50bb26b..0000000 --- a/web/src/wagmi.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createConfig, http } from "wagmi"; -import { injected } from "wagmi/connectors"; -import { arkDevnet } from "./config/chain"; - -export const wagmiConfig = createConfig({ - chains: [arkDevnet], - connectors: [injected()], - transports: { - // The devnet RPC has no Multicall3 and works through JSON-RPC batches almost serially (about 0.4s - // per entry), while concurrent single requests come back three times faster. So: no batching. - [arkDevnet.id]: http(undefined, { retryCount: 2 }), - }, -}); - -declare module "wagmi" { - interface Register { - config: typeof wagmiConfig; - } -} diff --git a/web/tsconfig.app.json b/web/tsconfig.app.json deleted file mode 100644 index 4971bc8..0000000 --- a/web/tsconfig.app.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "es2023", - "lib": ["ES2023", "DOM"], - "module": "esnext", - "types": ["vite/client"], - "allowArbitraryExtensions": true, - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/web/tsconfig.json b/web/tsconfig.json deleted file mode 100644 index 1ffef60..0000000 --- a/web/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/web/tsconfig.node.json b/web/tsconfig.node.json deleted file mode 100644 index 8455dcb..0000000 --- a/web/tsconfig.node.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "es2023", - "lib": ["ES2023"], - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "module": "nodenext", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["vite.config.ts"] -} diff --git a/web/vite.config.ts b/web/vite.config.ts deleted file mode 100644 index 9982072..0000000 --- a/web/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import react from '@vitejs/plugin-react' -import { defineConfig } from 'vite' - -// https://vite.dev/config/ -export default defineConfig({ - plugins: [react()], -}) From b70af5fa33c490b1dfbd8ecfc83918488a62f525 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 22:45:17 +0100 Subject: [PATCH 30/44] fix: untrack the Expo build output I committed by accident MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing mobile/ took its .gitignore with it, so the ios/, android/ and .expo artifacts it had been ignoring became visible — and my git add -A committed 114 of them, 1.2MB of generated files, in the commit that was supposed to delete the directory. Untracked, and the root .gitignore now refuses those three paths outright. The directories still exist locally with build output, node_modules and a .env in them; they are yours to delete and nothing in the repository refers to them. --- .gitignore | 7 + mobile/.expo/README.md | 14 - mobile/.expo/devices.json | 3 - mobile/.expo/prebuild/cached-packages.json | 4 - .../icon_108.png | Bin 304 -> 0 bytes .../icon_162.png | Bin 472 -> 0 bytes .../icon_216.png | Bin 627 -> 0 bytes .../icon_324.png | Bin 897 -> 0 bytes .../icon_432.png | Bin 1545 -> 0 bytes .../icon_108.png | Bin 1735 -> 0 bytes .../icon_162.png | Bin 2599 -> 0 bytes .../icon_216.png | Bin 3620 -> 0 bytes .../icon_324.png | Bin 5655 -> 0 bytes .../icon_432.png | Bin 8123 -> 0 bytes .../icon_108.png | Bin 1735 -> 0 bytes .../icon_162.png | Bin 2599 -> 0 bytes .../icon_216.png | Bin 3620 -> 0 bytes .../icon_324.png | Bin 5655 -> 0 bytes .../icon_432.png | Bin 8123 -> 0 bytes .../icon_24.png | Bin 370 -> 0 bytes .../icon_36.png | Bin 572 -> 0 bytes .../icon_48.png | Bin 827 -> 0 bytes .../icon_72.png | Bin 1162 -> 0 bytes .../icon_96.png | Bin 1555 -> 0 bytes .../icon_144.png | Bin 4681 -> 0 bytes .../icon_192.png | Bin 6553 -> 0 bytes .../icon_48.png | Bin 1554 -> 0 bytes .../icon_72.png | Bin 2283 -> 0 bytes .../icon_96.png | Bin 3108 -> 0 bytes .../icon_144.png | Bin 3787 -> 0 bytes .../icon_192.png | Bin 5345 -> 0 bytes .../icon_48.png | Bin 1293 -> 0 bytes .../icon_72.png | Bin 1900 -> 0 bytes .../icon_96.png | Bin 2542 -> 0 bytes .../App-Icon-1024x1024@1x.png | Bin 402523 -> 0 bytes .../App-Icon-1024x1024@1x.png | Bin 28686 -> 0 bytes mobile/android/.gitignore | 19 - mobile/android/app/build.gradle | 182 -- mobile/android/app/debug.keystore | Bin 2257 -> 0 bytes mobile/android/app/proguard-rules.pro | 14 - .../android/app/src/debug/AndroidManifest.xml | 7 - .../src/debugOptimized/AndroidManifest.xml | 7 - .../android/app/src/main/AndroidManifest.xml | 40 - .../main/java/io/skur/vault/MainActivity.kt | 61 - .../java/io/skur/vault/MainApplication.kt | 45 - .../res/drawable-hdpi/notification_icon.png | Bin 572 -> 0 bytes .../res/drawable-hdpi/splashscreen_logo.png | Bin 20754 -> 0 bytes .../res/drawable-mdpi/notification_icon.png | Bin 370 -> 0 bytes .../res/drawable-mdpi/splashscreen_logo.png | Bin 12863 -> 0 bytes .../res/drawable-xhdpi/notification_icon.png | Bin 827 -> 0 bytes .../res/drawable-xhdpi/splashscreen_logo.png | Bin 29081 -> 0 bytes .../res/drawable-xxhdpi/notification_icon.png | Bin 1162 -> 0 bytes .../res/drawable-xxhdpi/splashscreen_logo.png | Bin 47123 -> 0 bytes .../drawable-xxxhdpi/notification_icon.png | Bin 1555 -> 0 bytes .../drawable-xxxhdpi/splashscreen_logo.png | Bin 66529 -> 0 bytes .../res/drawable/ic_launcher_background.xml | 6 - .../res/drawable/rn_edit_text_material.xml | 37 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 6 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 6 - .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin 1900 -> 0 bytes .../mipmap-hdpi/ic_launcher_background.webp | Bin 472 -> 0 bytes .../mipmap-hdpi/ic_launcher_foreground.webp | Bin 2599 -> 0 bytes .../mipmap-hdpi/ic_launcher_monochrome.webp | Bin 2599 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 2283 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin 1293 -> 0 bytes .../mipmap-mdpi/ic_launcher_background.webp | Bin 304 -> 0 bytes .../mipmap-mdpi/ic_launcher_foreground.webp | Bin 1735 -> 0 bytes .../mipmap-mdpi/ic_launcher_monochrome.webp | Bin 1735 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 1554 -> 0 bytes .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin 2542 -> 0 bytes .../mipmap-xhdpi/ic_launcher_background.webp | Bin 627 -> 0 bytes .../mipmap-xhdpi/ic_launcher_foreground.webp | Bin 3620 -> 0 bytes .../mipmap-xhdpi/ic_launcher_monochrome.webp | Bin 3620 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 3108 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin 3787 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_background.webp | Bin 897 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_foreground.webp | Bin 5655 -> 0 bytes .../mipmap-xxhdpi/ic_launcher_monochrome.webp | Bin 5655 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 4681 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 5345 -> 0 bytes .../ic_launcher_background.webp | Bin 1545 -> 0 bytes .../ic_launcher_foreground.webp | Bin 8123 -> 0 bytes .../ic_launcher_monochrome.webp | Bin 8123 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 6553 -> 0 bytes .../app/src/main/res/values/colors.xml | 7 - .../app/src/main/res/values/strings.xml | 3 - .../app/src/main/res/values/styles.xml | 12 - mobile/android/build.gradle | 24 - mobile/android/gradle.properties | 68 - mobile/android/gradle.properties.bak2 | 68 - mobile/android/gradle.properties.bak3 | 68 - .../android/gradle/wrapper/gradle-wrapper.jar | Bin 46175 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - .../wrapper/gradle-wrapper.properties.bak | 7 - mobile/android/gradlew | 248 -- mobile/android/gradlew.bat | 98 - mobile/android/settings.gradle | 39 - mobile/ios/.gitignore | 30 - mobile/ios/.xcode.env | 11 - mobile/ios/Podfile | 67 - mobile/ios/Podfile.lock | 2472 ----------------- mobile/ios/Podfile.properties.json | 7 - mobile/ios/Skur.xcodeproj/project.pbxproj | 570 ---- .../xcshareddata/xcschemes/Skur.xcscheme | 88 - .../Skur.xcworkspace/contents.xcworkspacedata | 10 - mobile/ios/Skur/AppDelegate.swift | 69 - .../App-Icon-1024x1024@1x.png | Bin 28686 -> 0 bytes .../AppIcon.appiconset/Contents.json | 14 - mobile/ios/Skur/Images.xcassets/Contents.json | 6 - mobile/ios/Skur/Info.plist | 78 - mobile/ios/Skur/PrivacyInfo.xcprivacy | 48 - mobile/ios/Skur/Skur-Bridging-Header.h | 3 - mobile/ios/Skur/Skur.entitlements | 8 - mobile/ios/Skur/SplashScreen.storyboard | 47 - mobile/ios/Skur/Supporting/Expo.plist | 14 - 115 files changed, 7 insertions(+), 4642 deletions(-) delete mode 100644 mobile/.expo/README.md delete mode 100644 mobile/.expo/devices.json delete mode 100644 mobile/.expo/prebuild/cached-packages.json delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_108.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_162.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_216.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_324.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_432.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_108.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_162.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_216.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_432.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_108.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_162.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_216.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png delete mode 100644 mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_432.png delete mode 100644 mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_24.png delete mode 100644 mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_36.png delete mode 100644 mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_48.png delete mode 100644 mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_72.png delete mode 100644 mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_96.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_144.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_48.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_72.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_96.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_144.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_48.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_72.png delete mode 100644 mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_96.png delete mode 100644 mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-119462bb78eb240a65c869fc067ee599639b3cb5a41953f25c07b17d2a8c7e0f-cover-#ffffff/App-Icon-1024x1024@1x.png delete mode 100644 mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-#ffffff/App-Icon-1024x1024@1x.png delete mode 100644 mobile/android/.gitignore delete mode 100644 mobile/android/app/build.gradle delete mode 100644 mobile/android/app/debug.keystore delete mode 100644 mobile/android/app/proguard-rules.pro delete mode 100644 mobile/android/app/src/debug/AndroidManifest.xml delete mode 100644 mobile/android/app/src/debugOptimized/AndroidManifest.xml delete mode 100644 mobile/android/app/src/main/AndroidManifest.xml delete mode 100644 mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt delete mode 100644 mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt delete mode 100644 mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png delete mode 100644 mobile/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png delete mode 100644 mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png delete mode 100644 mobile/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png delete mode 100644 mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png delete mode 100644 mobile/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png delete mode 100644 mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png delete mode 100644 mobile/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png delete mode 100644 mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png delete mode 100644 mobile/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png delete mode 100644 mobile/android/app/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml delete mode 100644 mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp delete mode 100644 mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp delete mode 100644 mobile/android/app/src/main/res/values/colors.xml delete mode 100644 mobile/android/app/src/main/res/values/strings.xml delete mode 100644 mobile/android/app/src/main/res/values/styles.xml delete mode 100644 mobile/android/build.gradle delete mode 100644 mobile/android/gradle.properties delete mode 100644 mobile/android/gradle.properties.bak2 delete mode 100644 mobile/android/gradle.properties.bak3 delete mode 100644 mobile/android/gradle/wrapper/gradle-wrapper.jar delete mode 100644 mobile/android/gradle/wrapper/gradle-wrapper.properties delete mode 100644 mobile/android/gradle/wrapper/gradle-wrapper.properties.bak delete mode 100755 mobile/android/gradlew delete mode 100644 mobile/android/gradlew.bat delete mode 100644 mobile/android/settings.gradle delete mode 100644 mobile/ios/.gitignore delete mode 100644 mobile/ios/.xcode.env delete mode 100644 mobile/ios/Podfile delete mode 100644 mobile/ios/Podfile.lock delete mode 100644 mobile/ios/Podfile.properties.json delete mode 100644 mobile/ios/Skur.xcodeproj/project.pbxproj delete mode 100644 mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme delete mode 100644 mobile/ios/Skur.xcworkspace/contents.xcworkspacedata delete mode 100644 mobile/ios/Skur/AppDelegate.swift delete mode 100644 mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png delete mode 100644 mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 mobile/ios/Skur/Images.xcassets/Contents.json delete mode 100644 mobile/ios/Skur/Info.plist delete mode 100644 mobile/ios/Skur/PrivacyInfo.xcprivacy delete mode 100644 mobile/ios/Skur/Skur-Bridging-Header.h delete mode 100644 mobile/ios/Skur/Skur.entitlements delete mode 100644 mobile/ios/Skur/SplashScreen.storyboard delete mode 100644 mobile/ios/Skur/Supporting/Expo.plist diff --git a/.gitignore b/.gitignore index 10142f2..80ad9c7 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,10 @@ sui/Move.lock .DS_Store *.log crytic-export/ + +# The EVM build was removed. These directories may still exist locally, holding build output, +# node_modules and a .env — their own .gitignore files went with them, so without this a +# `git add -A` happily commits an Expo prebuild. Never track these paths again. +/contracts/ +/web/ +/mobile/ diff --git a/mobile/.expo/README.md b/mobile/.expo/README.md deleted file mode 100644 index 563b815..0000000 --- a/mobile/.expo/README.md +++ /dev/null @@ -1,14 +0,0 @@ -> Why do I have a folder named ".expo" in my project? - -The ".expo" folder is created when an Expo project is started using "expo start" command. - -> What do the files contain? - -- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds. -- "settings.json": contains the server configuration that is used to serve the application manifest. -- "dev/logs/": contains structured JSONL event logs from CLI commands (e.g. start.log, export.log). These are truncated on each run. - -> Should I commit the ".expo" folder? - -No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine. -Upon project creation, the ".expo" folder is already added to your ".gitignore" file. diff --git a/mobile/.expo/devices.json b/mobile/.expo/devices.json deleted file mode 100644 index 5efff6c..0000000 --- a/mobile/.expo/devices.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "devices": [] -} diff --git a/mobile/.expo/prebuild/cached-packages.json b/mobile/.expo/prebuild/cached-packages.json deleted file mode 100644 index 6afa893..0000000 --- a/mobile/.expo/prebuild/cached-packages.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "dependencies": "1fca5b73c40f37b750a7958544848f258fa60722", - "devDependencies": "bb8fe344f947319e69cdf214593cc09e6a829d57" -} diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_108.png b/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_108.png deleted file mode 100644 index edaae30ba394cb0e8d3cac2667d4ac481d88ef36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz1|<8_!p{P!@18D>Ar*{o4?6N5Fkm>c;meFS t7mxp7zEj}RRXgu@olCMy>M(>)*%{=S+$y@?$N+K3Qu2Ui?QSGqaS$g#!(2Y$gT^8X0+cG7=m{h3FO%eAgB*ZR+jMc?yg% N22WQ%mvv4FO#rmpet!S} diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_216.png b/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_216.png deleted file mode 100644 index 7c066413843d9ab68081308efc94dc2744d77bf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 627 zcmeAS@N?(olHy`uVBq!ia0vp^H$a$!4M=t>=)PrOV6yUbaSW+oe0$K4vB7|WdBZwC zi?Rpt3M*bre`53fFO!eS0Uzcwqr_+!pr?Z~{N)+Ua=g!~PXQAXgQu&X%Q~loCIC}3 B_(=c& diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_324.png b/mobile/.expo/web/cache/production/images/android-adaptive-background/android-adaptive-background-fd93206efb353711bfd6eafc116472a443faec1c20948bed7a05d4ef801eb109-cover-transparent/icon_324.png deleted file mode 100644 index 1dadd8d78b2f86c71f5bc4734ee71a239b45d696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 897 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 diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png b/mobile/.expo/web/cache/production/images/android-adaptive-foreground/android-adaptive-foreground-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png deleted file mode 100644 index 5aaf71b4cba8fa5811e84ab323f78b24a9f48c2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5655 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 diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_108.png b/mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_108.png deleted file mode 100644 index 213d6612b5432faba7d320b528629ba42616eba0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1735 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 diff --git a/mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png b/mobile/.expo/web/cache/production/images/android-adaptive-monochrome/android-adaptive-monochrome-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_324.png deleted file mode 100644 index 5aaf71b4cba8fa5811e84ab323f78b24a9f48c2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5655 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 diff --git a/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_24.png b/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_24.png deleted file mode 100644 index 761e9dfbc8e2c7eb5b50a52091f0f6e52e242900..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370 zcmV-&0ge8NP)Jj+?}~> zuQe!~%u#(E$A-efgrhmSjx!bV2?l%w5O6d$6c(bBJudcNxVnwe^WivOXLj1dhQd-d z)h3&2Gc1Xj%kW$bBqoX?P{LjbNf86V0Q!kAnjDY>1ZEm=5fsHTEk^#QAIscWq4h#m Q+5i9m07*qoM6N<$g0cIOlmGw# diff --git a/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_36.png b/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_36.png deleted file mode 100644 index 831332d475a1dc4884bf11820ce65e7743108ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 572 zcmV-C0>k}@P)_H>&L!g0K z1Y;t>1U?9S&{I4FE>R7^Baz@T1`Y;#njTLmwynMn^b!(T{DJW|w(M+yUpiJ*g8 z5p-anFwsZ^o60TLG4v$LhcAsdj^;>Lfoo@$h%{H<yBpu%tCyyc=gF?{M;1o?=Px z;%y6G7hERp%wbDmX*sW${ZY@A?iH?|U1CG1UXythW_8UW+*HAa!cyzD3X!G?lW&@d zh07d1Sm6ALRgNcrvL)nUOJPYlnvt71(xWlbqcJw@ik7%>ZV9(eV@qLaC9ha3NHYC7 ziY3YWPmMf&8K&<+I|t&w*xUXa8xl*Ozq_OcN%JxW!?xT6Go?gcDV0OX9mcr7Z z&UM;a$_$N1SzJ}P^_pj|TL`%xiT&%?l2~eN@EE@}&%T{S?mus1a4bfHtI71|h_;ro zrKmz@yvWnr^He;6)}S0swG<`-4+BSPd=YpUNK7N&G020m4*|g~K6yka(o75(c(V zeVuBEFdj*~QY3%~)fd4ffk!4@2@E`XGHr1FkEPttg)t0hZ7Q;PZ2>E+@I+wXk%?x% z569^Gayd_@4gPI;Lzz<_|3!1sMkk3zt_!^<8hJWx@MimSK7W6bPxn2fwW-L&qYxh+ zPokTNM!BgFxv3CRKws|!QOjk{=CuXhIIxQA_aZ!cV$u+=po>JKB~ce4z*X?;ML}1Jmc*R1zd$zCK}Z(b=cbRj2|!5(sMM)%EkuPy*k6j^mD%Go+N6y=w_nXk)9ka zsS;;?u46P8W;7S3e=tsct;6B{lWf^gKqnK8DvrQ$1qa^yo1X1c+!~AU=gk;rf2-xn zNR)%ek_;Rfr8#M%i$tSu2ji^SwVJ)3r4RyIn~Ln&`k3zyKOo&aOT`gfys-qGBpRg> zHgj%_MtEE>nCG~HnUZ8qEaIY*iAEi-&Crr6F*0uPPVY+IT3;X>Qe3zm(l6DqLFDRPJT4b2VXUE=~j$y&ebt*#WI^?2Xn-09CR|#tnsBX{hy36GH!8u%))U6 zO)uNDHP0d?+L=^IOR7XmszkL(yiz#)R}>B&NxTx|fg;sc#2}AH5|2bXHgJyW8xU!1 zJd*ffkO4|mkBuaY4+cJD`^aayxC3kh4D_;*>=tPT@xj2S?AHuuy7(SJ0(b>5S)3w* z9}w&mZTx~yf<;i*2;q_dOcthsBrnpG2?PRxKp^lx^bgtQ=z_RRdHetX002ovPDHLk FV1kGEa+3f6 diff --git a/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_72.png b/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_72.png deleted file mode 100644 index 9968354e371eae97478c178604989903df882762..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1162 zcmV;51aC))Yy??3g@o!`*djl;D6&3ePN}|VX+fEp zK}3}1TWW|R4re7TZAzq~ncJGvnVa|ScDK8G?{ne`H&CiC&)v=go!<|`Fbu;m48t%C z!!Qive?>3^)JgnUJV=5X6t^SrGZYkq2rgpNM3O^d3WH>rAcNFN1QySd;B}yk;njsr zBS|)iDJU{TkRj?ESw#5^#UgYP>>!7y#RU4v0E-Mz9SFi~Ls5r*mBgu9wSujU8*ojM z3BA;#cpR@#EF?@l86a^ z2tL?3g0$+%fAaEE-Hb0EB%TnooXKL%C!^@-_Tf12)~BWHTl*V2NHn-`$o-lxIDblX=_|U;d zgE6IXqy)zS$AQ;A8b#wXSIEyvl4eQ8^L5uqI^0lFm_P>`4T|!T)ZW|2{$qKh>~1dL zU`rmetD;Q5E6U8uex}~hPs5U{=w_qIoAq6E_u8B|n?*`=Kyv7KE{Bfil2V+Xq;77A zrH@^sv?zft5={zolYH6O#@c0?fr!Dp|I!oc(WKU`%P8;bx=3o^SIxc`l2T8I@5Up4CTb zQGx~4VHQ+}Q9#p)T$ZmdC(A6+MJ&>?gAO`KGQ!h((&? z!1ksBzB!gh+RVx*I@oA1u_DIen(KUZxR8`>hYQ)&T)?>72JzX7j&2{Jh(+3j(J>yG z9YzNmP1Y>E%s@=C_q%*j;t9do_5imUS3bz*S32w67VVBeW8=ZH6cDfSV+t1 zY_3NvQi1`8Nfj|3tq!wfelJ14LKhp&=1q$*Z(0PUAR3b-l7hUfBvRrDHXb1aOYiF+};D~3xF_uBEUc3hIU*Nk^H8MR|s~a*hB_cWI*FPu7f?5AE*F=42=Px4LC|M2gFzgF$}{n48t%C!!QiP cFbo&|0!3k7)F^01u>b%707*qoM6N<$f}>Iz#sB~S diff --git a/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_96.png b/mobile/.expo/web/cache/production/images/android-notification/android-notification-134d6ed005460309aab306747d62c92c47a96cf50b9520d1af436c1a73a33151-cover-transparent/icon_96.png deleted file mode 100644 index b0f2a7f8d12dad3b4b1601448dfc1ca8bdb17b2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1555 zcmV+u2JHEXP)G8vJ7ciXEL#^4I-cTtp*@Mrx2+QXB;;@t;aE zyrRxgi$)Tik{kqX!N2NBaS)9pny5aSP;AHV6x&rFO=u#~MX?Kz_@6|v3r!^YY^8W? zMH7hzs+T&Tk>b&)dZ|MLi5^PoOv9oy z`GkN?8=`bRdYODfBS9`r1~8e#U{g_td;wR{SeN2@Hf@+eNy_-_ZE2$RhUa&B9e z#AGf8tE$Mdxow6&y|;jzi{k+v>}+J^l3Ci<##nc2g3qmrbMwLs*KEBbf}gk;Zr{$! z^!>Apv55frhDL)7jRwhC(J;&Awi&*5*EGu;Quu|$aCOxge*e7-w6BeEBj?A096DOV z=4V&1`^SqJn+V_sEn8U6Ei+SyZVQQ;0n99Xqk(fi) z;}c~;kJ1uFNkDOXbBx=YV_cI=N#5!$r|Z=k&YmwNXFBTe(x0pO=7STM%Ee&!?`z~A zqd{`^J#v|yTR!GLm6mvXrEP{UuaENZcb9VNT!@_a`pba{OeHZ`NkEY=o|N23z*TI! zGeW+}X%~}847PYtntZ1Q%J^TVqYn8(K@XEj47PDijC}9(Rq*=BO0MVXj6?Tds>ru` zSrU`E7_8&Y2rnF|WhO4UMk(0y{9+!s=PDiT5kAu}OTbl3Ou3vo7vj*-Pcb$TAYVs& z1e3WKtg150zDGXdxvqM0JP*3xsHXdkYOWCilwwYIuZwb5YZQ}74EOafP4nDC<4D1r zlwwZnZcT9T=`ccIG#4Lu{N5|Hu1xU#U)OQ=d?`1wAe80NuYSz#`>qgh6{d6Xi7%{) zbL90_t|+9910+*IN5>045)Ulr$zYh#2;J^aGOM+DHkB1!X#B*j8v z%`1sDuOxaXijP7Ai5@YEPYewtdW-^!;-Qd?pn*gK(aL4uLyE_TqJ?oZkmz%qVj(z= zCK6o)hXD`&^AH?H6Nx5bE&T|N;CF%}qJ@4mk?2&)ULcHL2`(Yni$)F_?SGM2=Tp3c z$95oyzsyj=7SY5Y8aZgTzl(6^9!{Xx0#xD;VI*5b6DQHkp#b(DVyyEqeud;_pb3ze zDU0A`%D7LgVTb|{6qq{0Z76o3*aj>E1oKM)7ZCgr#bMFP`xKC19;q|b;IRZ)00;_8 z0TCplqJ>E;%d#xXvMkH8EX%Si%d#xXvMkH8EXyh`{{lin(SP!0(O>`o002ovPDHLk FV1ju{-e>>- diff --git a/mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_144.png b/mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_144.png deleted file mode 100644 index 643caaa5a8ac2ca4c69d5e1b20e145b1869d6600..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4681 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 LNkvXXu0mjfd~+vT diff --git a/mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png b/mobile/.expo/web/cache/production/images/android-standard-circle/android-standard-circle-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png deleted file mode 100644 index 84a79e444b25f788166c3631db06aaaa5a9f174f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6553 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 diff --git a/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png b/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_192.png deleted file mode 100644 index 60c519d816a2d3b5ef4155cb405f9f255fab99d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5345 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 LYlf*pJ4gQ);``&l diff --git a/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_48.png b/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_48.png deleted file mode 100644 index aac7a97d1fef34fa62501184c07b48ca2c2b0937..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1293 zcmV+o1@iidP)~A01eLy6 zgeFB{)*$VJT|Rl)2T?!ByyQ$VZ+WmY%U#^<+_v|;PaAsTWjKW1gY5i%f-&ee%FwJv zvjC_83INHIVFBI1B?QNTW>H6wM-Ysn+wddVg~?h#F+P|m_M`bw)X<5Iz(%(*8;iq0 z3FA`;$udz(D-Rhwq^~dslNP|w_?3%hWndF6O?wD2%wU-QjY1Nf0Q`)9ZW1gBH1ciJ zKBAHbb^*ntk75M77$)>Z%Fx^Z6zRo8Q7M5nfFk`UOjb)Y3rJUjg%YSDU1_Q$P)PbJ zlz=3CNkt0XyRSId;^XASY;K0!^bQyphGs&(Np(ex*XQ)J_=P@PN|P#z6lp%1&yE8V zh{h#$mMI8zWDx4e;K&&-pZ(}(_ojAcPK%NXk`!n@n$JgHO(GhXJWlX$7pt2}xpXs= zRFF8--Dj}#zy$34K9iLTdf5DS2OHk%q+!+ohSVfQwmeiTl+>g-YkpJYNy6{cTqQX z=l;mTDTza7LSScU!B}RL$Fb||Q8=Y=sKh^n-PgYs@M?WOg?R}^o0vbu+^PskrIQA6 z$_O+PzyV)Qg61OyXddY5QygmX(b=Og3@FG=;L6a9DE6ByZ|G%tLodr4dYLsnic?0Q zkpK=9QzMJ61#I(vnYAW zWJY-mCln5t3BlQ`9+Et6O?I7fEhVl*k?#kw#xQ-i#`v6B9XWW=p@7d-<8zMKUAm&5^2riB#z zr>jq)HDmJSB&aBkV;7D}oRB!+Qkp46gCuqL8Jud%W-Q^Dg&rCY*E3}5Z zoCFocgUqWA^V*yNGF=v_qDZm&=~3#ZM|n~tX-<;nBw&%gED3axzPcoEne=s80>?>T z$0P>d119OmM9?fn4M7C^Nk98V9YM(m%{CxJ`UnBr7-lf6X&=$R2b{!WCE#X!>qoIz z)N+Gi1`jpur9H5L7Bou$FXK}?k|m;sRvt32Y5IatU?T@GD8!-`kc&5@(298um500000NkvXXu0mjf D5XD<4 diff --git a/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_72.png b/mobile/.expo/web/cache/production/images/android-standard-square/android-standard-square-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-transparent/icon_72.png deleted file mode 100644 index 31c9395a71bf4ce7e372e4ac4f2e1efad02ca2a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 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 Efk&X}rQRy5dDP01C(Wo1xfHVjyl2QWFG6Y0H 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¨}w5v(!mPRs?7T!u6*C+J)tzSFc>J=om?w4uk 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
      Xe6^d|m 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 z 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

      H>RU+%S^xBr)_VlSn!5#iUb>eyq;-Jl^%T#Blk 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 z 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

      6mr1R5SGaoe?+rz4~K?v}--NN0lz9n54cOpZ( z`+v4|=c1YhzE-x3bklIn-8UC<&lwlj1X{hE^*a%B04X41q|0xt|GFui_s?iMZ4^Nb z6`DFz-71v4{C=cQ+RsV)O={8sWMw`a+K%t49%W=`Jn5r8wzJ@=ZjGdM5n<%&z3#Er zy|dak-*IDqJct!M6)rSz_^OUF`8dx|!>3cPVNhvUY`wqeD8bVXo+lT3ejtOod#oeF z>4R1NXw$$5+35)iIs%gSYpEhvzbfU-fuc{Ip|ALB+Nq}RpAC|BV%~TEy4=(9dG`M5 zS1ET5g^NqvHy6+MV1X15?QIdA^m!S!tMwiR6tY1xWlHSUfArXI&Hvc9^2zM{R%yb8 z>8#sV!>-mi=yh8OFT22bMm%PDyd=_e;8^LssMX)GTPq1`V;?`A58E=k7?u#?)_zbo zE;J@Je)YiC*KGHT8`BC+?P_}yR=DxstN6Tv6Un^5qSY!1fdY_VOW5&}Uwg+wswcz2~DcgrFCKg!g+Xj}i@c)$GByZH0* zLuZ~wZgDCMXFIx@N^ctd`8m2VDplH%G*a`f>~s>JEnJ-Eb;6^iUy!}8{^Pp za|6_87tcS;j>B)v#Y*|llngA~)4v8nDJzqwI+v}n9?})I-=?}Uo<1(ri#J@IF&Im@ zB4o*RuKBVSd~kDpbX+M?&O2^);E=NaTU6*a>V-;7Uhjl@!!d>-<7%REKMkXHk7msO z;S0pLB^SU++t{nga*)n9G8ymiG!%s%6)j1VzrXVRh17(ZNxiUl$<$p1_SX8{^1*PE z>glt8IB`2v^Yx#g8HI&BYYdl?PNiXpVAi-pOWdo4sSwAw?#R*0vl8BQi!}|M4WH)7`yA<64(r&HmPRDewpX|F z!Zo8s!mHk)4bmB9BDyQH{ZDmt)eCEop-BrVP{Q~h!W_eTI0hQ&IzR8$?={WvF+PBu5ETZ)4K&v%_f(fCNLFctq>o~q({ zw(T2zeNuxpQ|%jvWimxA=3!V)`dLVe8MD)Cu&N-G(9S`{Jr`IfbuZ8}LCF M)zXe!Ywkh+KkSt`a{vGU diff --git a/mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-#ffffff/App-Icon-1024x1024@1x.png b/mobile/.expo/web/cache/production/images/iconsuniversal-icon/iconsuniversal-icon-6b6177f9989e025d2b4c5c31480df20b64fea1475b6b537ccdbea012560ce931-cover-#ffffff/App-Icon-1024x1024@1x.png deleted file mode 100644 index ed858557aab88e3cba0ff06536ad2c3a218118b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28686 zcmce;WmHvN)G)f?5hWBvKtNGcL^=eK4pBhqI&`OW_W_Oy1}!NqQqocfX+&wHyOFL# zcipv*e((3*U-#b~j)Cm8XRX<5uB{&w<)y9=-XMe^=*o-d&y*qP0{Ha;gpUjU+VHLF zgCM*97tfxky5p?=xP;Pmd9{B!d6?|9-kvBDA<2CI?%g{QV%ZztDwd0)OO2km?Q4!l zDLErlR|Rs5it_PD)o&{ltYy5O8E^LUnQCRd`g8#9?&#?z&5T!~vojw;H^w&Hry*graYTGFk7 zL=cMAghKj>W=O8MCJy{37MF>UEQ}&tmnl=+HENZRKdOkuRJ}C|EL1AHrlU6h;8PJT zeN*;|{Hk6gzv-F2966LT>!X*R<=s}l{up`)>LO`FWIxHexMXpwC124XiBMkk2NG{S z+aT%nHiA>T2=8(XoxxXSxqv}tt(*g*06P`yce#-eRQI*bFKRgVz^uB1=<9}wzr6bN z5@BL~*Ak&DB`0|Z%2>KDYriwVPR%*TsMJx=`MwMU86;>h(OX7+?O&0N5;y<4c$p$8 z{SOg>Q@>7$ANR;{CLm9J{l@NzX0_Ga?dxDy^0x0hlhxLHJ)^kgQnnF}uL9UryZO2N zaVMHdH?n7acJq~XI+rzbhOTQe;XtT_2$8hrp8-O-F&;Sn9jcpn%r#;Sb_n}usD<=| zwKuhyP$HV8NH)u}y5kz4?x7~Vxf@WRe$263R3{X5me|UUXc;w)!S|WNubE-4c=6FR zfK|QohNcA$1c^TH&za#}J_r_)YM{*CNo1~7O)0)lckqGk;90iBM+S1ue9WAq;0`m` zW}RDZ$(K&%qg-Ndg$!v^-^_5gtW{;a5He&P>6W%*ZN+WHh5rKbzz*y59R$hG-qibc zwTasy8l+S=@8T`sAGVQhDLd8*P_iIv|J(#l%}G_*ACRZEt*+{x&n%ML8p^^a)hrki zrf|)LQ1tW0X@K2TKx^aIV2)|ER!vI16Jpa4;iL0|U%bZNPbloG$^pr8mHr1C5ExW! zo4b~p1<`h2H*^q44GLPdAIQ5+{NfnL%07nz0Xu|q9*CYsd1STLK+fDvW&wRfvQk46 z&`Nm=siRV7ujP4l{l1I?P)ShyqL##9_7Y3>!Po3FL<1#$c_XRg^K7L=x36nz>8?b; z;9tHAFCSD3_!PYM&ps;2K9lHBy(`5hPW+su>e*VYx=AdnI$)=HuTbXqq-w7l;!F?W zEjbq>9TGN9b2q+R$z>vSK%a3lT+fUEg6^znSh#Q~?O&rv_>!fbwWU%-=x05LKg`sh zhQ8T@iar8#t>3iZ+@ow`SE?`86zg_0*%s!AlfW5mfNA*mk7Q8LXC0o{DVT@bWM)n`_B*OsT zWsCd>{@|1S{9gbYA7)+Gjz1BfYxL$T9UkA8p>hl1oX~NZ$c(m%9AgJ!&<5BbejZbJ z7H8N!7|%a;yXZNOm;h%DVdE?>N`s)=37<`tSCBo1~*(Pm|S= zZ@~MFiXk)V>n&V zE#5ElwArT@JqUo6rxq(PYWt^gC-k@Wbz_wct@-LdJdDqM%hL}6 zc7r9fmRsic>4F|hQMm}SIB!VPy8>lHKf^@Q8auPs2ID*ur8y`hqv(RZ9I)T2Qm$r! z(MhGPRZb^!c9ee~_!CkRr2Zn6^p8>8_FdfYZG(*krP3Fv3aVKy_s5+HYvR?v=dW+x z70NtKR3QGJk&kE_WG(T2%Cj2g+SI8V>+w47Hk zY4x9W^fO%ft`e*tHOdTV2Ze^j_wRl(JJq6~z52F+^zGeJg=5j2q&Z-_I=;3?7L%9y z4{?51=)Icpzw79i;^1=NdFv=?>?^?KRH}%1+2kl!sitzS%T@oGzkVwHM(KHS-!{mO z5a;yR*SOj*&8cxt?{K;Oe>|+e<4lPygir3u1Y1<8_q<7E%=Xz(Jej8&a&Qqegzwg>G_LFC%e*sZ<-h+6e8lT@z9mZ<|$@JnM5!U7loX01`lx zAF|HIEi093W}Dr(1P)9~CmG?O-e77&%urHHW@++1k3RYJvEaKB5Ayj(Q?ONN#7?zB z$q5tA6mCa#D3z^L$)RQv3)WHUF2ZT!lq~&>lbl;0h90a5C~W?Q5kkl(b9EP(_QFqo zG?P@sSPV8u^TJkIWEuZDPMPf$i>zZ@FCG7SqAt>aEE-F^z1BtIdnHgFTt*f_CBN*;TWk;Ge^ylQcbHeYY20uBdw8%eLp|J zk|XBvi!u3ob+&KWJraLYOuCh@O_*1cTvkak&D705*zM$-1Y zD_yuIF^CT%=yvmrIDP1O7eyJgC6*!O;#=?xE*Yr8u&;>m<5|hb;~>Yxo9d@t4cpHsc>&$DFveGOu)N|iT_D)khlRy!JI7KRGRep-f zVAR0-xa9mKWt^wCCNHuhLMLqA2PcLe@-xpeCj!vJ?+>+ z1{T98gm{qB)mD*$L5>oRq08q_0$?pQ-*f1%)&DTwN-D{Jw>LxBm!k}h8!@zlHe&yF z`FJayx|=H-iFHL7lkTaw>+u%(h0j|vu<@x z-_9*l+EnXakFpV8Ca`vAuv9M-BNb&DR3wdjw|5>7)=($k)|1I6^R0~{g~!-=kct7Y zGd7dhYIup>=grPFj1<1Xu5R=W21SOCrTnMPXhmiE;prgL)^{vAS&a-(wkv1r#cC^; z#Y?dGTZlGZ@&d$l&NzG9f<1k94lHwhj~6^Asbgsm;=28;PO`(j@Brv+*|WU3{DEiO zaT*`zmJdW>^pnr0F(Bv(Odq}CN*vkez^)meXGSgc{dyQDc1g5AHUfY_=gp6nrWSY{ zf*we_7uE;D%T;Ty3gsWn)Y?pP+sE7%{ACdqL+7q8s{> zGfY*_KE8wTrV!H&gdE*`TsL@QZ}a#(f$>86b|g$aAL#`(%5A$v*^+}L6kR%T_F?4> z4#^q13JIH9*dI_eBR=Uv4}ytO9i|?*Z1fiCz$_Nq981rOl_iZkU((PVDKwyAbJmId ziFY|rzu_fm%vPwKCkpQZl`6O++~8&zL>*k($k8f;h3hUCwmb@N{M7v^fE9twXwYRz zlh}JQJkddoijtQKu#A5Qx<^HJe|mUB(58&BTo(|7E^?IX+LXO)rwS&8I|4Ym>J)j- z#cazO-*!`394eG!w`=fq?5E{nAz0IRj!_@wfYYym`-o3UpGYuHYGK#O6>K8`QQhW9 z$*{A$Och+QDBw>C$5q{PKgt}pJjwX(uU02TU;zr!=|$YIkxT{sVRtEPW=_X$9-z#x zTsL&tc(4mv#QJm|H-sfq8LOUQds>K7%SfBTMUM6zr0e0yw8ZrHj=SGmEgiJ8J5R~|H z@OhGC`^(w?3&VhgF_NSk{6}XErt|UPjg)5Pf4npTZGfgF8(;cq6;J{)sLgKAYVdgf zk06C6meUMfk?iK$4V=`Ed^^Uljj0s!YWwi1u4u#kGgde5%io{I5?_hw{#H7{$O6|v zXofih9nYg9`E#bB&jIW4LA87OZNZirL2olpU9k-?#CfKCso&w<+lH5XLZ!MKFdkX@ zZcKP)3ipk-&0O@ZSg&~Y0;6aW`?ljHm6jdW0Y3D5Mu5k!TsF%-Ixx}$wfz}s+JURo zR}iCirs-I-8fh~5)AoU-;7oKpymIHJGdm3OVwO66AJ((jJ#o8RsYD2I*(<5$FxPY zzbX|&FZqbY-o6sjeaB@Ct3l1?HKo~yVBxd-as_;ffQnR_jKH(OPQFTo#NP$%4(?E0 zkzBwQjAku0>0A3RuLgzuRvCnQCXkc`YNQWCn=uSL6nyCWOWaKQXi>;7i zdn@1Nz~kkl`hD0g;8}~6BR!Q%pkl&BdJWFlsMQ#ew4{Ck=G4>`PYtjDIZAXg--_z) zb|;*~8le1(d2C4QBI6&yC~Sp*%I{UEEq%La=1e{=1Lur8Wjn0>bwMFt%(Gzp+35WA z8=tzxs{B0Fuv)cU(oBCveI;$d;%_iDvn_cCtam{{7kf%oVGKv5edQ~4FYgHFV0S^e z%i0eG9YqO!{q-2DVF}@!S^7TOR38a7I6}liwyrH}rk+vl=9t4x4m6wJ%(dI}l{TpY zTZd6&{ilAj*(9koUq)wLup(eUr(UAwO|?s*%K~GR=bJ|zaV~@S#o|{aA(nrBEf~_m zvU4dc4bS1_I%0`+{d)`$%a@^5M#fAuFBUvYiV(sA{kNItNtarCO&9AHhbiWH@ar9H zwM3m<)z0MQ^88P|&;@HK+ArGl>QbBn$|Y)gSpVF5rqiu;>&N2re_Kv|Hn@y0DHV{1 z^*Urvr5X%f^aPe}>xE-xh{4YJ_kh1XiM&=2rBmIw=(4G+EQD02vebxCrX6$(#GBG4waFqSw;jyiZ-t+ItUvb;#CxucbM- zP3AB4?Q4!Rl3CYbu{YkR1}gmxx|2KOMze2WpROYr`=;~&Zr>oEFoK)uKVi;OmzMrt zi&`+7Iub5j$=IiV-^a?Q%4Why2T!sa7|G!L35hoQ1xLcNLcW}>zpyBj*CgR*2jFK2S5U!+2)~v-E%I{DZBRp~Avm z!4`)aL+nf5AQ<-GEga?0BqvtDoBwFTN(bWYU?Uh<}_iJAAbBg-f!%- z8;8*o9J6xU9~!TIaE-eq@`ZV%w02fdl)QFUNmQ!__|fr|*KCC+1($cq9cR>uh6DbK zh%d>QWy&4zN!gvLs2G#h!11j=vYHMVRYPoS9g&pgtukXpe`Gzt!Y>NwjyXRrWD@LN zZ)ttyQQ4)qk;Hkln3LD%tlt(G{6}SYUmQ}EuE~7T5dUcw#GA+EJ(kwD^J0lQLZwMg zS|K?y?je(l4#LwCF#-;x&1NB>D$O=j`&W`&Tp_-`Dx_#XrT96E?dpe-R?mDZ9zcKe zKkdHIr3mHXjEs=vXdOQl3ZWq*Z6j9VBh)U_4p+s zVj5!ir1YxZvD+_gNvwzT(gw*dj307`Gjzx%@Cow!ni>7b{k7Q}{t5*Is3(OCF5g!f z&|fC9S|QZ`N@SD6l52NaIvUCJ@ev0Pc}<_<*TD-k>wO-D#n&4<1eo@sBaBp-dvT#4 zO2EH6Ox~*Lte$e25MY<}`@7OIHk+`fh-Q_PnyPn4>q^vm$#TT=(|hdI4`~J(nX?5Y zB9UWgJcvpVY@hC%vHp+k(uU5#>jl19j7g8`yLiwSZ)(2@&1H{KrD;v@mEQT%>%}2Z z?RJ)%1_mL&fwb>ODp$?RC`4=XW)CR?v;_aFUt9_vX5o#>A5&$v&_XN&j7d+=^@hxS zdFD=hi1P*w4s`ME$C80+)g7eGCg3NyM?q-3t|&G23PC}Vn;qudlW-uBxv%H!xn9m7 z_0&HJ%xvZW<~Ng8t@5l{g`Bpe5uIxaHw<5|j_H4Q@||A49Z&8&cJ5-fUdgfOv!Lx6 z@D!w=qlM_>I=yZJ^-iDqGnbHm%7&og=_^Am3RU8f;sJCWDR zaiPm0bWoiY7xn2OM?+{HyEeL}q;l|jkp`EInk}ntdEuiecgp1M?Ifam>wFB#TC;?Z zy(-XKPm1e85(Pz|x>||rMZbh_X>A1?W^YRsi!O&r7roh3yA{usrRr#UNUW9y2UVMw z&sJgOF&7Y=9vehITVygKgswO#?4RS#ywBmKJt#GCJ?SAo8&r2wb3zRVMI!NKz9y3e zqo-C_RxZ{o6+Nd5^wKnO+h>9QqnH>N27n+)9s_@x(3I1marJmrwB-Es zkQ4_M3W(CWyIO6Y3qA5Um63QIYBPGPV#~aEzEc{BIbBn56Vyt=Aq*SYb7 zL(_F=_F-j)78G`Aq~7)SddM+`t%;`;5AU)rvrXQi%x3sPYo=NnWycGAXe&}zg$-)9 z_>i_MN+N$&&tcX-;D2AH4*%JgJu<5{H5)dMUV=>vgawY+M4?qS9#n4iTR-4z^Iel@ zdCH^2!V5v+Pj9_yU|}XMxj2C|s^SBVvh|)0YL?R#o)@(h#-y0H;RO+_{6J8&4Mh3O zM7$F{%>QOe0Bya&GUg`{Ro{!H?VKp8d|sy^o&LKwUM6{5%kf86^&EXZbY~yCW15~Z zjLuj0}s$y0gG5KOxH2xpk&I>)Qou|%fy2dG}%_xVw z{?Y~oTUO!q$d?FBNhqustLnX#MfCZ8sT0Pdh%4$b?t|yrLx(>DT2-~oIRb_OR3H{A zdi0yHv&ZjEuNy=cWFHL{57=?|Si20z5*hbq_u!&*jA3^uie6cc*_W$1@-=%lgGS|& zVhYa>oF(cuJNWq@K+Q}c&>ihk|FzC@>w(5w61YX7D_ZB?oqfBbfwl+A#ukMvP%|mk zSBQXJy5|OI^d~j$+zDK>A`sa^9{OkQ%I7!ZLyoVox?;}H(H|3>)8>^6rMJe>R3p&9MSWvD)fxP8P3wWs4VGn0+5)l{chVQO0zzSL|i24LWWb9I=6y z>qX~FQch@Ia>C{(AmL4Ve4Z+s6ykJ}20oJ)1V$*URs_f?ZKpCALQ`;`vSxqTqtuHK z4;pU8hl=Xv6H`c#R<_1gVqzgH%Y~vxr!(p{?AIX^dOGOSOND%n@+vcV^-#7u9QRe` zxd(siZRx~9caDc(?(lf#cDjh0bqBS34$F+&< znz&otos)p z{$qI@=`&w3+)_dhHRDP`oS0}K^}XMdvXoOdbF2b$e7RT>uS2qYbP$z(XaUpda)H_N zXh>AEG<~);xzkY>r|uUQF3O?A=xIx>zG&|@E6&;W?AxA#bI-R61ki&pQYa|qx8T#{ z^I_J((hCRuPdlT1kI!ispig{&8T;O2Jkisc;iVw@x=D<#rsj5~1(4k60%Tl}({$1s zYUZ{-f_rDYuw=Q(O`Zahy#VAe&WaQPIKg>OaNK{hh00c(Zc5|SedoqSJ>1*X?;I-1 zc@9l1zAIDE-j2D4Q+EL5D|Fuei2$afM2YAOR{UWo27K|L8Q?69?TxomRxokQ(0_{` zhR=~}tIxr)yfF~S9o%7iye*nYuZhd~?ajM4>L(^@4*+{wAooQf1@$wenRW~v)Ks+B z@P~Hdu^iY<5Gc`OC(UW49M_5JrpAEO6BHDHyZHqu)n*h^pL}K*09|fy^Yt1F@x}x4 znt>PD3})HB0xS`Q7YrD=s8@hiW$&}$)M)^*m0bD@%xISJ@$0(QY?u$a*Ls0sTJRys z&T1BBHETu+)O3ZH$DGq>03KxA2-aVimz^d9MWH?(wsM%4xD5m5pgT;Rm2#5}erAJ1 z6&vz?JL;wx*dgc>gWdwmkO-^Xg;J*vN5TbT)Ci$Q6j;{~$SXMSbjG0)9-MesTJw+* zqOt+IHsTfKvanNm1qCIUwCe2UP~)Py!4Bwp$1o?$uUc?9M=V#w_l0%YAu0p_=bAkE zz4NRGzmDoVCO>Pu8Z3DN4P8(hye?dp_Y7*3G%wrk^~xZGBtrqyI)!si1k~80+s5Mh zh#YJNIQZqk?a_d;H3EXVp`sd(UT2&-#)r75>7(I4Ot_qTFt_}#SHZy&m?hdAO>Q?z zb`9mQ2{f>V;lV|b0+%p6EC3wp+&?^9(--B_1e*wf3>MXF*eALb8BJap)FtX9#i}MH zsYb&;)neIMH(rO_yzKr1MQLC4c?R!4Jyo->fz8gPQUa}RiU#1>q3KTPi552`K?8}ojDn02+|3?Sij7d=evp~n+7r>roi33Nt75zd^T_Q2u?ydCK+NlN`cKfRmXrvB&V?#<0u73ByPt{ZMqrm?L>?JZ7Z z%c2?_U4Zx=BPEPmaO?aclpNObqkH%&T= zp9JAKn3gR?^sJY2ZY2@Xg@-fcp!4n9I=V7+CF0%uN9sd3&91$0YNJC;9;oI(2H$CL z>J*(_M-_6}$RyvnHNHNm?D(MLsb_)-N^?}hQCnvEkZz?tiZ@!LJDpi1>|q7_DW_MCP>c?Cf~A1 zbGN#IMuJs9WHTzXbWP+c(#U3b#!A}l79+Xj&s#D%*`i%~YO93M+YaD-BOtKiM{w)A zs%H|K877B4T4JlWlJSZoh|J1Pk4~kZ@R+RVvbU@ z=lW%LT-0613(%Y1k)_-*jeD1)_c28G)V*_ECfd{NFSPYkcC2{}mJ5Rh?rir>#9*!J z{mZ)dEzg%aO=+vrWFXFGVCVL?J<;vktcF+5_Sin=aEMkJxGGZ(HJI<{Atl$NbyIF) zl26*BuNl6-UXXh*MX&phWwEnvtUYT4OHb{A(Tui2DB&BY`TC)}NfEgDzp}5OhtBT< zRP7&IbBv6VCkWCpK~#ir<76+Jm)H?%oBV*Le=>2;idi zYcdk!)o4z>A1Jp?>S|n63aC#{+>LazIKTCLY45D*+KDgViKeKmw@<8QMDJwo#?%(8 zP$gVSVp0IZyr-ZZy!nRo&f-KBD+Gv~^&XMv_0R`teC;~!HrKX2-8*Zcu$b2P+gaj4 zPeI0Ox)w5IrO$fpXnUf}b$t7cH+N>5f437bAWMG1apiV}zp-Xjkut(1`gUdfLP{!uRv#RDMWJ>x*SIe(X;<&qyJ%P8SIFz7 zwfxHJrkR`^;eYN1h;rbmLD1A!wOYjlY3+I|n$gNN!AtCXJj_8cu_`?zXXZaYaFdDq z61!b=#c%)#LVyJQZ`UO1Nqx>5GC(gtIAi7LF@I)tQ$CTB?5Nn$_yceOnB-#&K0!hG z@=V^kw^bP@X=}iE!{Dmm!tB?srdBz6T+|PcOJAk;j;K*y)7wm`CGeg8X;c4;iFpTe zGI1u;u}V7evMpaxs*DYyg6r-O$RM(f*U}>9e-%`I(fsrhSaW-j1OyX%)vMjU`D-|J zcc^gc>K}unG#e+EUg2XrzyzwR6CN+#E;}f z;igNCIX5y9>3-_gW2Dz08c^>q8+5+HJ=Er$(%aosyBioqQOT?C-Bl?3#509G5?t?x zbl^i56$hyzYfo3a1Runh`>nc;oE(sdjNf~{6ok;G1Z1KBna}x!Vj^mK;pKn+TN7vh zev&v%X8z!U#Y_k2MU<#<#C*dotR_=X$W@i~WmYyve;otOilc~kcos7uVZdlX&}UJQ zSdz?JnncdZ4DY&C%_JnL$iHvff4oizqyQb|k%}89Bdy?i&Vr(pn2*b}MYVW`fRmwh_ol<4wzsh�k+si*!9!J=8KakBl8H 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 F{V& - // Split option: 'foo,bar' -> ['foo', 'bar'] - def options = (findProperty("android.packagingOptions.$prop") ?: "").split(","); - // Trim all elements in place. - for (i in 0.. 0) { - println "android.packagingOptions.$prop += $options ($options.length)" - // Ex: android.packagingOptions.pickFirsts += '**/SCCS/**' - options.each { - android.packagingOptions[prop] += it - } - } -} - -dependencies { - // The version of react-native is set by the React Native Gradle Plugin - implementation("com.facebook.react:react-android") - - def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true"; - def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true"; - def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true"; - - if (isGifEnabled) { - // For animated gif support - implementation("com.facebook.fresco:animated-gif:${expoLibs.versions.fresco.get()}") - } - - if (isWebpEnabled) { - // For webp support - implementation("com.facebook.fresco:webpsupport:${expoLibs.versions.fresco.get()}") - if (isWebpAnimatedEnabled) { - // Animated webp support - implementation("com.facebook.fresco:animated-webp:${expoLibs.versions.fresco.get()}") - } - } - - if (hermesEnabled.toBoolean()) { - implementation("com.facebook.react:hermes-android") - } else { - implementation jscFlavor - } -} diff --git a/mobile/android/app/debug.keystore b/mobile/android/app/debug.keystore deleted file mode 100644 index 364e105ed39fbfd62001429a68140672b06ec0de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2257 zcmchYXEfYt8;7T1^dLH$VOTZ%2NOdOH5j5LYLtZ0q7x-V8_6gU5)#7dkq{HTmsfNq zB3ZqcAxeY^G10@?efK?Q&)M(qInVv!xjx+IKEL}p*K@LYvIzo#AZG>st5|P)KF1_Z;y){W{<7K{nl!CPuE z_^(!C(Ol0n8 zK13*rzAtW>(wULKPRYLd7G18F8#1P`V*9`(Poj26eOXYyBVZPno~Cvvhx7vPjAuZo zF?VD!zB~QG(!zbw#qsxT8%BSpqMZ4f70ZPn-3y$L8{EVbbN9$H`B&Z1quk9tgp5FM zuxp3pJ0b8u|3+#5bkJ4SRnCF2l7#DyLYXYY8*?OuAwK4E6J{0N=O3QNVzQ$L#FKkR zi-c@&!nDvezOV$i$Lr}iF$XEcwnybQ6WZrMKuw8gCL^U#D;q3t&HpTbqyD%vG=TeDlzCT~MXUPC|Leb-Uk+ z=vnMd(|>ld?Fh>V8poP;q;;nc@en$|rnP0ytzD&fFkCeUE^kG9Kx4wUh!!rpjwKDP zyw_e|a^x_w3E zP}}@$g>*LLJ4i0`Gx)qltL}@;mDv}D*xR^oeWcWdPkW@Uu)B^X&4W1$p6}ze!zudJ zyiLg@uggoMIArBr*27EZV7djDg@W1MaL+rcZ-lrANJQ%%>u8)ZMWU@R2qtnmG(acP z0d_^!t>}5W zpT`*2NR+0+SpTHb+6Js4b;%LJB;B_-ChhnU5py}iJtku*hm5F0!iql8Hrpcy1aYbT z1*dKC5ua6pMX@@iONI?Hpr%h;&YaXp9n!ND7-=a%BD7v&g zOO41M6EbE24mJ#S$Ui0-brR5ML%@|ndz^)YLMMV1atna{Fw<;TF@>d&F|!Z>8eg>>hkFrV)W+uv=`^F9^e zzzM2*oOjT9%gLoub%(R57p-`TXFe#oh1_{&N-YN z<}artH|m=d8TQuKSWE)Z%puU|g|^^NFwC#N=@dPhasyYjoy(fdEVfKR@cXKHZV-`06HsP`|Ftx;8(YD$fFXumLWbGnu$GMqRncXYY9mwz9$ap zQtfZB^_BeNYITh^hA7+(XNFox5WMeG_LtJ%*Q}$8VKDI_p8^pqX)}NMb`0e|wgF7D zuQACY_Ua<1ri{;Jwt@_1sW9zzdgnyh_O#8y+C;LcZq6=4e^cs6KvmK@$vVpKFGbQ= z$)Eux5C|Fx;Gtmv9^#Y-g@7Rt7*eLp5n!gJmn7&B_L$G?NCN`AP>cXQEz}%F%K;vUs{+l4Q{}eWW;ATe2 zqvXzxoIDy(u;F2q1JH7Sf;{jy_j})F+cKlIOmNfjBGHoG^CN zM|Ho&&X|L-36f}Q-obEACz`sI%2f&k>z5c$2TyTSj~vmO)BW~+N^kt`Jt@R|s!){H ze1_eCrlNaPkJQhL$WG&iRvF*YG=gXd1IyYQ9ew|iYn7r~g!wOnw;@n42>enAxBv*A zEmV*N#sxdicyNM=A4|yaOC5MByts}s_Hpfj|y<6G=o=!3S@eIFKDdpR7|FY>L&Wat&oW&cm&X~ z5Bt>Fcq(fgnvlvLSYg&o6>&fY`ODg4`V^lWWD=%oJ#Kbad2u~! zLECFS*??>|vDsNR&pH=Ze0Eo`sC_G`OjoEKVHY|wmwlX&(XBE<@sx3Hd^gtd-fNwUHsylg06p`U2y_={u}Bc - - - - - diff --git a/mobile/android/app/src/debugOptimized/AndroidManifest.xml b/mobile/android/app/src/debugOptimized/AndroidManifest.xml deleted file mode 100644 index 3ec2507..0000000 --- a/mobile/android/app/src/debugOptimized/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 650fa75..0000000 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt b/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt deleted file mode 100644 index 8a4d784..0000000 --- a/mobile/android/app/src/main/java/io/skur/vault/MainActivity.kt +++ /dev/null @@ -1,61 +0,0 @@ -package io.skur.vault - -import android.os.Build -import android.os.Bundle - -import com.facebook.react.ReactActivity -import com.facebook.react.ReactActivityDelegate -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled -import com.facebook.react.defaults.DefaultReactActivityDelegate - -import expo.modules.ReactActivityDelegateWrapper - -class MainActivity : ReactActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - // Set the theme to AppTheme BEFORE onCreate to support - // coloring the background, status bar, and navigation bar. - // This is required for expo-splash-screen. - setTheme(R.style.AppTheme); - super.onCreate(null) - } - - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. - */ - override fun getMainComponentName(): String = "main" - - /** - * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] - * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] - */ - override fun createReactActivityDelegate(): ReactActivityDelegate { - return ReactActivityDelegateWrapper( - this, - BuildConfig.IS_NEW_ARCHITECTURE_ENABLED, - object : DefaultReactActivityDelegate( - this, - mainComponentName, - fabricEnabled - ){}) - } - - /** - * Align the back button behavior with Android S - * where moving root activities to background instead of finishing activities. - * @see onBackPressed - */ - override fun invokeDefaultOnBackPressed() { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) { - if (!moveTaskToBack(false)) { - // For non-root activities, use the default implementation to finish them. - super.invokeDefaultOnBackPressed() - } - return - } - - // Use the default back button implementation on Android S - // because it's doing more than [Activity.moveTaskToBack] in fact. - super.invokeDefaultOnBackPressed() - } -} diff --git a/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt b/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt deleted file mode 100644 index 9914534..0000000 --- a/mobile/android/app/src/main/java/io/skur/vault/MainApplication.kt +++ /dev/null @@ -1,45 +0,0 @@ -package io.skur.vault - -import android.app.Application -import android.content.res.Configuration - -import com.facebook.react.PackageList -import com.facebook.react.ReactApplication -import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative -import com.facebook.react.ReactPackage -import com.facebook.react.ReactHost -import com.facebook.react.common.ReleaseLevel -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint - -import expo.modules.ApplicationLifecycleDispatcher -import expo.modules.ExpoReactHostFactory - -class MainApplication : Application(), ReactApplication { - - override val reactHost: ReactHost by lazy { - ExpoReactHostFactory.getDefaultReactHost( - context = applicationContext, - packageList = - PackageList(this).packages.apply { - // Packages that cannot be autolinked yet can be added manually here, for example: - // add(MyReactNativePackage()) - } - ) - } - - override fun onCreate() { - super.onCreate() - DefaultNewArchitectureEntryPoint.releaseLevel = try { - ReleaseLevel.valueOf(BuildConfig.REACT_NATIVE_RELEASE_LEVEL.uppercase()) - } catch (e: IllegalArgumentException) { - ReleaseLevel.STABLE - } - loadReactNative(this) - ApplicationLifecycleDispatcher.onApplicationCreate(this) - } - - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig) - } -} diff --git a/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png deleted file mode 100644 index 831332d475a1dc4884bf11820ce65e7743108ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 572 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 diff --git a/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png deleted file mode 100644 index 761e9dfbc8e2c7eb5b50a52091f0f6e52e242900..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 370 zcmV-&0ge8NP)Jj+?}~> zuQe!~%u#(E$A-efgrhmSjx!bV2?l%w5O6d$6c(bBJudcNxVnwe^WivOXLj1dhQd-d z)h3&2Gc1Xj%kW$bBqoX?P{LjbNf86V0Q!kAnjDY>1ZEm=5fsHTEk^#QAIscWq4h#m Q+5i9m07*qoM6N<$g0cIOlmGw# diff --git a/mobile/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png deleted file mode 100644 index ef243aab6c07672628b98d8eb239605edfb97c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12863 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 F{}05A4LSe- diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png deleted file mode 100644 index 6b21888a01f7f82d9e68c237edde38ba4eef1202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 827 zcmV-B1H}A^P)N&G020m4*|g~K6yka(o75(c(V zeVuBEFdj*~QY3%~)fd4ffk!4@2@E`XGHr1FkEPttg)t0hZ7Q;PZ2>E+@I+wXk%?x% z569^Gayd_@4gPI;Lzz<_|3!1sMkk3zt_!^<8hJWx@MimSK7W6bPxn2fwW-L&qYxh+ zPokTNM!BgFxv3CRKws|!QOjk{=CuXhIIxQA_aZ!cV$u+=po>JKB~ce4z*X?;ML}1Jmc*R1zd$zCK}Z(b=cbRj2|!5(sMM)%EkuPy*k6j^mD%Go+N6y=w_nXk)9ka zsS;;?u46P8W;7S3e=tsct;6B{lWf^gKqnK8DvrQ$1qa^yo1X1c+!~AU=gk;rf2-xn zNR)%ek_;Rfr8#M%i$tSu2ji^SwVJ)3r4RyIn~Ln&`k3zyKOo&aOT`gfys-qGBpRg> zHgj%_MtEE>nCG~HnUZ8qEaIY*iAEi-&Crr6F*0uPPVY+IT3;X>Qe3zm(l6DqLFDRPJT4b2VXUE=~j$y&ebt*#WI^?2Xn-09CR|#tnsBX{hy36GH!8u%))U6 zO)uNDHP0d?+L=^IOR7XmszkL(yiz#)R}>B&NxTx|fg;sc#2}AH5|2bXHgJyW8xU!1 zJd*ffkO4|mkBuaY4+cJD`^aayxC3kh4D_;*>=tPT@xj2S?AHuuy7(SJ0(b>5S)3w* z9}w&mZTx~yf<;i*2;q_dOcthsBrnpG2?PRxKp^lx^bgtQ=z_RRdHetX002ovPDHLk FV1kGEa+3f6 diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png deleted file mode 100644 index e9d5474519c701b4b518f2f0a24d7d8742e93416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29081 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≠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 PMTS3g4RtcK&inljbZB-$ diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png deleted file mode 100644 index 9968354e371eae97478c178604989903df882762..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1162 zcmV;51aC))Yy??3g@o!`*djl;D6&3ePN}|VX+fEp zK}3}1TWW|R4re7TZAzq~ncJGvnVa|ScDK8G?{ne`H&CiC&)v=go!<|`Fbu;m48t%C z!!Qive?>3^)JgnUJV=5X6t^SrGZYkq2rgpNM3O^d3WH>rAcNFN1QySd;B}yk;njsr zBS|)iDJU{TkRj?ESw#5^#UgYP>>!7y#RU4v0E-Mz9SFi~Ls5r*mBgu9wSujU8*ojM z3BA;#cpR@#EF?@l86a^ z2tL?3g0$+%fAaEE-Hb0EB%TnooXKL%C!^@-_Tf12)~BWHTl*V2NHn-`$o-lxIDblX=_|U;d zgE6IXqy)zS$AQ;A8b#wXSIEyvl4eQ8^L5uqI^0lFm_P>`4T|!T)ZW|2{$qKh>~1dL zU`rmetD;Q5E6U8uex}~hPs5U{=w_qIoAq6E_u8B|n?*`=Kyv7KE{Bfil2V+Xq;77A zrH@^sv?zft5={zolYH6O#@c0?fr!Dp|I!oc(WKU`%P8;bx=3o^SIxc`l2T8I@5Up4CTb zQGx~4VHQ+}Q9#p)T$ZmdC(A6+MJ&>?gAO`KGQ!h((&? z!1ksBzB!gh+RVx*I@oA1u_DIen(KUZxR8`>hYQ)&T)?>72JzX7j&2{Jh(+3j(J>yG z9YzNmP1Y>E%s@=C_q%*j;t9do_5imUS3bz*S32w67VVBeW8=ZH6cDfSV+t1 zY_3NvQi1`8Nfj|3tq!wfelJ14LKhp&=1q$*Z(0PUAR3b-l7hUfBvRrDHXb1aOYiF+};D~3xF_uBEUc3hIU*Nk^H8MR|s~a*hB_cWI*FPu7f?5AE*F=42=Px4LC|M2gFzgF$}{n48t%C!!QiP cFbo&|0!3k7)F^01u>b%707*qoM6N<$f}>Iz#sB~S diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png deleted file mode 100644 index d61da15d2410dd60355d0d9ca34bb2aa741267f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47123 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 diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png deleted file mode 100644 index b0f2a7f8d12dad3b4b1601448dfc1ca8bdb17b2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1555 zcmV+u2JHEXP)G8vJ7ciXEL#^4I-cTtp*@Mrx2+QXB;;@t;aE zyrRxgi$)Tik{kqX!N2NBaS)9pny5aSP;AHV6x&rFO=u#~MX?Kz_@6|v3r!^YY^8W? zMH7hzs+T&Tk>b&)dZ|MLi5^PoOv9oy z`GkN?8=`bRdYODfBS9`r1~8e#U{g_td;wR{SeN2@Hf@+eNy_-_ZE2$RhUa&B9e z#AGf8tE$Mdxow6&y|;jzi{k+v>}+J^l3Ci<##nc2g3qmrbMwLs*KEBbf}gk;Zr{$! z^!>Apv55frhDL)7jRwhC(J;&Awi&*5*EGu;Quu|$aCOxge*e7-w6BeEBj?A096DOV z=4V&1`^SqJn+V_sEn8U6Ei+SyZVQQ;0n99Xqk(fi) z;}c~;kJ1uFNkDOXbBx=YV_cI=N#5!$r|Z=k&YmwNXFBTe(x0pO=7STM%Ee&!?`z~A zqd{`^J#v|yTR!GLm6mvXrEP{UuaENZcb9VNT!@_a`pba{OeHZ`NkEY=o|N23z*TI! zGeW+}X%~}847PYtntZ1Q%J^TVqYn8(K@XEj47PDijC}9(Rq*=BO0MVXj6?Tds>ru` zSrU`E7_8&Y2rnF|WhO4UMk(0y{9+!s=PDiT5kAu}OTbl3Ou3vo7vj*-Pcb$TAYVs& z1e3WKtg150zDGXdxvqM0JP*3xsHXdkYOWCilwwYIuZwb5YZQ}74EOafP4nDC<4D1r zlwwZnZcT9T=`ccIG#4Lu{N5|Hu1xU#U)OQ=d?`1wAe80NuYSz#`>qgh6{d6Xi7%{) zbL90_t|+9910+*IN5>045)Ulr$zYh#2;J^aGOM+DHkB1!X#B*j8v z%`1sDuOxaXijP7Ai5@YEPYewtdW-^!;-Qd?pn*gK(aL4uLyE_TqJ?oZkmz%qVj(z= zCK6o)hXD`&^AH?H6Nx5bE&T|N;CF%}qJ@4mk?2&)ULcHL2`(Yni$)F_?SGM2=Tp3c z$95oyzsyj=7SY5Y8aZgTzl(6^9!{Xx0#xD;VI*5b6DQHkp#b(DVyyEqeud;_pb3ze zDU0A`%D7LgVTb|{6qq{0Z76o3*aj>E1oKM)7ZCgr#bMFP`xKC19;q|b;IRZ)00;_8 z0TCplqJ>E;%d#xXvMkH8EX%Si%d#xXvMkH8EXyh`{{lin(SP!0(O>`o002ovPDHLk FV1ju{-e>>- diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png deleted file mode 100644 index 4aeed11d00badbb02d5b40a3d24fcf97dbabbd5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66529 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

      ^;WArDFIvK1}FmU%q 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 N_G%kxm1)=q{|~x=+3WxS diff --git a/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml b/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 883b2a0..0000000 --- a/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml b/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml deleted file mode 100644 index 5c25e72..0000000 --- a/mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index 9764d2a..0000000 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml deleted file mode 100644 index 9764d2a..0000000 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp deleted file mode 100644 index 31c9395a71bf4ce7e372e4ac4f2e1efad02ca2a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmV-y2b1`TP)s7BJg@L2<2UfRG7fWFMR?WL6y?Cd@@8?9@oY zht10<0#%3c$nTp&gAa zq*EtG(?UN4eNd;-fi)=B0xlj;K?J`9-V{@bVL)I&ouPmPJAl~?4M&hH6J^{WiAEB2 zfw4sRCs4-FF%rd6?`l4%{S7{P(db2;p^ylNfKd!RSwvavtzmoZCIZ}}agVA;NAV9} z3PV>G@RYZPZMB<7&_nWtHNY$^vkXPZ6*d%V!j8)me(@A^FT|z=h>=F5;}F zhfoa+BhEFzgQYhgc8Vm5YQTdfSvC=>C5kF6#st+8#dIuvnJ$4+EXEXLB#?upFF6vh zVd;xaV(FL8AZco`v*%wKocv!Jjo0k7cIbq{5=|t2$>qHxZhrsTRYny?NEJznY}@U@ySad9Oz>r0Xm;@Yx)QG3w2>;3 z6!_$_gY{eU`6{$_=)Cf)Vq$SYD(IxZuXp4UjR}mDjp=6LEI(t0M{v91M52EEN zG&@N4=e-`5S9M@EiOJ43If=vs$)=4D@ye1mgrH9&@}m6VCs(oSie&$}^rowE1<+CNWuNdIBQ{Po<+2 z1Cr)UU?dV1m`%rI`VY(-r-hSQ2L0ybh9$DvV$@9g~$5L>OBf zrtzwSWLtM-bLezBFMiv{{3pA}_rx$#SrMSJBEVqKyft_+Sw>odJ;yUJ($S@H@Kic) z@62J>$8H)fI`MVtxSR<*8F2=iP6{lZBeFF^}{Uo9(Ut%CKx{=j1Z)Z z=B>d?3P=gxm>!^Fe2B(t4sNyUJd8HK&Yt5L9BD{r=Hwu5SAtZ~yft`9p^}0q%d0z> zIr$DkLQ9*C?ucZduHUxt{!urT6+v<`$Rs=921WXtiX2QrY-(P&2BWGN^zOj(&w{0Z* z`=Lx$Ep5Y0IwtB2N?zYsNV2CV-(hY=fPt7@7G&$%W)`d&O*Ag(?b3BS?Oht4j5ubI zm`K+ZM!F+{hcUJ|%#2BQFmkJ1$4n9vWx5jRnj+cd8+H{TnQ_b{G1;uLAVzApMm3W^v`Fon%E%M9I#KVJ3;m zmd*1c1ovsY>R{>5OE`8ejlM)`+g}_`oCYv;>n}stwdH<-JWR2Gx zyx=XNv?#)iiFX*D8^vx@1VfUG*X$fS=c2t!!-&(aSh2u|*>qCijhAk4^87Hawc0S! z)MBTp#m>Wc?S)$u=SDG`Bn7hFakj3#LSasnufj_UeXLmEBNZemQd$(@-3^zRH!Z-I z<#Hxi|MGR#zIc;V(Mh4)tQebr+RVXI>Adw`4#&==p%f3~$%wP0($C68x5@LwNF|*? zP+1Y6vLe7upUy{TU7Y*W$<L%xtTFaiy}-N7h?K^5H?*g7<2|ves+xK z=Jh_4Zr+@(*kVnFZ!s)-`HSdHR)KsJvDAA)ztpiY$1LO%opr0Q`Xs7CNj5=;Y1fhPbPkG3e# m1~ef#iDEB`eWIK&1Mq*GU29gOB>;c`0000K3Qu2Ui?QSGqaS$g#!(2Y$gT^8X0+cG7=m{h3FO%eAgB*ZR+jMc?yg% N22WQ%mvv4FO#rmpet!S} diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp deleted file mode 100644 index edc4d67cf3e801c9237ff18aac8fef0a66e177e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2599 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 D5XD<4 diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp deleted file mode 100644 index edaae30ba394cb0e8d3cac2667d4ac481d88ef36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 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 Ef=)PrOV6yUbaSW+oe0$K4vB7|WdBZwC zi?Rpt3M*bre`53fFO!eS0Uzcwqr_+!pr?Z~{N)+Ua=g!~PXQAXgQu&X%Q~loCIC}3 B_(=c& diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp deleted file mode 100644 index 03a8cf238a9e7a9837c44b1e06ca54afc5865e19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3620 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 diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.webp deleted file mode 100644 index 03a8cf238a9e7a9837c44b1e06ca54afc5865e19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3620 zcmb_f`9G9j8@5E2v6g*e7z#}>md2nFMl;CXVzOi(5@D$EwQrMk%w$P2l&w%G6fLsO z5N2qRip1DuCr0Y~KHi_+Kj1x|&$HambIx;r&V60ab*__UZ;KHTk{9CQ;u5jMq8)+j z$o?U~51i8=CzgQci*2w%Es#zB+^pUQb09cUFNtzq9jxkB6Za* zg0JzVqs8atuVc6fqnhU6rZL(V%gUxFO9oyw=O2E%{PNpcV$;Gu557f|mkNJxek5QO zNJ%{dp)6W5r%$uUG}_-!)8&+H)!BiS4O8_0xA`Q)dmLJx&-Lg!2sJyn+BQDAK>}bt{o4gwL`8uNvzTZ#W%4Ekl*(h>OcM8mY zZyTTzK zxdafD5_M;zH&kmd^>C-l&R*Hwfxb*_l0;Wf8F=R;`5w2JMkQD0)gQLHw@_yVIt3=4 z>+p6$4df{gyhqYKQ;6e_{C=$Wt9ZVa57V z#jVlJOU~<~X}PBuv|!!*)Oxf9DYDJA{39*PQ&GY*O{g;>-qecL9&!W-xL!z!H4CMs z*NlE6qT|(sz<91L?D>y5vmli=Nj_3H_9N^l4{T^K6>S5R@JJ)gV?UmQ^1#%XL29Ds z%u4-kf3qr*#B0Q$?9=9uq9zfjR0i+i5k&R@aAByTgCfv+lG; zN=Av%DU;8zLwk(4tQk($1yIT_+Y*myd;70}3rcJ#xv?CS%yGWl_xf+gM0}S^CA~OXbTnArMe*R?vx`y`Az)x3c$KYAGS=51}`_) zW?gx6u^SO*Nd9vxMrhs^rx^E?RJYfytQsvXIQBd0oqte<6L$3G-W>Dd-vw5-cs7#1 zqakE|?_?~8CXLdC51cXHu##dbTX;|h-+a5>h7@}F_cpY@gf{7%sX+7IT8h%hFcRXd z<`_hYc2QSxs^PCL_o;VXZeAc90cQsst7uu@vlS9tCoP>2+|TKTudAS>KQneZ>SN%3 zhq>YfL5(V4I`GuNiro__#A4`-5&83`Wq?;}8HE=U{of%f%j)G?LCDc*!t3heypo|9 zWw$qqlBkU2+G?Hqlyk$Y_fF)2>xlgmkz})H38woWv$;$0ge<$bU@+N?H62jAd3qbh z?B>^8J>IoYmrSj=Mb%}OmOD8M4d9wUEkm;_Z>RnJ&Mjj)W}y%6#e^w&*AT!9n;Jfg zwP7b;d27Z+;f#)-{CWSm<`27w-}(os6YUtYJE=zbu(^E@L1=s(<8=1NjX@`G+~`Or zU)JgVk}>N)b6`3|tqYSrxpMOQtjuEI+`B6<@{EyclU&)@nQiSIdGfL4Q5oAkrsjT znd4xGoOy4KH7l_?%Cv^H3ld*@Mp-8U_*^{g&fvpGY#^*f3B#EvpSc~Z1E-i>tFRqP z*N7Qy@&mv5li!}-D?c1m?KM`ZDXqU5!iWg!FS>m;orOtf$~Mn*h)NfI@2h4k5QDv? zz7#2g-hL_c`4E*ix|d?U_a|>@r`SB5QP!nDhUVFkS9@f5cXpESswF&DrZ^=(CiJ~r zpNB9{XXR4fwdT#@9J?T&>}erhVzV;vSuRH|N6? z%`+}4^BPmT;PS8T$i+Wl`6uU&&KOy>jSYysw-el;dO~r<`1wdT*y*~A@ZtJ^C_aVf zMe3hA+rmDqc6g==n!RKKoxAp`Qu<;DapMksWz8E9`k+OQkICg zaj`z)5^_wV@9F;Jtfj+4*ILG~&Cxz1y8HkyX9ld`*Dt2qZEfOCy}iN&N*}xRRsB~J zLsotEM=@rxd9Elp)6{GVs-}S}p4}t41NcoZetxm`enxdX&I`8Eq$-;_4#2Enbld>% zCnT7iolHmi@AeW!71xl3ayh?Sd^yVG3;j1;!)*~V%q721?1;y)VX#Ps1M){VBBw}K zHzk>YF>CS+RC~3}Ko&0N`f581zi=Z^Ts?@ZRq(^>zpnRDLvX6+>Gt;D;r^i2yyIdH zE>iYA#k}yu*QOob)InKZ__zbMdR(VKvu~padBQ@uD%Kj6o!q1HpxToE@UwqIGF?4n z&ozDGPVwPQB4ATtlGOmKgpkB8JS#yqsjBQ-8RZ>XF_0<_1;b@+cZI?dln3d#dCUc-kzr3aw!40wHR5q~X$Y$h79 zJNh^25Ec(&u(2-~h*(2%f&t;OlH|#Z=c)2 z1qG~Z0$SSeMy(y-%M?%NnaJVL#dUM+PIS3?@T*-&U8`H~!6&|;^AyC-5t;{M`9M+t zz{-BwT{A$iO0oH~xQIn}%|nr-_xPig0lVwmaDU4x5ISgNe2**NBL)2Y_QTLn!w~jI3BOFZ(8B!UB zEnW`CO04iAZ({P7a{=AP#L?}kJvlIzQw~V>0+j(IGUoKuUz8@~cJlxla1>fWS5bNJ zG!^R)Q<0R-zIHg8x4jJap$YozZPj!b{HZ}1Oa}Edj`bw zLr_(-SX<-(&|ed5auDpe0EWlfqMb`So(eKtuvJlqM$l+yl@7hz40dpNBd#^jk9tf6 z=Ac8yYhN?9%JI}?M-~bIHc$@3pPhFmKDUsoB(Jg;;qX z_M3d zZD9}+2=gb?s|A_&uX3re%41IK<-%a!W0CpXaGxFRO$YjxpW(lj$&qN+4c?#ry9eE& ztm!j6a-xQ7Egk)nNEN2{0e|;_TQ)D&jFBkek5Kb@H%*+M-!rO2n|HE*YYDFn;wj1C z!hs?_=kkKEt`;SR{)`^VFIhYDOl?ZT{0|gpgDWYyms_FAs{(l!A?pc(=6)lIx$;CG zVMMntXA{3mQ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp deleted file mode 100644 index 95c4b6e6637c36b6613a762b623f687d235fb2f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3108 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 diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp deleted file mode 100644 index 1dadd8d78b2f86c71f5bc4734ee71a239b45d696..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 897 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 LNkvXXu0mjfd~+vT diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp deleted file mode 100644 index 60c519d816a2d3b5ef4155cb405f9f255fab99d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5345 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 LYlf*pJ4gQ);``&l diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp deleted file mode 100644 index 5f09067779e27c5cf96f544d64274f80780eb3a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1545 zcmeAS@N?(olHy`uVBq!ia0y~yVB7%09Be?56MhC-3=FInJY5_^Dj44$+{oKtz`(r0 zWWGVkga6DA`#iRtFTStOV6cp_!I77NCyOB=fSI9Lib3KE!+`~C3~Z(h1}jFTMnhvX kZH#7z(ZXTSl!t!{rC81dcKtgFEaDkFUHx3vIVCg!0Mox-kpKVy diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp deleted file mode 100644 index eebcfe7fe3b126026e7d2dd28cf16c4d6010da79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8123 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 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.webp deleted file mode 100644 index eebcfe7fe3b126026e7d2dd28cf16c4d6010da79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8123 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 diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp deleted file mode 100644 index 84a79e444b25f788166c3631db06aaaa5a9f174f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6553 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 - #FFFFFF - #212529 - #023c69 - #ffffff - #ffd000 - \ No newline at end of file diff --git a/mobile/android/app/src/main/res/values/strings.xml b/mobile/android/app/src/main/res/values/strings.xml deleted file mode 100644 index 3583dc6..0000000 --- a/mobile/android/app/src/main/res/values/strings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - Skur - \ No newline at end of file diff --git a/mobile/android/app/src/main/res/values/styles.xml b/mobile/android/app/src/main/res/values/styles.xml deleted file mode 100644 index 1e7eb74..0000000 --- a/mobile/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/mobile/android/build.gradle b/mobile/android/build.gradle deleted file mode 100644 index 0554dd1..0000000 --- a/mobile/android/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - repositories { - google() - mavenCentral() - } - dependencies { - classpath('com.android.tools.build:gradle') - classpath('com.facebook.react:react-native-gradle-plugin') - classpath('org.jetbrains.kotlin:kotlin-gradle-plugin') - } -} - -allprojects { - repositories { - google() - mavenCentral() - maven { url 'https://www.jitpack.io' } - } -} - -apply plugin: "expo-root-project" -apply plugin: "com.facebook.react.rootproject" diff --git a/mobile/android/gradle.properties b/mobile/android/gradle.properties deleted file mode 100644 index cd98214..0000000 --- a/mobile/android/gradle.properties +++ /dev/null @@ -1,68 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -org.gradle.parallel=true - -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true - -# Enable AAPT2 PNG crunching -android.enablePngCrunchInReleaseBuilds=true - -# Use this property to specify which architecture you want to build. -# You can also override it from the CLI using -# ./gradlew -PreactNativeArchitectures=x86_64 -reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 - -# Use this property to enable support to the new architecture. -# This will allow you to use TurboModules and the Fabric render in -# your application. You should enable this flag either if you want -# to write custom TurboModules/Fabric components OR use libraries that -# are providing them. -newArchEnabled=true - -# Use this property to enable or disable the Hermes JS engine. -# If set to false, you will be using JSC instead. -hermesEnabled=true - -# Use this property to enable edge-to-edge display support. -# This allows your app to draw behind system bars for an immersive UI. -# Note: Only works with ReactActivity and should not be used with custom Activity. -edgeToEdgeEnabled=true - -# Enable GIF support in React Native images (~200 B increase) -expo.gif.enabled=true -# Enable webp support in React Native images (~85 KB increase) -expo.webp.enabled=true -# Enable animated webp support (~3.4 MB increase) -# Disabled by default because iOS doesn't support animated webp -expo.webp.animated=false - -# Enable network inspector -EX_DEV_CLIENT_NETWORK_INSPECTOR=true - -# Use legacy packaging to compress native libraries in the resulting APK. -expo.useLegacyPackaging=false - -expo.inlineModules.watchedDirectories=[] -# Local workaround for a slow/flaky network: give HTTP fetches room before failing. -systemProp.org.gradle.internal.http.connectionTimeout=120000 -systemProp.org.gradle.internal.http.socketTimeout=120000 -systemProp.sun.net.inetaddr.negative.ttl=0 -systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle.properties.bak2 b/mobile/android/gradle.properties.bak2 deleted file mode 100644 index 87f01ab..0000000 --- a/mobile/android/gradle.properties.bak2 +++ /dev/null @@ -1,68 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -org.gradle.parallel=true - -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true - -# Enable AAPT2 PNG crunching -android.enablePngCrunchInReleaseBuilds=true - -# Use this property to specify which architecture you want to build. -# You can also override it from the CLI using -# ./gradlew -PreactNativeArchitectures=x86_64 -reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 - -# Use this property to enable support to the new architecture. -# This will allow you to use TurboModules and the Fabric render in -# your application. You should enable this flag either if you want -# to write custom TurboModules/Fabric components OR use libraries that -# are providing them. -newArchEnabled=true - -# Use this property to enable or disable the Hermes JS engine. -# If set to false, you will be using JSC instead. -hermesEnabled=true - -# Use this property to enable edge-to-edge display support. -# This allows your app to draw behind system bars for an immersive UI. -# Note: Only works with ReactActivity and should not be used with custom Activity. -edgeToEdgeEnabled=true - -# Enable GIF support in React Native images (~200 B increase) -expo.gif.enabled=true -# Enable webp support in React Native images (~85 KB increase) -expo.webp.enabled=true -# Enable animated webp support (~3.4 MB increase) -# Disabled by default because iOS doesn't support animated webp -expo.webp.animated=false - -# Enable network inspector -EX_DEV_CLIENT_NETWORK_INSPECTOR=true - -# Use legacy packaging to compress native libraries in the resulting APK. -expo.useLegacyPackaging=false - -expo.inlineModules.watchedDirectories=[] -# Local workaround for a slow/flaky network: give HTTP fetches room before failing. -systemProp.org.gradle.internal.http.connectionTimeout=120000 -systemProp.org.gradle.internal.http.socketTimeout=120000 -systemProp.sun.net.inetaddr.negative.ttl=0 -systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle.properties.bak3 b/mobile/android/gradle.properties.bak3 deleted file mode 100644 index b6e3114..0000000 --- a/mobile/android/gradle.properties.bak3 +++ /dev/null @@ -1,68 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m -org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m --enable-native-access=ALL-UNNAMED --sun-misc-unsafe-memory-access=allow - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -org.gradle.parallel=true - -# AndroidX package structure to make it clearer which packages are bundled with the -# Android operating system, and which are packaged with your app's APK -# https://developer.android.com/topic/libraries/support-library/androidx-rn -android.useAndroidX=true - -# Enable AAPT2 PNG crunching -android.enablePngCrunchInReleaseBuilds=true - -# Use this property to specify which architecture you want to build. -# You can also override it from the CLI using -# ./gradlew -PreactNativeArchitectures=x86_64 -reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 - -# Use this property to enable support to the new architecture. -# This will allow you to use TurboModules and the Fabric render in -# your application. You should enable this flag either if you want -# to write custom TurboModules/Fabric components OR use libraries that -# are providing them. -newArchEnabled=true - -# Use this property to enable or disable the Hermes JS engine. -# If set to false, you will be using JSC instead. -hermesEnabled=true - -# Use this property to enable edge-to-edge display support. -# This allows your app to draw behind system bars for an immersive UI. -# Note: Only works with ReactActivity and should not be used with custom Activity. -edgeToEdgeEnabled=true - -# Enable GIF support in React Native images (~200 B increase) -expo.gif.enabled=true -# Enable webp support in React Native images (~85 KB increase) -expo.webp.enabled=true -# Enable animated webp support (~3.4 MB increase) -# Disabled by default because iOS doesn't support animated webp -expo.webp.animated=false - -# Enable network inspector -EX_DEV_CLIENT_NETWORK_INSPECTOR=true - -# Use legacy packaging to compress native libraries in the resulting APK. -expo.useLegacyPackaging=false - -expo.inlineModules.watchedDirectories=[] -# Local workaround for a slow/flaky network: give HTTP fetches room before failing. -systemProp.org.gradle.internal.http.connectionTimeout=120000 -systemProp.org.gradle.internal.http.socketTimeout=120000 -systemProp.sun.net.inetaddr.negative.ttl=0 -systemProp.sun.net.inetaddr.ttl=86400 diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.jar b/mobile/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 61285a659d17295f1de7c53e24fdf13ad755c379..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46175 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

      pVX@HRij*jw$g4?}Pn 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 diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.properties b/mobile/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index d9a9aec..0000000 --- a/mobile/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://github.com/gradle/gradle-distributions/releases/download/v9.3.1/gradle-9.3.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak b/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak deleted file mode 100644 index 37f78a6..0000000 --- a/mobile/android/gradle/wrapper/gradle-wrapper.properties.bak +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/mobile/android/gradlew b/mobile/android/gradlew deleted file mode 100755 index adff685..0000000 --- a/mobile/android/gradlew +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/mobile/android/gradlew.bat b/mobile/android/gradlew.bat deleted file mode 100644 index 39baf4d..0000000 --- a/mobile/android/gradlew.bat +++ /dev/null @@ -1,98 +0,0 @@ -@REM Copyright (c) Meta Platforms, Inc. and affiliates. -@REM -@REM This source code is licensed under the MIT license found in the -@REM LICENSE file in the root directory of this source tree. - -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/mobile/android/settings.gradle b/mobile/android/settings.gradle deleted file mode 100644 index a1d366e..0000000 --- a/mobile/android/settings.gradle +++ /dev/null @@ -1,39 +0,0 @@ -pluginManagement { - def reactNativeGradlePlugin = new File( - providers.exec { - workingDir(rootDir) - commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })") - }.standardOutput.asText.get().trim() - ).getParentFile().absolutePath - includeBuild(reactNativeGradlePlugin) - - def expoPluginsPath = new File( - providers.exec { - workingDir(rootDir) - commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })") - }.standardOutput.asText.get().trim(), - "../android/expo-gradle-plugin" - ).absolutePath - includeBuild(expoPluginsPath) -} - -plugins { - id("com.facebook.react.settings") - id("expo-autolinking-settings") -} - -extensions.configure(com.facebook.react.ReactSettingsExtension) { ex -> - if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') { - ex.autolinkLibrariesFromCommand() - } else { - ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand) - } -} -expoAutolinking.useExpoModules() - -rootProject.name = 'Skur' - -expoAutolinking.useExpoVersionCatalog() - -include ':app' -includeBuild(expoAutolinking.reactNativeGradlePlugin) diff --git a/mobile/ios/.gitignore b/mobile/ios/.gitignore deleted file mode 100644 index 8beb344..0000000 --- a/mobile/ios/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -# OSX -# -.DS_Store - -# Xcode -# -build/ -*.pbxuser -!default.pbxuser -*.mode1v3 -!default.mode1v3 -*.mode2v3 -!default.mode2v3 -*.perspectivev3 -!default.perspectivev3 -xcuserdata -*.xccheckout -*.moved-aside -DerivedData -*.hmap -*.ipa -*.xcuserstate -project.xcworkspace -.xcode.env.local - -# Bundle artifacts -*.jsbundle - -# CocoaPods -/Pods/ diff --git a/mobile/ios/.xcode.env b/mobile/ios/.xcode.env deleted file mode 100644 index 3d5782c..0000000 --- a/mobile/ios/.xcode.env +++ /dev/null @@ -1,11 +0,0 @@ -# This `.xcode.env` file is versioned and is used to source the environment -# used when running script phases inside Xcode. -# To customize your local environment, you can create an `.xcode.env.local` -# file that is not versioned. - -# NODE_BINARY variable contains the PATH to the node executable. -# -# Customize the NODE_BINARY variable here. -# For example, to use nvm with brew, add the following line -# . "$(brew --prefix nvm)/nvm.sh" --no-use -export NODE_BINARY=$(command -v node) diff --git a/mobile/ios/Podfile b/mobile/ios/Podfile deleted file mode 100644 index be3a8ab..0000000 --- a/mobile/ios/Podfile +++ /dev/null @@ -1,67 +0,0 @@ -require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking") -require File.join(File.dirname(`node --print "require.resolve('react-native/package.json')"`), "scripts/react_native_pods") - -require 'json' -podfile_properties = JSON.parse(File.read(File.join(__dir__, 'Podfile.properties.json'))) rescue {} - -def ccache_enabled?(podfile_properties) - # Environment variable takes precedence - return ENV['USE_CCACHE'] == '1' if ENV['USE_CCACHE'] - - # Fall back to Podfile properties - podfile_properties['apple.ccacheEnabled'] == 'true' -end - -ENV['EX_DEV_CLIENT_NETWORK_INSPECTOR'] ||= podfile_properties['EX_DEV_CLIENT_NETWORK_INSPECTOR'] -ENV['RCT_USE_RN_DEP'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' -ENV['RCT_USE_PREBUILT_RNCORE'] ||= podfile_properties['ios.buildReactNativeFromSource'] == 'true' ? '0' : '1' -ENV['RCT_HERMES_V1_ENABLED'] ||= '0' if podfile_properties['expo.useHermesV1'] == 'false' -# An explicit `ios.usePrecompiledModules: false` must win even when the env var is already set -# (e.g. EXPO_USE_PRECOMPILED_MODULES exported by EAS Build), so force-disable here before the default. -ENV['EXPO_USE_PRECOMPILED_MODULES'] = '0' if podfile_properties['EXPO_USE_PRECOMPILED_MODULES'] == 'false' -ENV['EXPO_USE_PRECOMPILED_MODULES'] ||= '1' -platform :ios, podfile_properties['ios.deploymentTarget'] || '16.4' - -prepare_react_native_project! - -target 'Skur' do - use_expo_modules! - - if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1' - config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"]; - else - config_command = [ - 'node', - '--no-warnings', - '--eval', - 'require(\'expo/bin/autolinking\')', - 'expo-modules-autolinking', - 'react-native-config', - '--json', - '--platform', - 'ios' - ] - end - - config = use_native_modules!(config_command) - - use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] - use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS'] - - use_react_native!( - :path => config[:reactNativePath], - :hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes', - # An absolute path to your application root. - :app_path => "#{Pod::Config.instance.installation_root}/..", - :privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false', - ) - - post_install do |installer| - react_native_post_install( - installer, - config[:reactNativePath], - :mac_catalyst_enabled => false, - :ccache_enabled => ccache_enabled?(podfile_properties), - ) - end -end diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock deleted file mode 100644 index d03c2ae..0000000 --- a/mobile/ios/Podfile.lock +++ /dev/null @@ -1,2472 +0,0 @@ -PODS: - - EXApplication (57.0.3): - - ExpoModulesCore - - EXConstants (57.0.18): - - ExpoModulesCore - - Expo (57.0.23): - - ExpoModulesCore - - ExpoModulesJSI - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTAppDelegate - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactAppDependencyProvider - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - ExpoAsset (57.0.17): - - ExpoModulesCore - - ExpoCamera (57.0.5): - - ExpoModulesCore - - ExpoCameraBarcodeScanning (57.0.5): - - ExpoCamera - - ZXingObjC/OneD - - ZXingObjC/PDF417 - - ExpoClipboard (57.0.2): - - ExpoModulesCore - - ExpoDomWebView (57.0.1): - - ExpoModulesCore - - ExpoFileSystem (57.0.7): - - ExpoModulesCore - - ExpoFont (57.0.4): - - ExpoModulesCore - - ExpoKeepAwake (57.0.2): - - ExpoModulesCore - - ExpoLinking (57.0.10): - - ExpoModulesCore - - ExpoLocalAuthentication (57.0.3): - - ExpoModulesCore - - ExpoLogBox (57.0.4): - - React-Core - - ExpoModulesCore (57.0.18): - - ExpoModulesJSI - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-jsinspector - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - ExpoModulesJSI (57.1.0): - - React-Core - - ReactCommon - - ExpoModulesWorklets (57.0.18): - - ExpoModulesCore - - ExpoModulesJSI - - ExpoNotifications (57.0.19): - - ExpoModulesCore - - ExpoSecureStore (57.0.4): - - ExpoModulesCore - - FBLazyVector (0.86.3) - - hermes-engine (250829098.0.17): - - hermes-engine/cdp (= 250829098.0.17) - - hermes-engine/Hermes (= 250829098.0.17) - - hermes-engine/Public (= 250829098.0.17) - - hermes-engine/cdp (250829098.0.17) - - hermes-engine/Hermes (250829098.0.17) - - hermes-engine/Public (250829098.0.17) - - RCTDeprecation (0.86.3) - - RCTRequired (0.86.3) - - RCTSwiftUI (0.86.3) - - RCTSwiftUIWrapper (0.86.3): - - RCTSwiftUI - - RCTTypeSafety (0.86.3): - - FBLazyVector (= 0.86.3) - - RCTRequired (= 0.86.3) - - React-Core (= 0.86.3) - - React (0.86.3): - - React-Core (= 0.86.3) - - React-Core/DevSupport (= 0.86.3) - - React-Core/RCTWebSocket (= 0.86.3) - - React-RCTActionSheet (= 0.86.3) - - React-RCTAnimation (= 0.86.3) - - React-RCTBlob (= 0.86.3) - - React-RCTImage (= 0.86.3) - - React-RCTLinking (= 0.86.3) - - React-RCTNetwork (= 0.86.3) - - React-RCTSettings (= 0.86.3) - - React-RCTText (= 0.86.3) - - React-RCTVibration (= 0.86.3) - - React-callinvoker (0.86.3) - - React-Core (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default (= 0.86.3) - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core-prebuilt (0.86.3): - - ReactNativeDependencies - - React-Core/CoreModulesHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/Default (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/DevSupport (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default (= 0.86.3) - - React-Core/RCTWebSocket (= 0.86.3) - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTActionSheetHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTAnimationHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTBlobHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTImageHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTLinkingHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTNetworkHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTSettingsHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTTextHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTVibrationHeaders (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-Core/RCTWebSocket (0.86.3): - - hermes-engine - - RCTDeprecation - - React-Core-prebuilt - - React-Core/Default (= 0.86.3) - - React-cxxreact - - React-featureflags - - React-hermes - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsinspectorcdp - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-CoreModules (0.86.3): - - RCTTypeSafety (= 0.86.3) - - React-Core-prebuilt - - React-Core/CoreModulesHeaders (= 0.86.3) - - React-debug - - React-featureflags - - React-jsi (= 0.86.3) - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-NativeModulesApple - - React-RCTBlob - - React-RCTFBReactNativeSpec - - React-RCTImage (= 0.86.3) - - React-runtimeexecutor - - React-utils - - ReactCommon - - ReactNativeDependencies - - React-cxxreact (0.86.3): - - hermes-engine - - React-callinvoker (= 0.86.3) - - React-Core-prebuilt - - React-debug (= 0.86.3) - - React-jsi (= 0.86.3) - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-logger (= 0.86.3) - - React-perflogger (= 0.86.3) - - React-runtimeexecutor - - React-timing (= 0.86.3) - - React-utils - - ReactNativeDependencies - - React-debug (0.86.3): - - React-debug/redbox (= 0.86.3) - - React-debug/redbox (0.86.3) - - React-defaultsnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-domnativemodule - - React-Fabric/animated - - React-featureflags - - React-featureflagsnativemodule - - React-idlecallbacksnativemodule - - React-intersectionobservernativemodule - - React-jsi - - React-jsiexecutor - - React-microtasksnativemodule - - React-mutationobservernativemodule - - React-RCTFBReactNativeSpec - - React-viewtransitionnativemodule - - React-webperformancenativemodule - - ReactNativeDependencies - - Yoga - - React-domnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-Fabric - - React-Fabric/bridging - - React-FabricComponents - - React-graphics - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-Fabric (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/animated (= 0.86.3) - - React-Fabric/animationbackend (= 0.86.3) - - React-Fabric/animations (= 0.86.3) - - React-Fabric/attributedstring (= 0.86.3) - - React-Fabric/bridging (= 0.86.3) - - React-Fabric/componentregistry (= 0.86.3) - - React-Fabric/componentregistrynative (= 0.86.3) - - React-Fabric/components (= 0.86.3) - - React-Fabric/consistency (= 0.86.3) - - React-Fabric/core (= 0.86.3) - - React-Fabric/dom (= 0.86.3) - - React-Fabric/imagemanager (= 0.86.3) - - React-Fabric/leakchecker (= 0.86.3) - - React-Fabric/mounting (= 0.86.3) - - React-Fabric/observers (= 0.86.3) - - React-Fabric/scheduler (= 0.86.3) - - React-Fabric/telemetry (= 0.86.3) - - React-Fabric/uimanager (= 0.86.3) - - React-Fabric/viewtransition (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/animated (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/animationbackend - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/animationbackend (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/animations (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/attributedstring (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/bridging (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/componentregistry (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/componentregistrynative (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/components (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/components/legacyviewmanagerinterop (= 0.86.3) - - React-Fabric/components/root (= 0.86.3) - - React-Fabric/components/scrollview (= 0.86.3) - - React-Fabric/components/view (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/components/legacyviewmanagerinterop (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/components/root (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/components/scrollview (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/components/view (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-renderercss - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-Fabric/consistency (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/core (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/dom (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/imagemanager (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/leakchecker (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/mounting (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-jsinspectortracing - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/observers (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/observers/events (= 0.86.3) - - React-Fabric/observers/intersection (= 0.86.3) - - React-Fabric/observers/mutation (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/observers/events (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/observers/intersection (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/observers/mutation (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/scheduler (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/animationbackend - - React-Fabric/observers/events - - React-Fabric/viewtransition - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-performancecdpmetrics - - React-performancetimeline - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/telemetry (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/uimanager (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric/uimanager/consistency (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererconsistency - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/uimanager/consistency (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererconsistency - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-Fabric/viewtransition (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-FabricComponents (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-FabricComponents/components (= 0.86.3) - - React-FabricComponents/textlayoutmanager (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-FabricComponents/components/inputaccessory (= 0.86.3) - - React-FabricComponents/components/iostextinput (= 0.86.3) - - React-FabricComponents/components/modal (= 0.86.3) - - React-FabricComponents/components/rncore (= 0.86.3) - - React-FabricComponents/components/safeareaview (= 0.86.3) - - React-FabricComponents/components/scrollview (= 0.86.3) - - React-FabricComponents/components/switch (= 0.86.3) - - React-FabricComponents/components/text (= 0.86.3) - - React-FabricComponents/components/textinput (= 0.86.3) - - React-FabricComponents/components/unimplementedview (= 0.86.3) - - React-FabricComponents/components/virtualview (= 0.86.3) - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/inputaccessory (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/iostextinput (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/modal (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/rncore (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/safeareaview (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/scrollview (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/switch (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/text (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/textinput (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/unimplementedview (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/components/virtualview (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricComponents/textlayoutmanager (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-logger - - React-RCTFBReactNativeSpec - - React-rendererdebug - - React-runtimescheduler - - React-utils - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-FabricImage (0.86.3): - - hermes-engine - - RCTRequired (= 0.86.3) - - RCTTypeSafety (= 0.86.3) - - React-Core-prebuilt - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-jsiexecutor (= 0.86.3) - - React-logger - - React-rendererdebug - - React-utils - - ReactCommon - - ReactNativeDependencies - - Yoga - - React-featureflags (0.86.3): - - React-Core-prebuilt - - ReactNativeDependencies - - React-featureflagsnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-featureflags - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-graphics (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-featureflags - - React-jsi - - React-jsiexecutor - - React-rendererdebug - - React-utils - - ReactNativeDependencies - - React-hermes (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact (= 0.86.3) - - React-jsi - - React-jsiexecutor (= 0.86.3) - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-jsitooling - - React-oscompat - - React-perflogger (= 0.86.3) - - React-runtimeexecutor - - ReactNativeDependencies - - React-idlecallbacksnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - React-runtimescheduler - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-ImageManager (0.86.3): - - React-Core-prebuilt - - React-Core/Default - - React-debug - - React-Fabric - - React-graphics - - React-rendererdebug - - React-utils - - ReactNativeDependencies - - React-intersectionobservernativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-Fabric - - React-Fabric/bridging - - React-graphics - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - React-runtimescheduler - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-jserrorhandler (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-jsi - - ReactCommon/turbomodule/bridging - - ReactNativeDependencies - - React-jsi (0.86.3): - - hermes-engine - - React-Core-prebuilt - - ReactNativeDependencies - - React-jsiexecutor (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-jserrorhandler - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-jsitooling - - React-perflogger - - React-runtimeexecutor - - React-utils - - ReactNativeDependencies - - React-jsinspector (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-featureflags - - React-jsi - - React-jsinspectorcdp - - React-jsinspectornetwork - - React-jsinspectortracing - - React-oscompat - - React-perflogger (= 0.86.3) - - React-runtimeexecutor - - React-utils - - ReactNativeDependencies - - React-jsinspectorcdp (0.86.3): - - React-Core-prebuilt - - ReactNativeDependencies - - React-jsinspectornetwork (0.86.3): - - React-Core-prebuilt - - React-jsinspectorcdp - - ReactNativeDependencies - - React-jsinspectortracing (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-jsi - - React-jsinspectornetwork - - React-oscompat - - React-timing - - React-utils - - ReactNativeDependencies - - React-jsitooling (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact (= 0.86.3) - - React-debug - - React-jsi (= 0.86.3) - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-runtimeexecutor - - React-utils - - ReactNativeDependencies - - React-jsitracing (0.86.3): - - React-jsi - - React-logger (0.86.3): - - React-Core-prebuilt - - ReactNativeDependencies - - React-Mapbuffer (0.86.3): - - React-Core-prebuilt - - React-debug - - ReactNativeDependencies - - React-microtasksnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-mutationobservernativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-Fabric - - React-Fabric/bridging - - React-Fabric/observers/mutation - - React-featureflags - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - react-native-get-random-values (1.11.0): - - React-Core - - react-native-safe-area-context (5.7.0): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - react-native-safe-area-context/common (= 5.7.0) - - react-native-safe-area-context/fabric (= 5.7.0) - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - react-native-safe-area-context/common (5.7.0): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - react-native-safe-area-context/fabric (5.7.0): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - react-native-safe-area-context/common - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-NativeModulesApple (0.86.3): - - hermes-engine - - React-callinvoker - - React-Core - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-runtimeexecutor - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - React-networking (0.86.3): - - React-Core-prebuilt - - React-jsinspectornetwork - - React-jsinspectortracing - - React-performancetimeline - - React-timing - - ReactNativeDependencies - - React-oscompat (0.86.3) - - React-perflogger (0.86.3): - - React-Core-prebuilt - - ReactNativeDependencies - - React-performancecdpmetrics (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-jsi - - React-performancetimeline - - React-runtimeexecutor - - React-timing - - ReactNativeDependencies - - React-performancetimeline (0.86.3): - - React-Core-prebuilt - - React-featureflags - - React-jsinspector - - React-jsinspectortracing - - React-perflogger - - React-timing - - ReactNativeDependencies - - React-RCTActionSheet (0.86.3): - - React-Core/RCTActionSheetHeaders (= 0.86.3) - - React-RCTAnimation (0.86.3): - - RCTTypeSafety - - React-Core-prebuilt - - React-Core/RCTAnimationHeaders - - React-debug - - React-featureflags - - React-jsi - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - ReactCommon - - ReactNativeDependencies - - React-RCTAppDelegate (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-CoreModules - - React-debug - - React-defaultsnativemodule - - React-Fabric - - React-featureflags - - React-graphics - - React-hermes - - React-jsitooling - - React-NativeModulesApple - - React-RCTFabric - - React-RCTFBReactNativeSpec - - React-RCTImage - - React-RCTNetwork - - React-RCTRuntime - - React-rendererdebug - - React-RuntimeApple - - React-RuntimeCore - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactCommon - - ReactNativeDependencies - - React-RCTBlob (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-Core/RCTBlobHeaders - - React-Core/RCTWebSocket - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - React-RCTNetwork - - ReactCommon - - ReactNativeDependencies - - React-RCTFabric (0.86.3): - - hermes-engine - - RCTSwiftUIWrapper - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-FabricComponents - - React-FabricImage - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-networking - - React-performancecdpmetrics - - React-performancetimeline - - React-RCTAnimation - - React-RCTFBReactNativeSpec - - React-RCTImage - - React-RCTText - - React-rendererconsistency - - React-renderercss - - React-rendererdebug - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - Yoga - - React-RCTFBReactNativeSpec (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-jsi - - React-NativeModulesApple - - React-RCTFBReactNativeSpec/components (= 0.86.3) - - ReactCommon - - ReactNativeDependencies - - React-RCTFBReactNativeSpec/components (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-jsi - - React-NativeModulesApple - - React-rendererdebug - - React-utils - - ReactCommon - - ReactNativeDependencies - - Yoga - - React-RCTImage (0.86.3): - - RCTTypeSafety - - React-Core-prebuilt - - React-Core/RCTImageHeaders - - React-jsi - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - React-RCTNetwork - - ReactCommon - - ReactNativeDependencies - - React-RCTLinking (0.86.3): - - React-Core/RCTLinkingHeaders (= 0.86.3) - - React-jsi (= 0.86.3) - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - ReactCommon - - ReactCommon/turbomodule/core (= 0.86.3) - - React-RCTNetwork (0.86.3): - - RCTTypeSafety - - React-Core-prebuilt - - React-Core/RCTNetworkHeaders - - React-debug - - React-featureflags - - React-jsi - - React-jsinspectorcdp - - React-jsinspectornetwork - - React-NativeModulesApple - - React-networking - - React-RCTFBReactNativeSpec - - ReactCommon - - ReactNativeDependencies - - React-RCTRuntime (0.86.3): - - hermes-engine - - React-Core - - React-Core-prebuilt - - React-debug - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-jsitooling - - React-RuntimeApple - - React-RuntimeCore - - React-runtimeexecutor - - React-RuntimeHermes - - React-utils - - ReactNativeDependencies - - React-RCTSettings (0.86.3): - - RCTTypeSafety - - React-Core-prebuilt - - React-Core/RCTSettingsHeaders - - React-jsi - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - ReactCommon - - ReactNativeDependencies - - React-RCTText (0.86.3): - - React-Core/RCTTextHeaders (= 0.86.3) - - Yoga - - React-RCTVibration (0.86.3): - - React-Core-prebuilt - - React-Core/RCTVibrationHeaders - - React-jsi - - React-NativeModulesApple - - React-RCTFBReactNativeSpec - - ReactCommon - - ReactNativeDependencies - - React-rendererconsistency (0.86.3) - - React-renderercss (0.86.3): - - React-debug - - React-utils - - React-rendererdebug (0.86.3): - - React-Core-prebuilt - - React-debug - - ReactNativeDependencies - - React-RuntimeApple (0.86.3): - - hermes-engine - - React-callinvoker - - React-Core-prebuilt - - React-Core/Default - - React-CoreModules - - React-cxxreact - - React-featureflags - - React-jserrorhandler - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsitooling - - React-Mapbuffer - - React-NativeModulesApple - - React-RCTFabric - - React-RCTFBReactNativeSpec - - React-RuntimeCore - - React-runtimeexecutor - - React-RuntimeHermes - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - React-RuntimeCore (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-Fabric - - React-featureflags - - React-jserrorhandler - - React-jsi - - React-jsiexecutor - - React-jsinspector - - React-jsitooling - - React-performancetimeline - - React-runtimeexecutor - - React-runtimescheduler - - React-utils - - ReactNativeDependencies - - React-runtimeexecutor (0.86.3): - - React-Core-prebuilt - - React-debug - - React-featureflags - - React-jsi (= 0.86.3) - - React-utils - - ReactNativeDependencies - - React-RuntimeHermes (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-featureflags - - React-hermes - - React-jsi - - React-jsinspector - - React-jsinspectorcdp - - React-jsinspectortracing - - React-jsitooling - - React-jsitracing - - React-RuntimeCore - - React-runtimeexecutor - - React-utils - - ReactNativeDependencies - - React-runtimescheduler (0.86.3): - - hermes-engine - - React-callinvoker - - React-Core-prebuilt - - React-cxxreact - - React-debug - - React-featureflags - - React-jsi - - React-jsinspectortracing - - React-performancetimeline - - React-rendererconsistency - - React-rendererdebug - - React-runtimeexecutor - - React-timing - - React-utils - - ReactNativeDependencies - - React-timing (0.86.3): - - React-debug - - React-utils (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-debug - - React-jsi (= 0.86.3) - - ReactNativeDependencies - - React-viewtransitionnativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-Fabric - - React-Fabric/bridging - - React-jsi - - React-jsiexecutor - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - React-webperformancenativemodule (0.86.3): - - hermes-engine - - React-Core-prebuilt - - React-cxxreact - - React-jsi - - React-jsiexecutor - - React-performancetimeline - - React-RCTFBReactNativeSpec - - React-runtimeexecutor - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - ReactAppDependencyProvider (0.86.3): - - ReactCodegen - - ReactCodegen (0.86.3): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-FabricImage - - React-featureflags - - React-graphics - - React-jsi - - React-jsiexecutor - - React-NativeModulesApple - - React-RCTAppDelegate - - React-rendererdebug - - React-utils - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - ReactCommon (0.86.3): - - React-Core-prebuilt - - ReactCommon/turbomodule (= 0.86.3) - - ReactNativeDependencies - - ReactCommon/turbomodule (0.86.3): - - hermes-engine - - React-callinvoker (= 0.86.3) - - React-Core-prebuilt - - React-cxxreact (= 0.86.3) - - React-jsi (= 0.86.3) - - React-logger (= 0.86.3) - - React-perflogger (= 0.86.3) - - ReactCommon/turbomodule/bridging (= 0.86.3) - - ReactCommon/turbomodule/core (= 0.86.3) - - ReactNativeDependencies - - ReactCommon/turbomodule/bridging (0.86.3): - - hermes-engine - - React-callinvoker (= 0.86.3) - - React-Core-prebuilt - - React-cxxreact (= 0.86.3) - - React-jsi (= 0.86.3) - - React-logger (= 0.86.3) - - React-perflogger (= 0.86.3) - - ReactNativeDependencies - - ReactCommon/turbomodule/core (0.86.3): - - hermes-engine - - React-callinvoker (= 0.86.3) - - React-Core-prebuilt - - React-cxxreact (= 0.86.3) - - React-debug (= 0.86.3) - - React-featureflags (= 0.86.3) - - React-jsi (= 0.86.3) - - React-logger (= 0.86.3) - - React-perflogger (= 0.86.3) - - React-utils (= 0.86.3) - - ReactNativeDependencies - - ReactNativeDependencies (0.86.3) - - RNCAsyncStorage (2.2.0): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - RNScreens (4.26.2): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-RCTImage - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - RNScreens/common (= 4.26.2) - - Yoga - - RNScreens/common (4.26.2): - - hermes-engine - - RCTRequired - - RCTTypeSafety - - React-Core - - React-Core-prebuilt - - React-debug - - React-Fabric - - React-featureflags - - React-graphics - - React-ImageManager - - React-jsi - - React-NativeModulesApple - - React-RCTFabric - - React-RCTImage - - React-renderercss - - React-rendererdebug - - React-utils - - ReactCodegen - - ReactCommon/turbomodule/bridging - - ReactCommon/turbomodule/core - - ReactNativeDependencies - - Yoga - - Yoga (0.0.0) - - ZXingObjC/Core (3.6.9) - - ZXingObjC/OneD (3.6.9): - - ZXingObjC/Core - - ZXingObjC/PDF417 (3.6.9): - - ZXingObjC/Core - -DEPENDENCIES: - - EXApplication (from `../node_modules/expo-application/ios`) - - EXConstants (from `../node_modules/expo-constants/ios`) - - Expo (from `../node_modules/expo`) - - ExpoAsset (from `../node_modules/expo/node_modules/expo-asset/ios`) - - ExpoCamera (from `../node_modules/expo-camera/ios`) - - ExpoCameraBarcodeScanning (from `../node_modules/expo-camera/ios`) - - ExpoClipboard (from `../node_modules/expo-clipboard/ios`) - - "ExpoDomWebView (from `../node_modules/expo/node_modules/@expo/dom-webview/ios`)" - - ExpoFileSystem (from `../node_modules/expo/node_modules/expo-file-system/ios`) - - ExpoFont (from `../node_modules/expo-font/ios`) - - ExpoKeepAwake (from `../node_modules/expo/node_modules/expo-keep-awake/ios`) - - ExpoLinking (from `../node_modules/expo-linking/ios`) - - ExpoLocalAuthentication (from `../node_modules/expo-local-authentication/ios`) - - "ExpoLogBox (from `../node_modules/expo/node_modules/@expo/log-box`)" - - ExpoModulesCore (from `../node_modules/expo-modules-core`) - - ExpoModulesJSI (from `../node_modules/expo-modules-jsi/apple`) - - ExpoModulesWorklets (from `../node_modules/expo-modules-core`) - - ExpoNotifications (from `../node_modules/expo-notifications/ios`) - - ExpoSecureStore (from `../node_modules/expo-secure-store/ios`) - - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - - RCTDeprecation (from `../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation`) - - RCTRequired (from `../node_modules/react-native/Libraries/Required`) - - RCTSwiftUI (from `../node_modules/react-native/ReactApple/RCTSwiftUI`) - - RCTSwiftUIWrapper (from `../node_modules/react-native/ReactApple/RCTSwiftUIWrapper`) - - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) - - React (from `../node_modules/react-native/`) - - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - - React-Core (from `../node_modules/react-native/`) - - React-Core-prebuilt (from `../node_modules/react-native/React-Core-prebuilt.podspec`) - - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) - - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) - - React-defaultsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/defaults`) - - React-domnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/dom`) - - React-Fabric (from `../node_modules/react-native/ReactCommon`) - - React-FabricComponents (from `../node_modules/react-native/ReactCommon`) - - React-FabricImage (from `../node_modules/react-native/ReactCommon`) - - React-featureflags (from `../node_modules/react-native/ReactCommon/react/featureflags`) - - React-featureflagsnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/featureflags`) - - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) - - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) - - React-idlecallbacksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks`) - - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) - - React-intersectionobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver`) - - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) - - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) - - React-jsinspectorcdp (from `../node_modules/react-native/ReactCommon/jsinspector-modern/cdp`) - - React-jsinspectornetwork (from `../node_modules/react-native/ReactCommon/jsinspector-modern/network`) - - React-jsinspectortracing (from `../node_modules/react-native/ReactCommon/jsinspector-modern/tracing`) - - React-jsitooling (from `../node_modules/react-native/ReactCommon/jsitooling`) - - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) - - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - - React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`) - - React-mutationobservernativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver`) - - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - - React-networking (from `../node_modules/react-native/ReactCommon/react/networking`) - - React-oscompat (from `../node_modules/react-native/ReactCommon/oscompat`) - - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - - React-performancecdpmetrics (from `../node_modules/react-native/ReactCommon/react/performance/cdpmetrics`) - - React-performancetimeline (from `../node_modules/react-native/ReactCommon/react/performance/timeline`) - - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) - - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) - - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) - - React-RCTFabric (from `../node_modules/react-native/React`) - - React-RCTFBReactNativeSpec (from `../node_modules/react-native/React`) - - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) - - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) - - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) - - React-RCTRuntime (from `../node_modules/react-native/React/Runtime`) - - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - - React-rendererconsistency (from `../node_modules/react-native/ReactCommon/react/renderer/consistency`) - - React-renderercss (from `../node_modules/react-native/ReactCommon/react/renderer/css`) - - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) - - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) - - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) - - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) - - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) - - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - - React-timing (from `../node_modules/react-native/ReactCommon/react/timing`) - - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - - React-viewtransitionnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition`) - - React-webperformancenativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/webperformance`) - - ReactAppDependencyProvider (from `build/generated/ios/ReactAppDependencyProvider`) - - ReactCodegen (from `build/generated/ios/ReactCodegen`) - - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - - ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`) - - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - - RNScreens (from `../node_modules/react-native-screens`) - - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) - -SPEC REPOS: - trunk: - - ZXingObjC - -EXTERNAL SOURCES: - EXApplication: - :path: "../node_modules/expo-application/ios" - EXConstants: - :path: "../node_modules/expo-constants/ios" - Expo: - :path: "../node_modules/expo" - ExpoAsset: - :path: "../node_modules/expo/node_modules/expo-asset/ios" - ExpoCamera: - :path: "../node_modules/expo-camera/ios" - ExpoCameraBarcodeScanning: - :path: "../node_modules/expo-camera/ios" - ExpoClipboard: - :path: "../node_modules/expo-clipboard/ios" - ExpoDomWebView: - :path: "../node_modules/expo/node_modules/@expo/dom-webview/ios" - ExpoFileSystem: - :path: "../node_modules/expo/node_modules/expo-file-system/ios" - ExpoFont: - :path: "../node_modules/expo-font/ios" - ExpoKeepAwake: - :path: "../node_modules/expo/node_modules/expo-keep-awake/ios" - ExpoLinking: - :path: "../node_modules/expo-linking/ios" - ExpoLocalAuthentication: - :path: "../node_modules/expo-local-authentication/ios" - ExpoLogBox: - :path: "../node_modules/expo/node_modules/@expo/log-box" - ExpoModulesCore: - :path: "../node_modules/expo-modules-core" - ExpoModulesJSI: - :path: "../node_modules/expo-modules-jsi/apple" - ExpoModulesWorklets: - :path: "../node_modules/expo-modules-core" - ExpoNotifications: - :path: "../node_modules/expo-notifications/ios" - ExpoSecureStore: - :path: "../node_modules/expo-secure-store/ios" - FBLazyVector: - :path: "../node_modules/react-native/Libraries/FBLazyVector" - hermes-engine: - :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" - :tag: hermes-v250829098.0.17 - RCTDeprecation: - :path: "../node_modules/react-native/ReactApple/Libraries/RCTFoundation/RCTDeprecation" - RCTRequired: - :path: "../node_modules/react-native/Libraries/Required" - RCTSwiftUI: - :path: "../node_modules/react-native/ReactApple/RCTSwiftUI" - RCTSwiftUIWrapper: - :path: "../node_modules/react-native/ReactApple/RCTSwiftUIWrapper" - RCTTypeSafety: - :path: "../node_modules/react-native/Libraries/TypeSafety" - React: - :path: "../node_modules/react-native/" - React-callinvoker: - :path: "../node_modules/react-native/ReactCommon/callinvoker" - React-Core: - :path: "../node_modules/react-native/" - React-Core-prebuilt: - :podspec: "../node_modules/react-native/React-Core-prebuilt.podspec" - React-CoreModules: - :path: "../node_modules/react-native/React/CoreModules" - React-cxxreact: - :path: "../node_modules/react-native/ReactCommon/cxxreact" - React-debug: - :path: "../node_modules/react-native/ReactCommon/react/debug" - React-defaultsnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/defaults" - React-domnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/dom" - React-Fabric: - :path: "../node_modules/react-native/ReactCommon" - React-FabricComponents: - :path: "../node_modules/react-native/ReactCommon" - React-FabricImage: - :path: "../node_modules/react-native/ReactCommon" - React-featureflags: - :path: "../node_modules/react-native/ReactCommon/react/featureflags" - React-featureflagsnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/featureflags" - React-graphics: - :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" - React-hermes: - :path: "../node_modules/react-native/ReactCommon/hermes" - React-idlecallbacksnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/idlecallbacks" - React-ImageManager: - :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" - React-intersectionobservernativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/intersectionobserver" - React-jserrorhandler: - :path: "../node_modules/react-native/ReactCommon/jserrorhandler" - React-jsi: - :path: "../node_modules/react-native/ReactCommon/jsi" - React-jsiexecutor: - :path: "../node_modules/react-native/ReactCommon/jsiexecutor" - React-jsinspector: - :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" - React-jsinspectorcdp: - :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/cdp" - React-jsinspectornetwork: - :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/network" - React-jsinspectortracing: - :path: "../node_modules/react-native/ReactCommon/jsinspector-modern/tracing" - React-jsitooling: - :path: "../node_modules/react-native/ReactCommon/jsitooling" - React-jsitracing: - :path: "../node_modules/react-native/ReactCommon/hermes/executor/" - React-logger: - :path: "../node_modules/react-native/ReactCommon/logger" - React-Mapbuffer: - :path: "../node_modules/react-native/ReactCommon" - React-microtasksnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/microtasks" - React-mutationobservernativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver" - react-native-get-random-values: - :path: "../node_modules/react-native-get-random-values" - react-native-safe-area-context: - :path: "../node_modules/react-native-safe-area-context" - React-NativeModulesApple: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" - React-networking: - :path: "../node_modules/react-native/ReactCommon/react/networking" - React-oscompat: - :path: "../node_modules/react-native/ReactCommon/oscompat" - React-perflogger: - :path: "../node_modules/react-native/ReactCommon/reactperflogger" - React-performancecdpmetrics: - :path: "../node_modules/react-native/ReactCommon/react/performance/cdpmetrics" - React-performancetimeline: - :path: "../node_modules/react-native/ReactCommon/react/performance/timeline" - React-RCTActionSheet: - :path: "../node_modules/react-native/Libraries/ActionSheetIOS" - React-RCTAnimation: - :path: "../node_modules/react-native/Libraries/NativeAnimation" - React-RCTAppDelegate: - :path: "../node_modules/react-native/Libraries/AppDelegate" - React-RCTBlob: - :path: "../node_modules/react-native/Libraries/Blob" - React-RCTFabric: - :path: "../node_modules/react-native/React" - React-RCTFBReactNativeSpec: - :path: "../node_modules/react-native/React" - React-RCTImage: - :path: "../node_modules/react-native/Libraries/Image" - React-RCTLinking: - :path: "../node_modules/react-native/Libraries/LinkingIOS" - React-RCTNetwork: - :path: "../node_modules/react-native/Libraries/Network" - React-RCTRuntime: - :path: "../node_modules/react-native/React/Runtime" - React-RCTSettings: - :path: "../node_modules/react-native/Libraries/Settings" - React-RCTText: - :path: "../node_modules/react-native/Libraries/Text" - React-RCTVibration: - :path: "../node_modules/react-native/Libraries/Vibration" - React-rendererconsistency: - :path: "../node_modules/react-native/ReactCommon/react/renderer/consistency" - React-renderercss: - :path: "../node_modules/react-native/ReactCommon/react/renderer/css" - React-rendererdebug: - :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" - React-RuntimeApple: - :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" - React-RuntimeCore: - :path: "../node_modules/react-native/ReactCommon/react/runtime" - React-runtimeexecutor: - :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" - React-RuntimeHermes: - :path: "../node_modules/react-native/ReactCommon/react/runtime" - React-runtimescheduler: - :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" - React-timing: - :path: "../node_modules/react-native/ReactCommon/react/timing" - React-utils: - :path: "../node_modules/react-native/ReactCommon/react/utils" - React-viewtransitionnativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/viewtransition" - React-webperformancenativemodule: - :path: "../node_modules/react-native/ReactCommon/react/nativemodule/webperformance" - ReactAppDependencyProvider: - :path: build/generated/ios/ReactAppDependencyProvider - ReactCodegen: - :path: build/generated/ios/ReactCodegen - ReactCommon: - :path: "../node_modules/react-native/ReactCommon" - ReactNativeDependencies: - :podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec" - RNCAsyncStorage: - :path: "../node_modules/@react-native-async-storage/async-storage" - RNScreens: - :path: "../node_modules/react-native-screens" - Yoga: - :path: "../node_modules/react-native/ReactCommon/yoga" - -SPEC CHECKSUMS: - EXApplication: a727f05eb8592f0bc764f6ab8d51eacc158652ec - EXConstants: 8948a340eb14bf2bdaaa0e21a63cb9343860b87a - Expo: d06878ab7512dbcb2deec84c4d56f07af8a8b765 - ExpoAsset: b3999ffb3d4049b6c870708c60ea2209ace9f170 - ExpoCamera: c4c16b83b6db376e5a0e538fe2a04deafbb5b6d8 - ExpoCameraBarcodeScanning: 69275ab8ecd76f338da22df825c59405bcf36472 - ExpoClipboard: 15b8cc88075d7c50af165ed8fca0a76915903bba - ExpoDomWebView: beaec034e51bd028428b98bb1f2633ab79c6d095 - ExpoFileSystem: 28778f942725170102f7c6cf4dee05a526ddacd0 - ExpoFont: f8198a952ba2ff53c9b393b5269ea435f232cfc3 - ExpoKeepAwake: 72af0b3be3615e59bc819d26061ff4e06b155ee0 - ExpoLinking: 15c8ddb0eb4a778950712ea4a6feedf021778852 - ExpoLocalAuthentication: 1e4aef156a3a1f953f8278b8d8309f6118919640 - ExpoLogBox: 80957303325cd4439137765c90a87d7f22aaf2ff - ExpoModulesCore: 859b593d784f53f2a55224dd0b21e7c80556465e - ExpoModulesJSI: 9df8e7c9719f59e8c001ec33611774137fc1484a - ExpoModulesWorklets: 986cf72c18400743869b4642d243115f831e404d - ExpoNotifications: 098f80e610228da37ee98c0828931337cf5b1106 - ExpoSecureStore: ff1fd5e073957417ba8f9dec0bebcbd55a60e747 - FBLazyVector: 2138c6c2ab66c31bf5754dc18097fbc498a49c7f - hermes-engine: a1e4a1fbfc2f5de70c9a5c1454992f977a6337c6 - RCTDeprecation: 96f68ebf33f8762466b01d57d6e873c4f30efb07 - RCTRequired: 166eed8ad6d8440e73e56d09a9090366609823d2 - RCTSwiftUI: e818198d11928a78c2b2afe281d072171dab617f - RCTSwiftUIWrapper: b9457f8613a1d0c8146c08844a04154702ff8809 - RCTTypeSafety: efc19e6b92931abf0b68b064212323a258a5f019 - React: 52dce66f71097ed7a4968673d95eeb8095ded74e - React-callinvoker: afa0525ab27f4ffbb4c377f855fe9368edb099bc - React-Core: fdb67992e049f2526ade3e258c21b8404e7943a3 - React-Core-prebuilt: 9abc518a8aa7aa4fa3bbbe52bc825bcd9fb3c3ce - React-CoreModules: 456d91152aa283ddc6ae8abfcec3292af88912f6 - React-cxxreact: 73a20c0dde5ec221f98d5e4da0e71349ab48353d - React-debug: d06757ac6c78b84af0c31e513a83662d6b8d0ac7 - React-defaultsnativemodule: ad832e8ce045ef01ea586834b1732c3d4d4d5d86 - React-domnativemodule: 7d1bd200df2d58c2f61d416cf16838c0c9fbb06c - React-Fabric: 363e0524d0724a17afbcba653da4f3398f41236e - React-FabricComponents: d41c87cd39ccf6c4c1df7f726ced22db1f90f072 - React-FabricImage: b4fb0ebc0a2e6fabfd8de8b3fa441331bda99403 - React-featureflags: 1c88b4566806604500a8a9fdf9ad0108c2e9d541 - React-featureflagsnativemodule: dab00693f49c6629f186dedcc3cdaeadd094972f - React-graphics: 991a75fa954a20d0297580dc7fd4e365982cef3b - React-hermes: 65cfbf62d8d31c1e69f3556ff6836a2890cf4a62 - React-idlecallbacksnativemodule: 492f6da9e5a2fa37e2ac0c3a7447302a342d42c2 - React-ImageManager: 02effe13f7b0ca3a7282ee364a8691cd789b9726 - React-intersectionobservernativemodule: 91b54a39a2e7187b9caf62e8b7310aa2d0026679 - React-jserrorhandler: 91985482e35b0b102febda42168ee71946db9958 - React-jsi: 69052b2d1958c9069a143f1637f382b933917b43 - React-jsiexecutor: b9b98ea432f58ee2899a60204f090d0bc8d48313 - React-jsinspector: 75119552df2413c48d33e9f0a72836b30c1ccb14 - React-jsinspectorcdp: 8e65995e9083f7bce0839d3169f6f2d304049e2e - React-jsinspectornetwork: 7e8375e27430cc7694c52fb904db2b9118194480 - React-jsinspectortracing: 643bd9d6f9dc64ea9b28b0e915b4fb0b9b0b1b90 - React-jsitooling: b7ec4b982dfc62f744587deeb1948b983f9edaa4 - React-jsitracing: 8d2f0c8d6d81324606b6d55b946cb443a0c5a425 - React-logger: b9bf04943233973fece220497f0784eaad409b3a - React-Mapbuffer: 3c805ea54675b00ef1755f23b3c1fccf34962b93 - React-microtasksnativemodule: 97a771dbbb4315c71579995b53e4e3e351a99d89 - React-mutationobservernativemodule: 530bff1bba9511a5133e3cf8170e3b2c0df49e89 - react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba - react-native-safe-area-context: 6b4966397ada0f7dd481e4486a2ef936834861a1 - React-NativeModulesApple: 2b658272ca69df0694cf5d54f9510aa7c33977bc - React-networking: 6be0b80e18e710dd30e77b04838ec46666a7bb78 - React-oscompat: cea7c66df8076bd97e95885d7f584b86afffde41 - React-perflogger: 9110ba33a4aa70c708e9d50aeca040e6f2aefaf7 - React-performancecdpmetrics: d9c07c4855c5a975cc7abc482fcb086e8a87abd1 - React-performancetimeline: 336af57802d9cdb4ac079774007677031c891fe0 - React-RCTActionSheet: aeb20277150454e9020517c6a2cb70410d4856d9 - React-RCTAnimation: 8453deeb01d0f284202c9670b5f7d827575b4967 - React-RCTAppDelegate: 5e9c748cc138decd9045683d8987700d824a99ff - React-RCTBlob: e6c01cae3eeb7e63a55b12f72b7dfcfd8236b4b2 - React-RCTFabric: deab07276af1b74b0b8d0772a9a58cac15785312 - React-RCTFBReactNativeSpec: 83d67909e5c67b460bec8851d8413a8ce1ecc6b2 - React-RCTImage: ec8488bc119d7e5d3209f85be3ebda7e4a937c61 - React-RCTLinking: b6ff56c2f206127d49d338262418c097ea306ad0 - React-RCTNetwork: 08d71b365278511a9bb07885b4a54bdc510d99bf - React-RCTRuntime: 634c58094cc601bc2a63ef38b2389cf81143fbcb - React-RCTSettings: 372551bc9f30d26890f5c5fd569dcd15243c656c - React-RCTText: 62cff7e93aeb3c06e3634f1c59984e8c5322b542 - React-RCTVibration: 2e8c1630ae80c092f437db9638a03715f616ac03 - React-rendererconsistency: e8b244c284931cac80a30ce754d77f6c64e528f9 - React-renderercss: 97791244f7ff7a2a060d07acbf240261d4a0519c - React-rendererdebug: 9d023ca26ed3daf60e7b7615729bb7ba6027a96a - React-RuntimeApple: 2daf515379135ccd5e3af5306c90f7827428f4ca - React-RuntimeCore: 637867058de3e0ae7f1ef2653cd0e01c4c850d71 - React-runtimeexecutor: a5cdf5961ec221a40e6612f35bd1e23f84fd9702 - React-RuntimeHermes: 390a5605857f207c8261c75fd4a296ead9aeee0f - React-runtimescheduler: 1be91f9ec0417bb69bd8dfabbe11b07147b24538 - React-timing: bbb861d02c9bcee3e9c08c51a38f59d27c0904ce - React-utils: 28c555b582a9607a938cc0f47b5a7600db42393a - React-viewtransitionnativemodule: 3977270cf367fd1562221047e2358a26da174f2d - React-webperformancenativemodule: fb203d77856165582e519855fc13773a2855f9a6 - ReactAppDependencyProvider: bb350d1333fd459c1aabe782088419a9b8894d3a - ReactCodegen: 828f54f35f2bc4ee3f39345144ff0ec22c9535c2 - ReactCommon: 02f6a489d5eb4ab79d7deba5cd4434e0ba351a07 - ReactNativeDependencies: 6738e602b46fd24aa453cd58267ec3bb8bf29d27 - RNCAsyncStorage: 2ad919e88b8bc2cd80e8697ce66d04d006743283 - RNScreens: 7118cd7715c226856125b5bece3c4d9abec90356 - Yoga: 18b74b3ade30bebc1904004dfaceae1dd02a330a - ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 - -PODFILE CHECKSUM: 056772c7104740b5121837f3617d58290be47fa8 - -COCOAPODS: 1.17.0 diff --git a/mobile/ios/Podfile.properties.json b/mobile/ios/Podfile.properties.json deleted file mode 100644 index 95e5a41..0000000 --- a/mobile/ios/Podfile.properties.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "expo.jsEngine": "hermes", - "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true", - "expo.inlineModules.watchedDirectories": "[]", - "expo.inlineModules.xcodeProjectTargets": "{\"mainTarget\":\"Skur\",\"targets\":[]}", - "EXPO_USE_PRECOMPILED_MODULES": "false" -} \ No newline at end of file diff --git a/mobile/ios/Skur.xcodeproj/project.pbxproj b/mobile/ios/Skur.xcodeproj/project.pbxproj deleted file mode 100644 index 0be63c7..0000000 --- a/mobile/ios/Skur.xcodeproj/project.pbxproj +++ /dev/null @@ -1,570 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; - 242B3214F71344004775440B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */; }; - 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; - 58D12312F746D2921935B260 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */; }; - BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; - D13F2AED329DF3390FC31857 /* libPods-Skur.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0B846F60806D8065C4FC1076 /* libPods-Skur.a */; }; - F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F11748412D0307B40044C1D9 /* AppDelegate.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = Skur/PrivacyInfo.xcprivacy; sourceTree = ""; }; - 0B846F60806D8065C4FC1076 /* libPods-Skur.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Skur.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07F961A680F5B00A75B9A /* Skur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Skur.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Skur/Images.xcassets; sourceTree = ""; }; - 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Skur/Info.plist; sourceTree = ""; }; - 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Skur.debug.xcconfig"; path = "Target Support Files/Pods-Skur/Pods-Skur.debug.xcconfig"; sourceTree = ""; }; - 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-Skur/ExpoModulesProvider.swift"; sourceTree = ""; }; - 905D895957517020C305549E /* Pods-Skur.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Skur.release.xcconfig"; path = "Target Support Files/Pods-Skur/Pods-Skur.release.xcconfig"; sourceTree = ""; }; - AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = Skur/SplashScreen.storyboard; sourceTree = ""; }; - BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = ""; }; - ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; - F11748412D0307B40044C1D9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Skur/AppDelegate.swift; sourceTree = ""; }; - F11748442D0722820044C1D9 /* Skur-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "Skur-Bridging-Header.h"; path = "Skur/Skur-Bridging-Header.h"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D13F2AED329DF3390FC31857 /* libPods-Skur.a in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 13B07FAE1A68108700A75B9A /* Skur */ = { - isa = PBXGroup; - children = ( - F11748412D0307B40044C1D9 /* AppDelegate.swift */, - F11748442D0722820044C1D9 /* Skur-Bridging-Header.h */, - BB2F792B24A3F905000567C9 /* Supporting */, - 13B07FB51A68108700A75B9A /* Images.xcassets */, - 13B07FB61A68108700A75B9A /* Info.plist */, - AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */, - 07695E364E6917195BAE692E /* PrivacyInfo.xcprivacy */, - ); - name = Skur; - sourceTree = ""; - }; - 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { - isa = PBXGroup; - children = ( - ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 0B846F60806D8065C4FC1076 /* libPods-Skur.a */, - ); - name = Frameworks; - sourceTree = ""; - }; - 832341AE1AAA6A7D00B99B32 /* Libraries */ = { - isa = PBXGroup; - children = ( - ); - name = Libraries; - sourceTree = ""; - }; - 83CBB9F61A601CBA00E9B192 = { - isa = PBXGroup; - children = ( - 13B07FAE1A68108700A75B9A /* Skur */, - 832341AE1AAA6A7D00B99B32 /* Libraries */, - 83CBBA001A601CBA00E9B192 /* Products */, - 2D16E6871FA4F8E400B85C8A /* Frameworks */, - DFB825BCD9BC0E07AB6AFF87 /* Pods */, - 87DCFAAEFA5DB25BC6833BB1 /* ExpoModulesProviders */, - ); - indentWidth = 2; - sourceTree = ""; - tabWidth = 2; - usesTabs = 0; - }; - 83CBBA001A601CBA00E9B192 /* Products */ = { - isa = PBXGroup; - children = ( - 13B07F961A680F5B00A75B9A /* Skur.app */, - ); - name = Products; - sourceTree = ""; - }; - 87DCFAAEFA5DB25BC6833BB1 /* ExpoModulesProviders */ = { - isa = PBXGroup; - children = ( - AA51DD12C9A244FE59F73DAC /* Skur */, - ); - name = ExpoModulesProviders; - sourceTree = ""; - }; - AA51DD12C9A244FE59F73DAC /* Skur */ = { - isa = PBXGroup; - children = ( - 785DF7D124F5CE6DAA3A8181 /* ExpoModulesProvider.swift */, - ); - name = Skur; - sourceTree = ""; - }; - BB2F792B24A3F905000567C9 /* Supporting */ = { - isa = PBXGroup; - children = ( - BB2F792C24A3F905000567C9 /* Expo.plist */, - ); - name = Supporting; - path = Skur/Supporting; - sourceTree = ""; - }; - DFB825BCD9BC0E07AB6AFF87 /* Pods */ = { - isa = PBXGroup; - children = ( - 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */, - 905D895957517020C305549E /* Pods-Skur.release.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 13B07F861A680F5B00A75B9A /* Skur */ = { - isa = PBXNativeTarget; - buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Skur" */; - buildPhases = ( - 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, - 4F45F064C519C0B967E3A074 /* [Expo] Configure project */, - 13B07F871A680F5B00A75B9A /* Sources */, - 13B07F8C1A680F5B00A75B9A /* Frameworks */, - 13B07F8E1A680F5B00A75B9A /* Resources */, - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, - D348159AE2F81BAF644E4C43 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Skur; - productName = Skur; - productReference = 13B07F961A680F5B00A75B9A /* Skur.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 83CBB9F71A601CBA00E9B192 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1130; - TargetAttributes = { - 13B07F861A680F5B00A75B9A = { - LastSwiftMigration = 1250; - }; - }; - }; - buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Skur" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 83CBB9F61A601CBA00E9B192; - productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 13B07F861A680F5B00A75B9A /* Skur */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 13B07F8E1A680F5B00A75B9A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - BB2F792D24A3F905000567C9 /* Expo.plist in Resources */, - 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, - 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */, - 242B3214F71344004775440B /* PrivacyInfo.xcprivacy in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/.xcode.env", - "$(SRCROOT)/.xcode.env.local", - ); - name = "Bundle React Native code and images"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n"; - }; - 08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Skur-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 4F45F064C519C0B967E3A074 /* [Expo] Configure project */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/.xcode.env", - "$(SRCROOT)/.xcode.env.local", - "$(SRCROOT)/Skur/Skur.entitlements", - "$(SRCROOT)/Pods/Target Support Files/Pods-Skur/expo-configure-project.sh", - ); - name = "[Expo] Configure project"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(SRCROOT)/Pods/Target Support Files/Pods-Skur/ExpoModulesProvider.swift", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-Skur/expo-configure-project.sh\"\n"; - }; - 800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/EXApplication/ExpoApplication_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/ExpoNotifications/ExpoNotifications_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle", - "${PODS_CONFIGURATION_BUILD_DIR}/React-timing/React-timing_privacy.bundle", - ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoApplication_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoNotifications_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-timing_privacy.bundle", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - D348159AE2F81BAF644E4C43 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-frameworks.sh", - "${PODS_ROOT}/hermes-engine/destroot/Library/Frameworks/ios/hermesvm.framework", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/ExpoModulesJSI/ExpoModulesJSI.framework/ExpoModulesJSI", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/React-Core-prebuilt/React.framework/React", - "${PODS_XCFRAMEWORKS_BUILD_DIR}/ReactNativeDependencies/ReactNativeDependencies.framework/ReactNativeDependencies", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermesvm.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ExpoModulesJSI.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ReactNativeDependencies.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Skur/Pods-Skur-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 13B07F871A680F5B00A75B9A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - F11748422D0307B40044C1D9 /* AppDelegate.swift in Sources */, - 58D12312F746D2921935B260 /* ExpoModulesProvider.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 13B07F941A680F5B00A75B9A /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 6FF48916FAC4A3352742E9E9 /* Pods-Skur.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Skur/Skur.entitlements; - CURRENT_PROJECT_VERSION = 1; - ENABLE_BITCODE = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( - "$(inherited)", - "FB_SONARKIT_ENABLED=1", - ); - INFOPLIST_FILE = Skur/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 13.4; - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG"; - PRODUCT_BUNDLE_IDENTIFIER = io.skur.vault; - PRODUCT_NAME = Skur; - SWIFT_OBJC_BRIDGING_HEADER = "Skur/Skur-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 13B07F951A680F5B00A75B9A /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 905D895957517020C305549E /* Pods-Skur.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Skur/Skur.entitlements; - CURRENT_PROJECT_VERSION = 1; - INFOPLIST_FILE = Skur/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 13.4; - MARKETING_VERSION = 1.0; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-lc++", - ); - OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE"; - PRODUCT_BUNDLE_IDENTIFIER = io.skur.vault; - PRODUCT_NAME = Skur; - SWIFT_OBJC_BRIDGING_HEADER = "Skur/Skur-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; - 83CBBA201A601CBA00E9B192 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++20"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - /usr/lib/swift, - "$(inherited)", - ); - LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ( - "$(inherited)", - "-DRCT_REMOVE_LEGACY_ARCH=1", - ); - OTHER_CPLUSPLUSFLAGS = ( - "$(inherited)", - "-DRCT_REMOVE_LEGACY_ARCH=1", - ); - PODFILE_DIR = "$(SRCROOT)"; - REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; - SWIFT_ENABLE_EXPLICIT_MODULES = NO; - USE_HERMES = true; - }; - name = Debug; - }; - 83CBBA211A601CBA00E9B192 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++20"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 16.4; - LD_RUNPATH_SEARCH_PATHS = ( - /usr/lib/swift, - "$(inherited)", - ); - LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\""; - MTL_ENABLE_DEBUG_INFO = NO; - OTHER_CFLAGS = ( - "$(inherited)", - "-DRCT_REMOVE_LEGACY_ARCH=1", - ); - OTHER_CPLUSPLUSFLAGS = ( - "$(inherited)", - "-DRCT_REMOVE_LEGACY_ARCH=1", - ); - PODFILE_DIR = "$(SRCROOT)"; - REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; - SDKROOT = iphoneos; - SWIFT_ENABLE_EXPLICIT_MODULES = NO; - USE_HERMES = true; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "Skur" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 13B07F941A680F5B00A75B9A /* Debug */, - 13B07F951A680F5B00A75B9A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "Skur" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 83CBBA201A601CBA00E9B192 /* Debug */, - 83CBBA211A601CBA00E9B192 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; -} diff --git a/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme b/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme deleted file mode 100644 index 465753e..0000000 --- a/mobile/ios/Skur.xcodeproj/xcshareddata/xcschemes/Skur.xcscheme +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata b/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 7fc9b19..0000000 --- a/mobile/ios/Skur.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/mobile/ios/Skur/AppDelegate.swift b/mobile/ios/Skur/AppDelegate.swift deleted file mode 100644 index 9670a1f..0000000 --- a/mobile/ios/Skur/AppDelegate.swift +++ /dev/null @@ -1,69 +0,0 @@ -internal import Expo -import React -import ReactAppDependencyProvider - -@main -class AppDelegate: ExpoAppDelegate { - var window: UIWindow? - - var reactNativeDelegate: ExpoReactNativeFactoryDelegate? - var reactNativeFactory: RCTReactNativeFactory? - - public override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil - ) -> Bool { - let delegate = ReactNativeDelegate() - let factory = ExpoReactNativeFactory(delegate: delegate) - delegate.dependencyProvider = RCTAppDependencyProvider() - - reactNativeDelegate = delegate - reactNativeFactory = factory - -#if os(iOS) || os(tvOS) - window = UIWindow(frame: UIScreen.main.bounds) - factory.startReactNative( - withModuleName: "main", - in: window, - launchOptions: launchOptions) -#endif - - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } - - // Linking API - public override func application( - _ app: UIApplication, - open url: URL, - options: [UIApplication.OpenURLOptionsKey: Any] = [:] - ) -> Bool { - return super.application(app, open: url, options: options) || RCTLinkingManager.application(app, open: url, options: options) - } - - // Universal Links - public override func application( - _ application: UIApplication, - continue userActivity: NSUserActivity, - restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void - ) -> Bool { - let result = RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler) - return super.application(application, continue: userActivity, restorationHandler: restorationHandler) || result - } -} - -class ReactNativeDelegate: ExpoReactNativeFactoryDelegate { - // Extension point for config-plugins - - override func sourceURL(for bridge: RCTBridge) -> URL? { - // needed to return the correct URL for expo-dev-client. - bridge.bundleURL ?? bundleURL() - } - - override func bundleURL() -> URL? { -#if DEBUG - return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry") -#else - return Bundle.main.url(forResource: "main", withExtension: "jsbundle") -#endif - } -} diff --git a/mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png b/mobile/ios/Skur/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png deleted file mode 100644 index ed858557aab88e3cba0ff06536ad2c3a218118b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28686 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�k+si*!9!J=8KakBl8H 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 F{V& - - - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Skur - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 0.1.0 - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleURLSchemes - - skur - io.skur.vault - - - - CFBundleVersion - 1 - LSMinimumSystemVersion - 12.0 - LSRequiresIPhoneOS - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsLocalNetworking - - - NSCameraUsageDescription - Skur uses the camera only to read a vault or recipient address from a QR code. - NSFaceIDUsageDescription - Skur uses Face ID to approve signatures from this device. - NSMicrophoneUsageDescription - Allow $(PRODUCT_NAME) to access your microphone - RCTMetroPort - $(RCT_METRO_PORT) - RCTNewArchEnabled - - UILaunchStoryboardName - SplashScreen - UIRequiredDeviceCapabilities - - arm64 - - UIRequiresFullScreen - - UIStatusBarStyle - UIStatusBarStyleDefault - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - - UIUserInterfaceStyle - Dark - UIViewControllerBasedStatusBarAppearance - - - diff --git a/mobile/ios/Skur/PrivacyInfo.xcprivacy b/mobile/ios/Skur/PrivacyInfo.xcprivacy deleted file mode 100644 index 49b8ded..0000000 --- a/mobile/ios/Skur/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,48 +0,0 @@ - - - - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp - NSPrivacyAccessedAPITypeReasons - - C617.1 - 0A2A.1 - 3B52.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - CA92.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryDiskSpace - NSPrivacyAccessedAPITypeReasons - - E174.1 - 85F4.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategorySystemBootTime - NSPrivacyAccessedAPITypeReasons - - 35F9.1 - - - - NSPrivacyCollectedDataTypes - - NSPrivacyTracking - - - diff --git a/mobile/ios/Skur/Skur-Bridging-Header.h b/mobile/ios/Skur/Skur-Bridging-Header.h deleted file mode 100644 index 8361941..0000000 --- a/mobile/ios/Skur/Skur-Bridging-Header.h +++ /dev/null @@ -1,3 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// diff --git a/mobile/ios/Skur/Skur.entitlements b/mobile/ios/Skur/Skur.entitlements deleted file mode 100644 index 018a6e2..0000000 --- a/mobile/ios/Skur/Skur.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - aps-environment - development - - \ No newline at end of file diff --git a/mobile/ios/Skur/SplashScreen.storyboard b/mobile/ios/Skur/SplashScreen.storyboard deleted file mode 100644 index 58d2179..0000000 --- a/mobile/ios/Skur/SplashScreen.storyboard +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/ios/Skur/Supporting/Expo.plist b/mobile/ios/Skur/Supporting/Expo.plist deleted file mode 100644 index 2324695..0000000 --- a/mobile/ios/Skur/Supporting/Expo.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - EXUpdatesCheckOnLaunch - ALWAYS - EXUpdatesEnableBsdiffPatchSupport - - EXUpdatesEnabled - - EXUpdatesLaunchWaitMs - 0 - - \ No newline at end of file From 7f5e5ec45b4ee478f283e19534d93ec67382ade2 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Mon, 5 Oct 2026 23:12:01 +0100 Subject: [PATCH 31/44] feat(mobile): the Sui app for iOS and Android MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expo and React Native, reading the chain over gRPC and sharing the vault logic with every other interface through @skur/sdk. The design the project settled on carries over — theme, primitives, identicon — with the chain layer replaced. The signing key lives in the device's secure element, unlocked per transaction rather than per session: a cached signer is a signer that acts without a face. The app is explicit that this is a hot key, appropriate for an approver or an executor whose authority the policy bounds, and not for a guardian — a guardian key on the same phone as an approver key collapses the two control planes the contract works to keep apart. Three things React Native needed, none of them obvious: - Hermes has no CSPRNG behind crypto.getRandomValues, which key generation needs. assertCryptoReady fails at startup rather than mid-signature. - BCS needs text codecs that recent React Native ships, but a silent absence would surface as a corrupted transaction rather than a missing global, so there is a guarded UTF-8 fallback. - The Sui SDK is ESM with an exports map and no CommonJS fallback, and @skur/sdk resolves through a symlink. Metro needs package exports enabled and the workspace in watchFolders. Verified by bundling: 5.8MB of Hermes bytecode for iOS, which is the check that actually matters here — it proves the SDK resolves under Metro, where a typecheck cannot. verify.sh now runs both the typecheck and the bundle. --- .gitignore | 1 - README.md | 10 +- mobile/.env.example | 9 + mobile/.gitignore | 9 + mobile/App.tsx | 143 + mobile/README.md | 94 + mobile/app.json | 43 + mobile/index.ts | 4 + mobile/metro.config.js | 22 + mobile/package-lock.json | 5795 +++++++++++++++++++++++++++ mobile/package.json | 45 + mobile/src/components/Identicon.tsx | 38 + mobile/src/components/TokenMark.tsx | 48 + mobile/src/components/ui.tsx | 313 ++ mobile/src/hooks/useTx.ts | 77 + mobile/src/hooks/useVault.ts | 65 + mobile/src/lib/client.ts | 12 + mobile/src/lib/config.ts | 23 + mobile/src/lib/keystore.ts | 117 + mobile/src/lib/polyfills.ts | 83 + mobile/src/screens/Home.tsx | 171 + mobile/src/screens/Onboard.tsx | 156 + mobile/src/screens/OpenVault.tsx | 100 + mobile/src/screens/Receive.tsx | 64 + mobile/src/screens/Security.tsx | 169 + mobile/src/screens/Send.tsx | 222 + mobile/src/screens/Settings.tsx | 111 + mobile/src/screens/Transactions.tsx | 108 + mobile/src/screens/TxDetail.tsx | 249 ++ mobile/src/screens/Welcome.tsx | 51 + mobile/src/state/store.tsx | 128 + mobile/src/state/theme.tsx | 31 + mobile/src/theme.ts | 39 + mobile/tsconfig.json | 13 + package.json | 7 +- scripts/verify.sh | 5 + 36 files changed, 8570 insertions(+), 5 deletions(-) create mode 100644 mobile/.env.example create mode 100644 mobile/.gitignore create mode 100644 mobile/App.tsx create mode 100644 mobile/README.md create mode 100644 mobile/app.json create mode 100644 mobile/index.ts create mode 100644 mobile/metro.config.js create mode 100644 mobile/package-lock.json create mode 100644 mobile/package.json create mode 100644 mobile/src/components/Identicon.tsx create mode 100644 mobile/src/components/TokenMark.tsx create mode 100644 mobile/src/components/ui.tsx create mode 100644 mobile/src/hooks/useTx.ts create mode 100644 mobile/src/hooks/useVault.ts create mode 100644 mobile/src/lib/client.ts create mode 100644 mobile/src/lib/config.ts create mode 100644 mobile/src/lib/keystore.ts create mode 100644 mobile/src/lib/polyfills.ts create mode 100644 mobile/src/screens/Home.tsx create mode 100644 mobile/src/screens/Onboard.tsx create mode 100644 mobile/src/screens/OpenVault.tsx create mode 100644 mobile/src/screens/Receive.tsx create mode 100644 mobile/src/screens/Security.tsx create mode 100644 mobile/src/screens/Send.tsx create mode 100644 mobile/src/screens/Settings.tsx create mode 100644 mobile/src/screens/Transactions.tsx create mode 100644 mobile/src/screens/TxDetail.tsx create mode 100644 mobile/src/screens/Welcome.tsx create mode 100644 mobile/src/state/store.tsx create mode 100644 mobile/src/state/theme.tsx create mode 100644 mobile/src/theme.ts create mode 100644 mobile/tsconfig.json diff --git a/.gitignore b/.gitignore index 80ad9c7..99e3487 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,3 @@ crytic-export/ # `git add -A` happily commits an Expo prebuild. Never track these paths again. /contracts/ /web/ -/mobile/ diff --git a/README.md b/README.md index fbde0c1..dd9b266 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ Details, with the test that proves each invariant, in |---|---| | [sui/](sui/) | The Move package: `types`, `policy`, `risk`, `vault`, and the test suites named after the attacks they defend against | | [sdk/](sdk/) | TypeScript SDK on `@mysten/sui` v2 — reads, PTB builders, event decoding, and the chain-agnostic engines (risk, policy rules, templates, maximum loss, posture, attack simulator) | -| [app/](app/) | The interface: Next.js, React, `@mysten/dapp-kit-react` | +| [app/](app/) | The web interface: Next.js, React, `@mysten/dapp-kit-react` | +| [mobile/](mobile/) | iOS and Android: Expo, React Native, with the signing key in the device's secure element | | [server/](server/) | Node and PostgreSQL: the event indexer, the notification service and the advisory API | | [docs/SUI_SECURITY_MODEL.md](docs/SUI_SECURITY_MODEL.md) | Roles, lifecycle, the sixteen invariants, the threat map and the known limitations | | [docs/SUI_LANDSCAPE.md](docs/SUI_LANDSCAPE.md) | What exists on Sui today and what it does not do | @@ -85,10 +86,15 @@ cp .env.example .env # set DATABASE_URL and SKUR_PACKAGE_ID createdb skur && npm install && npm run migrate npm run dev # the indexer and the read API together -# the interface +# the web interface cd ../app npm install npm run dev # http://localhost:3000 + +# the phone +cd ../mobile +npm install +npm run ios # or: npm run android, npm start ``` The Sui CLI is the one prerequisite that is not an npm install: get it from diff --git a/mobile/.env.example b/mobile/.env.example new file mode 100644 index 0000000..3e43396 --- /dev/null +++ b/mobile/.env.example @@ -0,0 +1,9 @@ +# Which network, and the package published on it. +EXPO_PUBLIC_SKUR_NETWORK=testnet +EXPO_PUBLIC_SKUR_PACKAGE_ID=0x0 + +# A full node other than the public one. +# EXPO_PUBLIC_SKUR_GRPC_URL=https://fullnode.testnet.sui.io:443 + +# The indexer. Optional: every screen reads the chain directly without it. +# EXPO_PUBLIC_SKUR_API=http://localhost:8787 diff --git a/mobile/.gitignore b/mobile/.gitignore new file mode 100644 index 0000000..100dbea --- /dev/null +++ b/mobile/.gitignore @@ -0,0 +1,9 @@ +node_modules/ +.expo/ +dist/ +web-build/ +ios/ +android/ +*.log +.env +.env.local diff --git a/mobile/App.tsx b/mobile/App.tsx new file mode 100644 index 0000000..c26b92e --- /dev/null +++ b/mobile/App.tsx @@ -0,0 +1,143 @@ +import './src/lib/polyfills'; + +import { useFonts } from 'expo-font'; +import { DMMono_400Regular, DMMono_500Medium } from '@expo-google-fonts/dm-mono'; +import { DMSans_400Regular, DMSans_500Medium, DMSans_700Bold } from '@expo-google-fonts/dm-sans'; +import { SpaceGrotesk_600SemiBold, SpaceGrotesk_700Bold } from '@expo-google-fonts/space-grotesk'; +import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native'; +import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { StatusBar } from 'expo-status-bar'; +import { useState } from 'react'; +import { ActivityIndicator, View } from 'react-native'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; + +import { Icon } from './src/components/ui'; +import { StoreProvider, useStore } from './src/state/store'; +import { ThemeProvider, useScheme, useTheme } from './src/state/theme'; +import { F } from './src/theme'; +import { Home } from './src/screens/Home'; +import { Onboard } from './src/screens/Onboard'; +import { OpenVault } from './src/screens/OpenVault'; +import { Receive } from './src/screens/Receive'; +import { Security } from './src/screens/Security'; +import { Send } from './src/screens/Send'; +import { Settings } from './src/screens/Settings'; +import { Transactions } from './src/screens/Transactions'; +import { TxDetail } from './src/screens/TxDetail'; +import { Welcome } from './src/screens/Welcome'; + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { staleTime: 5_000, retry: 1, refetchOnWindowFocus: false }, + }, +}); + +const Tab = createBottomTabNavigator(); +const Stack = createNativeStackNavigator(); + +/** The activity tab owns its own stack, so a proposal opens over it rather than replacing it. */ +function ActivityStack() { + const [open, setOpen] = useState(null); + if (open !== null) return setOpen(null)} />; + return ; +} + +function Tabs() { + const C = useTheme(); + const [tab, setTab] = useState(0); + return ( + ({ + headerShown: false, + tabBarActiveTintColor: C.text, + tabBarInactiveTintColor: C.text3, + tabBarStyle: { backgroundColor: C.canvas, borderTopColor: C.border }, + tabBarLabelStyle: { fontFamily: F.bodyMedium, fontSize: 11 }, + tabBarIcon: ({ color }) => { + const name = + route.name === 'Treasury' + ? 'home' + : route.name === 'Activity' + ? 'list' + : route.name === 'Pay' + ? 'arrow-up-right' + : route.name === 'Receive' + ? 'download' + : route.name === 'Security' + ? 'shield' + : 'settings'; + return ; + }, + })} + > + + {() => setTab(1)} onSwitch={() => undefined} />} + + + {() => undefined} />} + + + + + ); +} + +/** Decides what the app is: an introduction, a key to set up, a vault to pick, or the vault. */ +function Root() { + const C = useTheme(); + const { dark } = useScheme(); + const { ready, onboarded, address, vaultId, finishOnboarding } = useStore(); + const [seenWelcome, setSeenWelcome] = useState(false); + + if (!ready) { + return ( + + + + ); + } + + const nav = { + ...(dark ? DarkTheme : DefaultTheme), + colors: { ...(dark ? DarkTheme : DefaultTheme).colors, background: C.canvas, card: C.canvas, border: C.border, text: C.text, primary: C.accent }, + }; + + return ( + + + {!onboarded && !seenWelcome ? ( + setSeenWelcome(true)} /> + ) : !address ? ( + + ) : !vaultId ? ( + + ) : ( + + )} + + ); +} + +export default function App() { + const [loaded] = useFonts({ + DMSans_400Regular, + DMSans_500Medium, + DMSans_700Bold, + DMMono_400Regular, + DMMono_500Medium, + SpaceGrotesk_600SemiBold, + SpaceGrotesk_700Bold, + }); + + return ( + + + + {loaded ? : null} + + + + ); +} diff --git a/mobile/README.md b/mobile/README.md new file mode 100644 index 0000000..7bcbabc --- /dev/null +++ b/mobile/README.md @@ -0,0 +1,94 @@ +# Skur on iOS and Android + +Expo and React Native, reading the chain through `@mysten/sui` over gRPC and sharing the vault +logic with every other interface via [`@skur/sdk`](../sdk). + +## The key on the device + +This is the part to understand before using it. + +The app generates an Ed25519 key and writes it to the **iOS keychain or Android keystore**, not to +app storage. `requireAuthentication` means the OS will not release it without a successful +biometric or passcode check, and the key is unlocked **per transaction** — there is no session. +A cached signer is a signer that acts without a face, which on a treasury app is the thing you +were trying to avoid. + +What that does **not** give you: + +- **No protection on a rooted or jailbroken device.** The keystore's guarantees end there. +- **No backup.** Lose the phone and the key is gone — which is what the vault's guardian recovery + is for: guardians move your roles to a new key after a delay any owner can cancel. + +**A key on a phone is a hot key.** It is appropriate for an **approver** or an **executor**, whose +authority is bounded by the vault's policy — tiers, caps, the day's allowance, the loss envelope. +It is **not** appropriate for a **guardian**. A guardian's entire value is being an independent +control plane an attacker has to breach separately; keeping a guardian key on the same phone as an +approver key collapses the two planes the contract works to keep apart. The app says so where it +matters, and the contract will refuse to give one address both roles anyway. + +## Running it + +```bash +npm install +cp .env.example .env # point it at a network and a published package +npm start # Metro, for Expo Go or a dev build +npm run ios # prebuild, pods and a simulator run +npm run android +npm run typecheck +``` + +Every script builds [`../sdk`](../sdk) first, because the app consumes its compiled output and a +fresh clone would otherwise fail with an unhelpful resolver error. + +| Variable | What it does | +|---|---| +| `EXPO_PUBLIC_SKUR_NETWORK` | `mainnet`, `testnet`, `devnet` or `localnet` | +| `EXPO_PUBLIC_SKUR_PACKAGE_ID` | The published package | +| `EXPO_PUBLIC_SKUR_GRPC_URL` | A full node other than the public one | +| `EXPO_PUBLIC_SKUR_API` | The indexer. Optional — see below | + +`app.json`'s `extra` holds the committed defaults; `EXPO_PUBLIC_*` overrides them. + +## What needed solving for React Native + +Three things, all in [`src/lib/polyfills.ts`](src/lib/polyfills.ts) and +[`metro.config.js`](metro.config.js): + +- **Hermes has no CSPRNG behind `crypto.getRandomValues`**, which key generation needs. + `react-native-get-random-values` supplies it, and `assertCryptoReady` fails at startup rather + than mid-signature if it did not load. +- **The text codecs BCS needs** ship with recent React Native, but a silent absence would surface + much later as a corrupted transaction rather than a missing global, so there is a guarded UTF-8 + fallback. +- **The Sui SDK is ESM with an exports map and no CommonJS fallback**, and `@skur/sdk` resolves + through a symlink to a sibling directory. Metro needs `unstable_enablePackageExports` and the + workspace in `watchFolders`, or an edit to the SDK is invisible until the bundler restarts. + +Transport is **gRPC-web over fetch**, which is what React Native can actually do — there is no +HTTP/2 socket to reach for. JSON-RPC is not used anywhere: Sui switched it off on mainnet full +nodes in July 2026 and is removing it. + +## The indexer is optional + +Every screen reads the chain directly through the SDK. Setting `EXPO_PUBLIC_SKUR_API` adds one +thing — finding your vaults by address, since a vault does not know it is yours — and saves round +trips. Without it you open a vault by its id and everything else works. + +## Screens + +| Screen | What it does | +|---|---| +| Welcome, Set up signing | The pitch, then creating or importing the device key | +| Treasury | Posture, holdings, today's outflow per asset, what the policy enforces | +| Activity | The queue and the history, with one proposal per row | +| Proposal | Approve, reject, confirm, veto or execute — each gated on the role the contract requires | +| Pay | Open a payment, with the vault's own `preview_transfer` as the review | +| Receive | The vault address, and which assets it accepts | +| Security | The posture report, the maximum-loss numbers, and freezing the vault | +| Settings | Appearance, the device key, the network, closing the vault | + +Every action is gated on the role the device's key actually holds, so a signer is never offered +something the vault would refuse. The payment review is the chain's classification, simulated +live — the phone does not compute a tier, because an interface that computed its own answer could +promise something the vault would reject, and on a confirmation screen that is the one thing that +must never happen. diff --git a/mobile/app.json b/mobile/app.json new file mode 100644 index 0000000..dec9eb3 --- /dev/null +++ b/mobile/app.json @@ -0,0 +1,43 @@ +{ + "expo": { + "name": "Skur", + "slug": "skur", + "version": "1.0.0", + "orientation": "portrait", + "scheme": "skur", + "userInterfaceStyle": "automatic", + "newArchEnabled": true, + "ios": { + "supportsTablet": false, + "bundleIdentifier": "io.skur.app", + "usePrecompiledModules": false, + "infoPlist": { + "NSFaceIDUsageDescription": "Skur unlocks your signing key with Face ID so a payment cannot be approved without you.", + "NSCameraUsageDescription": "Skur uses the camera to scan a vault or recipient address." + } + }, + "android": { + "package": "io.skur.app", + "edgeToEdgeEnabled": true, + "permissions": ["android.permission.USE_BIOMETRIC", "android.permission.CAMERA"] + }, + "plugins": [ + [ + "expo-local-authentication", + { + "faceIDPermission": "Skur unlocks your signing key with Face ID so a payment cannot be approved without you." + } + ], + [ + "expo-camera", + { + "cameraPermission": "Skur uses the camera to scan a vault or recipient address." + } + ] + ], + "extra": { + "SKUR_NETWORK": "testnet", + "SKUR_PACKAGE_ID": "0x0" + } + } +} diff --git a/mobile/index.ts b/mobile/index.ts new file mode 100644 index 0000000..5fd059f --- /dev/null +++ b/mobile/index.ts @@ -0,0 +1,4 @@ +import { registerRootComponent } from 'expo'; +import App from './App'; + +registerRootComponent(App); diff --git a/mobile/metro.config.js b/mobile/metro.config.js new file mode 100644 index 0000000..37e0ea5 --- /dev/null +++ b/mobile/metro.config.js @@ -0,0 +1,22 @@ +const { getDefaultConfig } = require('expo/metro-config'); +const path = require('node:path'); + +const projectRoot = __dirname; +const workspaceRoot = path.resolve(projectRoot, '..'); + +const config = getDefaultConfig(projectRoot); + +// `@skur/sdk` is a file: dependency, so it resolves through a symlink to a sibling directory. +// Metro has to be told to watch the workspace and to look there for modules, or an edit to the +// SDK is invisible until the bundler is restarted. +config.watchFolders = [workspaceRoot]; +config.resolver.nodeModulesPaths = [ + path.resolve(projectRoot, 'node_modules'), + path.resolve(workspaceRoot, 'node_modules'), +]; + +// The Sui SDK ships ESM with an exports map and no CommonJS fallback. +config.resolver.unstable_enablePackageExports = true; +config.resolver.unstable_conditionNames = ['react-native', 'require', 'import', 'default']; + +module.exports = config; diff --git a/mobile/package-lock.json b/mobile/package-lock.json new file mode 100644 index 0000000..f1ddffb --- /dev/null +++ b/mobile/package-lock.json @@ -0,0 +1,5795 @@ +{ + "name": "@skur/mobile", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@skur/mobile", + "version": "1.0.0", + "dependencies": { + "@expo-google-fonts/dm-mono": "^0.4.2", + "@expo-google-fonts/dm-sans": "^0.4.2", + "@expo-google-fonts/space-grotesk": "^0.4.1", + "@expo/vector-icons": "^15.0.2", + "@mysten/sui": "^2.34.0", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.19.1", + "@react-navigation/native": "^7.4.1", + "@react-navigation/native-stack": "^7.19.1", + "@skur/sdk": "file:../sdk", + "@tanstack/react-query": "^5.102.8", + "expo": "~57.0.23", + "expo-camera": "~57.0.5", + "expo-clipboard": "~57.0.2", + "expo-constants": "^57.0.20", + "expo-font": "~57.0.4", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", + "expo-notifications": "~57.0.19", + "expo-secure-store": "~57.0.4", + "expo-status-bar": "~57.0.1", + "react": "19.2.3", + "react-native": "0.86.3", + "react-native-get-random-values": "~1.11.0", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0" + }, + "devDependencies": { + "@types/react": "~19.2.2", + "typescript": "~6.0.3" + } + }, + "../sdk": { + "name": "@skur/sdk", + "version": "0.1.0", + "dependencies": { + "@mysten/sui": "^2.34.0" + }, + "devDependencies": { + "@types/node": "^24.19.1", + "typescript": "~6.0.2", + "vitest": "^3.2.7" + } + }, + "node_modules/@0no-co/graphql.web": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.3.4.tgz", + "integrity": "sha512-imSwulOeDQodRy/olQmVEo2PiY6ntjkZ9eiGdw6lMYylh/tay9b7MusyJBmEnkL8GiKRKr6ltr+D42mY5bd8Bg==", + "license": "MIT", + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "graphql": { + "optional": true + } + } + }, + "node_modules/@0no-co/graphqlsp": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/@0no-co/graphqlsp/-/graphqlsp-1.17.5.tgz", + "integrity": "sha512-wsygfTO3pdkz4idDw8BxdMdgB9AB8nuJDJTUwYy87BiZEZRXS4bEfn4oNl9VtxTo6j2lzX/gED+IvOgxsSy2Jg==", + "license": "MIT", + "dependencies": { + "@gql.tada/internal": "^1.2.1", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-decorators": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-flow": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@expo-google-fonts/dm-mono": { + "version": "0.4.2", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo-google-fonts/dm-sans": { + "version": "0.4.2", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo-google-fonts/space-grotesk": { + "version": "0.4.1", + "license": "MIT AND OFL-1.1" + }, + "node_modules/@expo/code-signing-certificates": { + "version": "0.0.6", + "license": "MIT", + "dependencies": { + "node-forge": "^1.3.3" + } + }, + "node_modules/@expo/config": { + "version": "57.0.9", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.9", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.5", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/@expo/config-plugins": { + "version": "57.0.9", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.5", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/config-types": { + "version": "57.0.2", + "license": "MIT" + }, + "node_modules/@expo/devcert": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "@expo/sudo-prompt": "^9.3.1", + "debug": "^3.1.0" + } + }, + "node_modules/@expo/devcert/node_modules/debug": { + "version": "3.2.7", + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@expo/devtools": { + "version": "57.0.1", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@expo/env": { + "version": "2.4.3", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" + } + }, + "node_modules/@expo/expo-modules-macros-plugin": { + "version": "0.6.1", + "license": "MIT" + }, + "node_modules/@expo/fingerprint": { + "version": "0.20.13", + "license": "MIT", + "dependencies": { + "@expo/env": "^2.4.3", + "@expo/spawn-async": "^1.8.0", + "arg": "^5.0.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "ignore": "^5.3.1", + "minimatch": "^10.2.2", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "bin": { + "fingerprint": "bin/cli.js" + } + }, + "node_modules/@expo/image-utils": { + "version": "0.11.5", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/inline-modules": { + "version": "0.1.7", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.9" + } + }, + "node_modules/@expo/json-file": { + "version": "11.0.1", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/local-build-cache-provider": { + "version": "57.0.8", + "license": "MIT", + "dependencies": { + "@expo/config": "~57.0.9", + "chalk": "^4.1.2" + } + }, + "node_modules/@expo/metro": { + "version": "56.0.2", + "license": "MIT", + "dependencies": { + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5" + } + }, + "node_modules/@expo/metro-file-map": { + "version": "57.0.3", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "fb-watchman": "^2.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "node_modules/@expo/osascript": { + "version": "2.7.1", + "license": "MIT", + "dependencies": { + "@expo/spawn-async": "^1.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/package-manager": { + "version": "1.13.1", + "license": "MIT", + "dependencies": { + "@expo/json-file": "^11.0.1", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" + } + }, + "node_modules/@expo/plist": { + "version": "0.8.1", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/prebuild-config": { + "version": "57.0.16", + "license": "MIT", + "dependencies": { + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/config-types": "^57.0.2", + "@expo/image-utils": "^0.11.5", + "@expo/json-file": "^11.0.1", + "@react-native/normalize-colors": "0.86.3", + "debug": "^4.3.1", + "expo-modules-autolinking": "~57.0.13", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + } + }, + "node_modules/@expo/require-utils": { + "version": "57.0.5", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@expo/schema-utils": { + "version": "57.0.2", + "license": "MIT" + }, + "node_modules/@expo/sdk-runtime-versions": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/@expo/spawn-async": { + "version": "1.8.0", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@expo/sudo-prompt": { + "version": "9.3.2", + "license": "MIT" + }, + "node_modules/@expo/vector-icons": { + "version": "15.1.1", + "license": "MIT", + "peerDependencies": { + "expo-font": ">=14.0.4", + "react": "*", + "react-native": "*" + } + }, + "node_modules/@expo/xcpretty": { + "version": "4.4.5", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "chalk": "^4.1.0", + "js-yaml": "^4.1.0" + }, + "bin": { + "excpretty": "build/cli.js" + } + }, + "node_modules/@gql.tada/cli-utils": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@gql.tada/cli-utils/-/cli-utils-1.9.4.tgz", + "integrity": "sha512-xQ9M+2Xxjxhz9IJi+7IMU/aOsEtuSiSNb4OgDMBUC/8AcSpo2vDtx71Aodsaif4qSwuTb0YFVfDwC+ESqiZSHg==", + "license": "MIT", + "dependencies": { + "@0no-co/graphqlsp": "^1.17.3", + "@gql.tada/internal": "1.2.2", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0" + }, + "peerDependencies": { + "@0no-co/graphqlsp": "^1.16.0", + "@gql.tada/svelte-support": "1.0.3", + "@gql.tada/vue-support": "1.0.3", + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@gql.tada/svelte-support": { + "optional": true + }, + "@gql.tada/vue-support": { + "optional": true + } + } + }, + "node_modules/@gql.tada/internal": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@gql.tada/internal/-/internal-1.2.2.tgz", + "integrity": "sha512-4lZcElPP6MC8Ct8KN70LR2WQsHjbAsyAmTGG09VsOPhx738UFIYaL0S1XiI2pqq2tj/sDs/y3b9jvKoWGL7iuQ==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.3.1" + }, + "peerDependencies": { + "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mysten/bcs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-2.1.2.tgz", + "integrity": "sha512-fv6lyuZMTHN0xRlu4GYiV/UXUrdJDOHbXm1KfZYEU0sy/t+22yTrTVtWnAQv1Km7eyB3qHhwIrAG2aem4JMocw==", + "license": "Apache-2.0", + "dependencies": { + "@mysten/utils": "^0.4.1", + "@scure/base": "^2.3.0" + } + }, + "node_modules/@mysten/bcs/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/sui": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-2.34.0.tgz", + "integrity": "sha512-Qf/xt10YIJv3Yo0hQTU70xPgimFfw2mudBzI/dylGXZNuhuQVmkmxUm0fz49BFPOFvBxWc/MRFl204zwpwRnXw==", + "license": "Apache-2.0", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "@mysten/bcs": "^2.1.2", + "@mysten/utils": "^0.4.1", + "@noble/curves": "^2.3.0", + "@noble/hashes": "^2.3.0", + "@protobuf-ts/grpcweb-transport": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "@scure/base": "^2.3.0", + "@scure/bip32": "^2.3.0", + "@scure/bip39": "^2.3.0", + "gql.tada": "^1.11.3", + "graphql": "^17.0.2", + "poseidon-lite": "0.3.0", + "valibot": "^1.4.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@mysten/sui/node_modules/@noble/curves": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", + "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.4.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/sui/node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/sui/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/sui/node_modules/@scure/bip32": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.4.0.tgz", + "integrity": "sha512-i3DS0CptAocyvqE4n3SUkpzeQK4vJMFwWLofTwRiiKo2aWojBOfyMCgfKw9HVpO6fSY5AK86sHS/Uzn8kK9Few==", + "license": "MIT", + "dependencies": { + "@noble/curves": "2.4.0", + "@noble/hashes": "2.4.0", + "@scure/base": "2.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/sui/node_modules/@scure/bip39": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.4.0.tgz", + "integrity": "sha512-82dxFbZUYboyOf0AXiydsQrFQ5Q4h9mX+O2UkE91ROYmsc0BKMGZLwDmy96Jpa2+vrtoxomjUhy1RPIgH/r2nA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "2.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@mysten/utils": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@mysten/utils/-/utils-0.4.1.tgz", + "integrity": "sha512-gffLJ84CbqG/CcOPuVlwXIRu37tFn0BtUx7CQtbLwJzWjUE7FU2Gq8BXWjzxImnvufcyLTaNWtCPG6wq22Zhog==", + "license": "Apache-2.0", + "dependencies": { + "@scure/base": "^2.3.0" + } + }, + "node_modules/@mysten/utils/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@protobuf-ts/grpcweb-transport": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/grpcweb-transport/-/grpcweb-transport-2.11.1.tgz", + "integrity": "sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1" + } + }, + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "merge-options": "^3.0.4" + }, + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.65 <1.0" + } + }, + "node_modules/@react-native/assets-registry": { + "version": "0.86.3", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.86.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/hermes-estree": { + "version": "0.36.0", + "license": "MIT" + }, + "node_modules/@react-native/codegen/node_modules/hermes-parser": { + "version": "0.36.0", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.86.3", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.84.3", + "metro-config": "^0.84.3", + "metro-core": "^0.84.3", + "semver": "^7.1.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.86.3" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.86.3", + "license": "BSD-3-Clause", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/debugger-shell": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.86.3", + "@react-native/debugger-shell": "0.86.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.3.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.86.3", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.86.3", + "license": "MIT", + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.86.3", + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "0.86.3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.19.1", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" + }, + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/core": { + "version": "7.22.1", + "license": "MIT", + "dependencies": { + "@react-navigation/routers": "^7.6.4", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "react": ">= 18.2.0" + } + }, + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "19.3.0", + "license": "MIT" + }, + "node_modules/@react-navigation/elements": { + "version": "2.9.42", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } + } + }, + "node_modules/@react-navigation/native": { + "version": "7.4.1", + "license": "MIT", + "dependencies": { + "@react-navigation/core": "^7.22.1", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "standard-navigation": "^0.0.8", + "use-latest-callback": "^0.2.4" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" + } + }, + "node_modules/@react-navigation/native-stack": { + "version": "7.19.1", + "license": "MIT", + "dependencies": { + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0", + "warn-once": "^0.1.1" + }, + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" + } + }, + "node_modules/@react-navigation/routers": { + "version": "7.6.4", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "license": "MIT" + }, + "node_modules/@skur/sdk": { + "resolved": "../sdk", + "link": true + }, + "node_modules/@tanstack/query-core": { + "version": "5.102.8", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.102.8", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.102.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@types/emscripten": { + "version": "1.41.6", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "22.20.3", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "license": "ISC" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-cli-detector": { + "version": "0.1.7", + "license": "MIT", + "bin": { + "agent-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "license": "MIT" + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/asap": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/babel-plugin-react-native-web": { + "version": "0.21.2", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.0", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.0", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.0", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/badgin": { + "version": "1.2.3", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/barcode-detector": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "zxing-wasm": "3.1.3" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.24", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "stream-buffers": "2.2.x" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.1", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.3.0", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "destroy": "1.2.0", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/content-type": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "devOptional": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dnssd-advertise": { + "version": "1.1.6", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.429", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/expo": { + "version": "57.0.23", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "^57.0.25", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devtools": "~57.0.1", + "@expo/dom-webview": "~57.0.1", + "@expo/fingerprint": "^0.20.13", + "@expo/local-build-cache-provider": "^57.0.8", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~57.0.12", + "expo-asset": "~57.0.17", + "expo-constants": "~57.0.18", + "expo-file-system": "~57.0.7", + "expo-font": "~57.0.4", + "expo-keep-awake": "~57.0.2", + "expo-modules-autolinking": "~57.0.13", + "expo-modules-core": "~57.0.18", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-minimum": "^0.1.2" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-web": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-native-webview": { + "optional": true + } + } + }, + "node_modules/expo-application": { + "version": "57.0.3", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-camera": { + "version": "57.0.5", + "license": "MIT", + "dependencies": { + "barcode-detector": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "node_modules/expo-clipboard": { + "version": "57.0.2", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-constants": { + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.20.tgz", + "integrity": "sha512-WycPVvBgbluSa6yAh6DKnX646ZHrae0gV2ZLum5fioNkR+DiWyulq1+UfS++Jc6yfAh/l55NOirv6mt5cnQhSw==", + "license": "MIT", + "dependencies": { + "@expo/env": "~2.4.3" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-font": { + "version": "57.0.4", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-linking": { + "version": "57.0.10", + "license": "MIT", + "dependencies": { + "expo-constants": "~57.0.18", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-local-authentication": { + "version": "57.0.3", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-autolinking": { + "version": "57.0.13", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.1.0", + "commander": "^7.2.0" + }, + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + } + }, + "node_modules/expo-modules-core": { + "version": "57.0.18", + "license": "MIT", + "dependencies": { + "@expo/expo-modules-macros-plugin": "0.6.1", + "expo-modules-jsi": "~57.1.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" + }, + "peerDependenciesMeta": { + "react-native-worklets": { + "optional": true + } + } + }, + "node_modules/expo-modules-jsi": { + "version": "57.1.0", + "license": "MIT", + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/expo-notifications": { + "version": "57.0.19", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "abort-controller": "^3.0.0", + "badgin": "^1.1.5", + "expo-application": "~57.0.3", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-secure-store": { + "version": "57.0.4", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-server": { + "version": "57.0.3", + "license": "MIT", + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/expo-status-bar": { + "version": "57.0.1", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/cli": { + "version": "57.0.25", + "license": "MIT", + "dependencies": { + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.4.3", + "@expo/image-utils": "^0.11.5", + "@expo/inline-modules": "^0.1.7", + "@expo/json-file": "^11.0.1", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@expo/metro-file-map": "^57.0.3", + "@expo/osascript": "^2.7.1", + "@expo/package-manager": "^1.13.1", + "@expo/plist": "^0.8.1", + "@expo/prebuild-config": "^57.0.16", + "@expo/require-utils": "^57.0.5", + "@expo/router-server": "^57.0.10", + "@expo/schema-utils": "^57.0.2", + "@expo/spawn-async": "^1.8.0", + "@expo/ws-tunnel": "^2.0.0", + "@expo/xcpretty": "^4.4.4", + "@react-native/dev-middleware": "0.86.3", + "accepts": "^1.3.8", + "agent-cli-detector": "0.1.7", + "arg": "^5.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "dnssd-advertise": "^1.1.4", + "expo-server": "^57.0.3", + "fetch-nodeshim": "^0.4.10", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.2.1", + "multitars": "^1.0.2", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^4.0.4", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "resolve-from": "^5.0.0", + "sandbox-cli-detector": "^0.2.0", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "terminal-link": "^2.1.1", + "toqr": "^0.1.1", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1", + "zod": "^3.25.76" + }, + "bin": { + "expo-internal": "main.js" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { + "version": "57.0.10", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "@expo/metro-runtime": "^57.0.15", + "expo": "*", + "expo-constants": "^57.0.18", + "expo-font": "^57.0.4", + "expo-router": "*", + "expo-server": "^57.0.3", + "react": "*", + "react-dom": "*", + "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" + }, + "peerDependenciesMeta": { + "@expo/metro-runtime": { + "optional": true + }, + "expo-router": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/dom-webview": { + "version": "57.0.1", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/log-box": { + "version": "57.0.4", + "license": "MIT", + "dependencies": { + "@expo/dom-webview": "^57.0.1", + "anser": "^1.4.9", + "stacktrace-parser": "^0.1.10" + }, + "peerDependencies": { + "@expo/dom-webview": "^57.0.1", + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/metro-config": { + "version": "57.0.12", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~57.0.9", + "@expo/env": "~2.4.3", + "@expo/json-file": "~11.0.1", + "@expo/metro": "~56.0.2", + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.36.0", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/ws-tunnel": { + "version": "2.0.0", + "license": "MIT", + "peerDependencies": { + "ws": "^8.0.0" + } + }, + "node_modules/expo/node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/babel-preset-expo": { + "version": "57.0.12", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^57.0.19", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/ci-info": { + "version": "3.9.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expo/node_modules/expo-asset": { + "version": "57.0.17", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-file-system": { + "version": "57.0.7", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-keep-awake": { + "version": "57.0.2", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "node_modules/expo/node_modules/hermes-estree": { + "version": "0.36.1", + "license": "MIT" + }, + "node_modules/expo/node_modules/hermes-parser": { + "version": "0.36.1", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "node_modules/expo/node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/picomatch": { + "version": "4.0.7", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/expo/node_modules/ws": { + "version": "8.21.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "license": "Apache-2.0" + }, + "node_modules/fast-base64-decode": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "license": "(MIT OR Apache-2.0)", + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fetch-nodeshim": { + "version": "0.4.10", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "license": "MIT" + }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "license": "BSD-2-Clause" + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/getenv": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gql.tada": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.11.4.tgz", + "integrity": "sha512-UQnhJUhSM0MV8cpcgjci/7ET8LnmHx9o9FtZqU4sH+ILiBVG5rnfXJzNdzTN+Y7MuCz6Pp3XE/VPEVqmO969jw==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.3.2", + "@0no-co/graphqlsp": "^1.17.3", + "@gql.tada/cli-utils": "1.9.4", + "@gql.tada/internal": "1.2.2" + }, + "bin": { + "gql-tada": "bin/cli.js", + "gql.tada": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphql": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-17.0.2.tgz", + "integrity": "sha512-FRWbddMxfkjiB7z+aQDWIR+E34xo9I8c9mtK2RPv8PmMzKRvrdsreHL/Ui/TmwHJfhHChEtsFPyMHKI+xuarQQ==", + "license": "MIT", + "engines": { + "node": "^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-compiler": { + "version": "250829098.0.17", + "license": "MIT" + }, + "node_modules/hermes-estree": { + "version": "0.35.0", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.35.0", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "license": "ISC" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jimp-compact": { + "version": "0.16.1", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "license": "0BSD" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lan-network": { + "version": "0.2.1", + "license": "MIT", + "bin": { + "lan-network": "dist/lan-network-cli.js" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "license": "Apache-2.0" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "license": "MIT" + }, + "node_modules/merge-options": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/metro": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.35.0", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-cache": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.84.5" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-cache-key": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.5", + "metro-cache": "0.84.5", + "metro-core": "0.84.5", + "metro-runtime": "0.84.5", + "yaml": "^2.6.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-core": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.84.5" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-file-map": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-resolver": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-runtime": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-source-map": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.84.5", + "nullthrows": "^1.1.1", + "ob1": "0.84.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.84.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-source-map": "0.84.5", + "metro-transform-plugins": "0.84.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" + }, + "node_modules/multitars": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.19", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.55", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.3", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/ob1": { + "version": "0.84.5", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/open": { + "version": "7.4.2", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "3.4.0", + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-regex": { + "version": "4.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "3.2.1", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "1.9.3", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.3", + "license": "MIT" + }, + "node_modules/ora/node_modules/escape-string-regexp": { + "version": "1.0.5", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ora/node_modules/has-flag": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "5.2.0", + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "5.5.0", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-png": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "pngjs": "^3.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.2", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/plist": { + "version": "3.1.1", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.9.10", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/plist/node_modules/@xmldom/xmldom": { + "version": "0.9.12", + "license": "MIT", + "engines": { + "node": ">=14.6" + } + }, + "node_modules/pngjs": { + "version": "3.4.0", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/poseidon-lite": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/poseidon-lite/-/poseidon-lite-0.3.0.tgz", + "integrity": "sha512-ilJj4MIve4uBEG7SrtPqUUNkvpJ/pLVbndxa0WvebcQqeIhe+h72JR4g0EvwchUzm9sOQDlOjiDNmRAgxNZl4A==", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.28", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "4.2.0", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise": { + "version": "8.3.0", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/react": { + "version": "19.2.3", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-freeze": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=17.0.0" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@react-native/assets-registry": "0.86.3", + "@react-native/codegen": "0.86.3", + "@react-native/community-cli-plugin": "0.86.3", + "@react-native/gradle-plugin": "0.86.3", + "@react-native/js-polyfills": "0.86.3", + "@react-native/normalize-colors": "0.86.3", + "@react-native/virtualized-lists": "0.86.3", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-plugin-syntax-hermes-parser": "0.36.0", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "hermes-compiler": "250829098.0.17", + "invariant": "^2.2.4", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.84.3", + "metro-source-map": "^0.84.3", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.27.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", + "whatwg-fetch": "^3.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native/jest-preset": "0.86.3", + "@types/react": "^19.1.1", + "react": "^19.2.3" + }, + "peerDependenciesMeta": { + "@react-native/jest-preset": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-get-random-values": { + "version": "1.11.0", + "license": "MIT", + "dependencies": { + "fast-base64-decode": "^1.0.0" + }, + "peerDependencies": { + "react-native": ">=0.56" + } + }, + "node_modules/react-native-safe-area-context": { + "version": "5.7.0", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-screens": { + "version": "4.26.2", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "license": "MIT" + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.2", + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-workspace-root": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sandbox-cli-detector": { + "version": "0.2.0", + "license": "MIT", + "bin": { + "sandbox-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/sax": { + "version": "1.6.1", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "license": "ISC" + }, + "node_modules/sf-symbols-typescript": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "license": "ISC" + }, + "node_modules/simple-plist": { + "version": "1.3.1", + "license": "MIT", + "dependencies": { + "bplist-creator": "0.1.0", + "bplist-parser": "0.3.1", + "plist": "^3.0.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "license": "MIT" + }, + "node_modules/slugify": { + "version": "1.6.9", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/standard-navigation": { + "version": "0.0.8", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-buffers": { + "version": "2.2.0", + "license": "Unlicense", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/structured-headers": { + "version": "0.4.1", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.51.2", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "license": "MIT" + }, + "node_modules/throat": { + "version": "5.0.0", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.7", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toqr": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/type-fest": { + "version": "0.7.1", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-latest-callback": { + "version": "0.2.6", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.7.0", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "7.0.3", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/valibot": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.5.0.tgz", + "integrity": "sha512-nil6AkP2TChWL43Z5uJ6GTxX01CUA+g8LWUM+N/rB9NBbkUMaUsi9PUNzlUPgoKASgmx9f7eGOYpJ04/fSa6FQ==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/warn-once": { + "version": "0.1.1", + "license": "MIT" + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "license": "MIT" + }, + "node_modules/whatwg-url-minimum": { + "version": "0.1.2", + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/ws": { + "version": "7.5.13", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xcode": { + "version": "3.0.1", + "license": "Apache-2.0", + "dependencies": { + "simple-plist": "^1.1.0", + "uuid": "^7.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.6.0", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.1", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "17.7.3", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zxing-wasm": { + "version": "3.1.3", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.41.5", + "type-fest": "^5.8.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } + }, + "node_modules/zxing-wasm/node_modules/type-fest": { + "version": "5.9.0", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/mobile/package.json b/mobile/package.json new file mode 100644 index 0000000..402335a --- /dev/null +++ b/mobile/package.json @@ -0,0 +1,45 @@ +{ + "name": "@skur/mobile", + "version": "1.0.0", + "main": "index.ts", + "private": true, + "scripts": { + "sdk": "npm --prefix ../sdk run --silent build", + "start": "npm run sdk && expo start", + "ios": "npm run sdk && expo run:ios", + "android": "npm run sdk && expo run:android", + "typecheck": "npm run sdk && tsc --noEmit" + }, + "dependencies": { + "@expo-google-fonts/dm-mono": "^0.4.2", + "@expo-google-fonts/dm-sans": "^0.4.2", + "@expo-google-fonts/space-grotesk": "^0.4.1", + "@expo/vector-icons": "^15.0.2", + "@mysten/sui": "^2.34.0", + "@react-native-async-storage/async-storage": "2.2.0", + "@react-navigation/bottom-tabs": "^7.19.1", + "@react-navigation/native": "^7.4.1", + "@react-navigation/native-stack": "^7.19.1", + "@skur/sdk": "file:../sdk", + "@tanstack/react-query": "^5.102.8", + "expo": "~57.0.23", + "expo-camera": "~57.0.5", + "expo-clipboard": "~57.0.2", + "expo-constants": "^57.0.20", + "expo-font": "~57.0.4", + "expo-linking": "~57.0.10", + "expo-local-authentication": "~57.0.3", + "expo-notifications": "~57.0.19", + "expo-secure-store": "~57.0.4", + "expo-status-bar": "~57.0.1", + "react": "19.2.3", + "react-native": "0.86.3", + "react-native-get-random-values": "~1.11.0", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0" + }, + "devDependencies": { + "@types/react": "~19.2.2", + "typescript": "~6.0.3" + } +} diff --git a/mobile/src/components/Identicon.tsx b/mobile/src/components/Identicon.tsx new file mode 100644 index 0000000..e16598f --- /dev/null +++ b/mobile/src/components/Identicon.tsx @@ -0,0 +1,38 @@ +import { useMemo } from "react"; +import { useTheme } from "../state/theme"; +import { Text, View } from "react-native"; +import { F } from "../theme"; + +/** A deterministic blocky avatar, drawn with views. + * + * A Sui address is already the output of a hash, so its hex is used directly as the entropy — + * hashing it again would add a dependency and no information. */ +export function Identicon({ address, size = 40, badge }: { address: string; size?: number; badge?: string }) { + const C = useTheme(); + const { cells, fg, bg } = useMemo(() => { + const hash = address.toLowerCase().replace(/^0x/, '').padEnd(64, '0'); + const hue = parseInt(hash.slice(0, 4), 16) % 360; + const hue2 = (hue + 140) % 360; + const bits = hash.slice(4); + const cells: boolean[] = []; + for (let y = 0; y < 5; y++) { + const row: boolean[] = []; + for (let x = 0; x < 3; x++) row.push(parseInt(bits[(y * 3 + x) % bits.length], 16) % 3 !== 0); + cells.push(row[0], row[1], row[2], row[1], row[0]); + } + return { cells, fg: `hsl(${hue}, 70%, 45%)`, bg: `hsl(${hue2}, 60%, 88%)` }; + }, [address]); + const unit = size / 5; + return ( + + + {cells.map((on, i) => )} + + {badge ? ( + + {badge} + + ) : null} + + ); +} diff --git a/mobile/src/components/TokenMark.tsx b/mobile/src/components/TokenMark.tsx new file mode 100644 index 0000000..5031e40 --- /dev/null +++ b/mobile/src/components/TokenMark.tsx @@ -0,0 +1,48 @@ +import { Text, View } from 'react-native'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; + +/** A coin type's struct name is what a person recognises; the rest is address noise. */ +export function coinSymbol(coinType: string): string { + return (coinType.split('::').pop() ?? coinType).toUpperCase(); +} + +const DECIMALS: Record = { SUI: 9, USDC: 6, USDT: 6, USDSUI: 6 }; + +export function coinDecimals(coinType: string): number { + return DECIMALS[coinSymbol(coinType)] ?? 9; +} + +/** Deterministic colour per symbol, so the same asset looks the same on every screen. */ +const TINTS: [string, string][] = [ + ['#4da2ff', '#0b1f36'], + ['#2775ca', '#06182e'], + ['#26a17b', '#05261c'], + ['#8b5cf6', '#1b0f33'], +]; + +export function TokenMark({ coinType, size = 32 }: { coinType: string; size?: number }) { + const C = useTheme(); + const symbol = coinSymbol(coinType); + let n = 0; + for (let i = 0; i < symbol.length; i++) n = (n + symbol.charCodeAt(i)) % TINTS.length; + const [bg, fg] = TINTS[n]; + return ( + + + {symbol.slice(0, 2)} + + + ); +} diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx new file mode 100644 index 0000000..1ceae7d --- /dev/null +++ b/mobile/src/components/ui.tsx @@ -0,0 +1,313 @@ +import { Feather } from "@expo/vector-icons"; +import * as Clipboard from "expo-clipboard"; +import { forwardRef, useState, type ComponentProps, type ReactNode } from "react"; +import { ActivityIndicator, Modal, Pressable, ScrollView, StyleSheet, Text, TextInput, View, type StyleProp, type TextInputProps, type ViewStyle } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { + MODE_LABELS, + Mode, + STATUS_LABELS, + Status, + TIER_LABELS, + Tier, + TRUST_LABELS, + Trust, + short, +} from "@skur/sdk"; +import type { TxState } from "../hooks/useTx"; +import { useTheme } from "../state/theme"; +import { F, R, type Palette } from "../theme"; + +export type IconName = ComponentProps["name"]; +export function Icon({ name, size = 18, color }: { name: IconName; size?: number; color?: string }) { + const C = useTheme(); + return ; +} + +export function Screen({ children, top, footer, refreshControl, padded = true }: { children: ReactNode; top?: ReactNode; footer?: ReactNode; refreshControl?: ReactNode; padded?: boolean }) { + const C = useTheme(); const s = useStyles(); const insets = useSafeAreaInsets(); + return ( + + {top ? {top} : null} + {children} + {footer ? {footer} : null} + + ); +} + +export function TopBar({ left, center, right, title }: { left?: ReactNode; center?: ReactNode; right?: ReactNode; title?: string }) { + const s = useStyles(); + return ( + + {left}{title ? {title} : null} + {center ? {center} : null} + {right} + + ); +} + +export function IconButton({ name, onPress, dot, tone = "dark", label }: { name: IconName; onPress?: () => void; dot?: boolean; tone?: "dark" | "accent"; label?: string }) { + const C = useTheme(); const s = useStyles(); + return ( + [s.iconBtn, tone === "accent" && { backgroundColor: C.accent }, pressed && { opacity: 0.6 }]}> + + {dot ? : null} + + ); +} + +export function BackButton({ onPress }: { onPress: () => void }) { return ; } + +/** The web logo: a yellow tile with an S, then the wordmark. */ +export function Logo({ size = 28, wordmark = true }: { size?: number; wordmark?: boolean }) { + const C = useTheme(); + return ( + + + S + + {wordmark ? Skur : null} + + ); +} + +/** A card that opens on tap: the header carries the value, so a long screen reads as a short list. */ +export function Expandable({ title, summary, icon, tone = "dark", children, open, onToggle }: { title: string; summary?: string; icon?: IconName; tone?: Tone; children: ReactNode; open: boolean; onToggle: () => void }) { + const C = useTheme(); const s = useStyles(); + return ( + + [{ flexDirection: "row", alignItems: "center", gap: 12, padding: 16 }, pressed && { opacity: 0.6 }]}> + {icon ? : null} + + {title} + {summary ? {summary} : null} + + + + {open ? {children} : null} + + ); +} + +export function Card({ children, style, flush = false }: { children: ReactNode; style?: StyleProp; flush?: boolean }) { + const s = useStyles(); + return {children}; +} +export function SectionLabel({ children }: { children: ReactNode }) { const s = useStyles(); return {children}; } + +/** The list row every screen is built from: leading mark, title, value, chevron. */ +export function Row({ leading, title, subtitle, trailing, onPress, chevron = false, last = false }: { leading?: ReactNode; title: ReactNode; subtitle?: ReactNode; trailing?: ReactNode; onPress?: () => void; chevron?: boolean; last?: boolean }) { + const C = useTheme(); const s = useStyles(); + const body = ( + + {leading ? {leading} : null} + + {typeof title === "string" ? {title} : title} + {subtitle ? (typeof subtitle === "string" ? {subtitle} : subtitle) : null} + + {trailing} + {chevron ? : null} + + ); + return onPress ? pressed && { opacity: 0.6 }}>{body} : body; +} + +type Tone = "ok" | "warn" | "bad" | "info" | "neutral" | "accent" | "dark" | "success" | "error"; +function tones(C: Palette): Record { + return { + ok: { bg: C.successBg, fg: C.success }, success: { bg: C.successBg, fg: C.success }, + warn: { bg: C.warningBg, fg: C.warning }, bad: { bg: C.errorBg, fg: C.error }, error: { bg: C.errorBg, fg: C.error }, + info: { bg: C.infoBg, fg: C.info }, neutral: { bg: C.card2, fg: C.text2 }, dark: { bg: C.card2, fg: C.text }, + accent: { bg: C.accent, fg: C.onAccent }, + }; +} + +export function CircleIcon({ name, size = 40, tone = "dark", text }: { name?: IconName; size?: number; tone?: Tone; text?: string }) { + const C = useTheme(); const t = tones(C)[tone]; + return ( + + {text ? {text} : name ? : null} + + ); +} + +export function KV({ k, v, mono = false, last = false }: { k: string; v: ReactNode; mono?: boolean; last?: boolean }) { + const s = useStyles(); + return ( + + {k} + {typeof v === "string" || typeof v === "number" ? {v} : v} + + ); +} + +export function Badge({ tone = "neutral", children, icon }: { tone?: Tone; children: ReactNode; icon?: IconName }) { + const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; + return {icon ? : null}{children}; +} +export const TierBadge = ({ tier }: { tier: Tier }) => {TIER_LABELS[tier]}; +export const ModeBadge = ({ mode }: { mode: Mode }) => {MODE_LABELS[mode]}; +export const StatusBadge = ({ status }: { status: Status }) => {STATUS_LABELS[status]}; +export const TrustBadge = ({ trust }: { trust: Trust }) => {TRUST_LABELS[trust]}; + +export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md" }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm" }) { + const C = useTheme(); const s = useStyles(); + const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.card2 : "transparent"; + const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; + return ( + [s.btn, size === "sm" && { height: 36, paddingHorizontal: 14 }, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, style]}> + {loading ? : <>{icon ? : null}{children}} + + ); +} + +/** The sticky primary action: what you are about to sign, and with which key. */ +export function SignBar({ label, signerAddress, onPress, disabled, loading, hint }: { label: string; signerAddress?: string | null; onPress?: () => void; disabled?: boolean; loading?: boolean; hint?: string }) { + const C = useTheme(); const s = useStyles(); + return ( + + {hint ? {hint} : null} + [s.signbar, { opacity: disabled ? 0.45 : pressed ? 0.85 : 1 }]}> + {loading ? : } + {label} + {signerAddress ? {short(signerAddress)} : null} + + + + ); +} + +export function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { + const s = useStyles(); + return ( + + {label} + {children} + {hint ? {hint} : null} + + ); +} + +export const Input = forwardRef(function Input(props, ref) { + const C = useTheme(); const s = useStyles(); + return ; +}); + +export function Tabs({ value, options, onChange }: { value: T; options: Array<[T, string]>; onChange: (v: T) => void }) { + const C = useTheme(); const s = useStyles(); + return ( + + {options.map(([v, label]) => ( + onChange(v)} style={[s.tab, value === v && { borderBottomColor: C.accent }]}>{label} + ))} + + ); +} + +export function Address({ value, full = false, style }: { value: string; full?: boolean; style?: object }) { + const C = useTheme(); const s = useStyles(); + const [copied, setCopied] = useState(false); + return ( + { await Clipboard.setStringAsync(value); setCopied(true); setTimeout(() => setCopied(false), 1200); }} hitSlop={8} style={{ flexDirection: "row", alignItems: "center", gap: 6 }}> + {full ? value : short(value)} + + + ); +} + +export function Notice({ tone = "info", children }: { tone?: Tone; children: ReactNode }) { + const C = useTheme(); const s = useStyles(); const t = tones(C)[tone]; + return {children}; +} + +export function TxStatus({ state }: { state: TxState }) { + if (state.phase === "idle") return null; + // A declined fingerprint is a decision, not a failure. + if (state.phase === "cancelled") return Cancelled.; + if (state.phase === "error") return {state.message}; + if (state.phase === "done") return Executed · {short(state.digest, 6)}; + const msg = + state.phase === "unlocking" + ? "Waiting for you to unlock the key…" + : state.phase === "signing" + ? "Signing and sending…" + : "Waiting for the network to settle it…"; + return {msg}; +} + +export function Empty({ icon = "inbox", children }: { icon?: IconName; children: ReactNode }) { + const C = useTheme(); + return {children}; +} + +/** Caution tape: the brand's mark, used only where the vault is not in Normal mode. */ +export function Tape({ height = 8 }: { height?: number }) { + const C = useTheme(); + return ( + + {Array.from({ length: 34 }).map((_, i) => )} + + ); +} + +export function Sheet({ open, onClose, title, children, action }: { open: boolean; onClose: () => void; title: string; children: ReactNode; action?: ReactNode }) { + const s = useStyles(); const insets = useSafeAreaInsets(); + return ( + + + + + + {title} + {action ? {action} : null} + + {children} + + + ); +} + +const makeStyles = (C: Palette) => StyleSheet.create({ + screen: { flex: 1, backgroundColor: C.canvas }, + topbar: { height: 52, paddingHorizontal: 16, flexDirection: "row", alignItems: "center", justifyContent: "space-between" }, + topTitle: { fontFamily: F.display, fontSize: 22, color: C.text, letterSpacing: -0.3 }, + iconBtn: { width: 40, height: 40, borderRadius: 20, backgroundColor: C.card, alignItems: "center", justifyContent: "center" }, + dot: { position: "absolute", top: 8, right: 8, width: 8, height: 8, borderRadius: 4, backgroundColor: C.accent, borderWidth: 1.5, borderColor: C.canvas }, + footer: { position: "absolute", left: 0, right: 0, bottom: 0, padding: 16, backgroundColor: C.canvas, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: C.border }, + card: { backgroundColor: C.card, borderRadius: R.lg, padding: 16, marginBottom: 12 }, + sectionLabel: { fontFamily: F.mono, fontSize: 11, letterSpacing: 1.2, textTransform: "uppercase", color: C.text3, marginBottom: 8, marginTop: 8 }, + row: { flexDirection: "row", alignItems: "center", gap: 12, paddingVertical: 13, paddingHorizontal: 16, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + rowTitle: { fontFamily: F.bodyBold, fontSize: 15, color: C.text }, + rowSub: { fontFamily: F.body, fontSize: 13, color: C.text2 }, + kv: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", gap: 12, paddingVertical: 11, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border }, + kvK: { fontFamily: F.body, fontSize: 14, color: C.text2 }, + kvV: { fontFamily: F.bodyMedium, fontSize: 14, color: C.text, textAlign: "right", flexShrink: 1 }, + badge: { flexDirection: "row", alignItems: "center", gap: 5, paddingHorizontal: 9, paddingVertical: 4, borderRadius: R.pill, alignSelf: "flex-start" }, + badgeText: { fontFamily: F.bodyBold, fontSize: 12 }, + btn: { height: 48, borderRadius: R.md, alignItems: "center", justifyContent: "center", paddingHorizontal: 18, flexDirection: "row", gap: 8 }, + btnText: { fontFamily: F.bodyBold, fontSize: 15 }, + signbar: { height: 56, borderRadius: R.lg, backgroundColor: C.accent, flexDirection: "row", alignItems: "center", gap: 10, paddingHorizontal: 18 }, + signbarText: { fontFamily: F.bodyBold, fontSize: 16, color: C.onAccent, flex: 1 }, + signerChip: { backgroundColor: "rgba(16,20,24,0.12)", borderRadius: R.pill, paddingHorizontal: 10, height: 28, justifyContent: "center" }, + signerChipText: { fontFamily: F.monoMedium, fontSize: 12, color: C.onAccent }, + label: { fontFamily: F.bodyMedium, fontSize: 13, color: C.text2, marginBottom: 6 }, + hint: { fontFamily: F.body, fontSize: 12, color: C.text3, marginTop: 6, lineHeight: 16 }, + input: { backgroundColor: C.card2, borderRadius: R.md, paddingHorizontal: 14, height: 48, color: C.text, fontFamily: F.body, fontSize: 15, borderWidth: 1, borderColor: C.border }, + tabs: { flexDirection: "row", borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: C.border, marginBottom: 4 }, + tab: { paddingVertical: 10, paddingHorizontal: 4, marginRight: 22, borderBottomWidth: 2, borderBottomColor: "transparent" }, + tabText: { fontFamily: F.bodyBold, fontSize: 15, color: C.text3 }, + addr: { fontFamily: F.mono, fontSize: 13, color: C.text2 }, + notice: { padding: 12, borderRadius: R.md, marginTop: 10 }, + sheetBackdrop: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)" }, + sheet: { backgroundColor: C.card, borderTopLeftRadius: 22, borderTopRightRadius: 22, paddingHorizontal: 16, paddingTop: 8 }, + grabber: { width: 40, height: 4, borderRadius: 2, backgroundColor: C.border, alignSelf: "center", marginBottom: 14 }, + sheetTitle: { fontFamily: F.display, fontSize: 18, color: C.text }, +}); + +const cache = new Map>(); +/** Styles for the ground currently in use, built once per palette. */ +export function useStyles() { + const C = useTheme(); + if (!cache.has(C.canvas)) cache.set(C.canvas, makeStyles(C)); + return cache.get(C.canvas)!; +} diff --git a/mobile/src/hooks/useTx.ts b/mobile/src/hooks/useTx.ts new file mode 100644 index 0000000..e348bcd --- /dev/null +++ b/mobile/src/hooks/useTx.ts @@ -0,0 +1,77 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { useCallback, useState } from 'react'; +import type { Transaction } from '@mysten/sui/transactions'; +import { describeFailure } from '@skur/sdk'; +import { client } from '../lib/client'; +import { NETWORK } from '../lib/config'; +import { unlockSigner } from '../lib/keystore'; + +export type TxState = + | { phase: 'idle' } + | { phase: 'unlocking' } + | { phase: 'signing' } + | { phase: 'waiting'; digest: string } + | { phase: 'done'; digest: string } + | { phase: 'error'; message: string } + | { phase: 'cancelled' }; + +/** + * Sign and execute, with the key unlocked for exactly one action. + * + * The biometric prompt is per transaction, not per session. A cached signer is a signer that acts + * without a face, which on a treasury app is the whole thing you were trying to avoid. + */ +export function useTx(vaultId: string | null) { + const queryClient = useQueryClient(); + const [state, setState] = useState({ phase: 'idle' }); + + const run = useCallback( + async (build: () => Transaction, reason: string): Promise => { + try { + setState({ phase: 'unlocking' }); + const keypair = await unlockSigner(reason); + + setState({ phase: 'signing' }); + const result = await client.signAndExecuteTransaction({ + transaction: build(), + signer: keypair, + include: { effects: true }, + }); + + // A resolved promise means the network executed it, not that it succeeded: a Move abort + // comes back as FailedTransaction. + if (result.FailedTransaction) { + const message = describeFailure( + result.FailedTransaction.status.error?.message ?? 'the vault refused it', + ); + setState({ phase: 'error', message }); + return null; + } + + const digest = result.Transaction.digest; + setState({ phase: 'waiting', digest }); + await client.core.waitForTransaction({ digest }); + + await queryClient.invalidateQueries({ queryKey: ['vault', NETWORK, vaultId] }); + await queryClient.invalidateQueries({ queryKey: ['preview', NETWORK, vaultId] }); + setState({ phase: 'done', digest }); + return digest; + } catch (e) { + const raw = e instanceof Error ? e.message : String(e); + // A declined fingerprint is not an error worth a red banner. + if (raw === 'cancelled') { + setState({ phase: 'cancelled' }); + return null; + } + setState({ phase: 'error', message: describeFailure(e) }); + return null; + } + }, + [queryClient, vaultId], + ); + + const reset = useCallback(() => setState({ phase: 'idle' }), []); + const busy = state.phase === 'unlocking' || state.phase === 'signing' || state.phase === 'waiting'; + + return { run, state, reset, busy }; +} diff --git a/mobile/src/hooks/useVault.ts b/mobile/src/hooks/useVault.ts new file mode 100644 index 0000000..7f0544c --- /dev/null +++ b/mobile/src/hooks/useVault.ts @@ -0,0 +1,65 @@ +import { useQuery } from '@tanstack/react-query'; +import { + fetchVaultView, + previewTransfer, + type TransferPreview, + type VaultView, +} from '@skur/sdk'; +import { client } from '../lib/client'; +import { NETWORK, PACKAGE_ID } from '../lib/config'; + +/** Everything one screen needs, read from the chain. */ +export function useVaultView(vaultId: string | null) { + return useQuery({ + queryKey: ['vault', NETWORK, vaultId], + enabled: Boolean(vaultId), + // A vault is a shared object, so anyone's write changes it. Short freshness, and a poll + // slow enough that the screen does not look like it is reloading constantly. + staleTime: 5_000, + refetchInterval: 20_000, + retry: 1, + queryFn: () => fetchVaultView(client, vaultId!), + }); +} + +/** + * What the vault itself will demand for this payment. + * + * Simulated against the chain's own `preview_transfer`, not computed here, so the confirmation + * screen cannot promise something execution would refuse. + */ +export function useTransferPreview(input: { + vaultId: string | null; + coinType: string; + amount: bigint; + recipient: string; + sender: string | null; + enabled: boolean; +}) { + return useQuery({ + queryKey: [ + 'preview', + NETWORK, + input.vaultId, + input.coinType, + input.amount.toString(), + input.recipient, + ], + enabled: + input.enabled && + Boolean(input.vaultId && input.sender && input.coinType) && + input.amount > 0n, + staleTime: 10_000, + refetchInterval: false, + retry: 0, + queryFn: () => + previewTransfer(client, { + packageId: PACKAGE_ID, + vaultId: input.vaultId!, + coinType: input.coinType, + amount: input.amount, + recipient: input.recipient, + sender: input.sender!, + }), + }); +} diff --git a/mobile/src/lib/client.ts b/mobile/src/lib/client.ts new file mode 100644 index 0000000..057c9fe --- /dev/null +++ b/mobile/src/lib/client.ts @@ -0,0 +1,12 @@ +import './polyfills'; +import { SuiGrpcClient } from '@mysten/sui/grpc'; +import { GRPC_URL, NETWORK } from './config'; + +/** + * One client for the app. + * + * gRPC, not JSON-RPC: Sui switched JSON-RPC off on mainnet full nodes in July 2026 and is + * removing it entirely. The default transport is gRPC-web over fetch, which is what React Native + * can actually do — there is no HTTP/2 socket to reach for here. + */ +export const client = new SuiGrpcClient({ network: NETWORK, baseUrl: GRPC_URL }); diff --git a/mobile/src/lib/config.ts b/mobile/src/lib/config.ts new file mode 100644 index 0000000..585ea04 --- /dev/null +++ b/mobile/src/lib/config.ts @@ -0,0 +1,23 @@ +import Constants from 'expo-constants'; +import { GRPC_ENDPOINTS, type Network } from '@skur/sdk'; + +/** + * Where this build points. `EXPO_PUBLIC_*` wins, then app.json's `extra`, then the defaults — + * so a developer can point a build at their own publish without editing a committed file. + */ +const extra = (Constants.expoConfig?.extra ?? {}) as Record; + +function setting(key: string, fallback: string): string { + return process.env[`EXPO_PUBLIC_${key}`] ?? extra[key] ?? fallback; +} + +export const NETWORK = setting('SKUR_NETWORK', 'testnet') as Network; +export const PACKAGE_ID = setting('SKUR_PACKAGE_ID', '0x0'); +export const GRPC_URL = setting('SKUR_GRPC_URL', GRPC_ENDPOINTS[NETWORK]); +/** The indexer. Optional: every screen reads the chain directly without it. */ +export const API_URL = setting('SKUR_API', ''); + +export const CONFIGURED = PACKAGE_ID !== '0x0'; + +export const explorer = (kind: 'object' | 'tx', id: string) => + `https://suiscan.xyz/${NETWORK}/${kind}/${id}`; diff --git a/mobile/src/lib/keystore.ts b/mobile/src/lib/keystore.ts new file mode 100644 index 0000000..181e229 --- /dev/null +++ b/mobile/src/lib/keystore.ts @@ -0,0 +1,117 @@ +import * as LocalAuthentication from 'expo-local-authentication'; +import * as SecureStore from 'expo-secure-store'; +import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; +import { decodeSuiPrivateKey } from '@mysten/sui/cryptography'; + +/** + * The signing key, held in the device's secure element behind biometrics. + * + * Be clear about what this is. A key on a phone is a **hot key**: it is appropriate for an + * approver or an executor, who need to act often and whose authority is bounded by the vault's + * policy. It is **not** appropriate for a guardian, whose entire value is being an independent + * control plane an attacker has to breach separately — a guardian key belongs on hardware or on a + * machine that is not also reading email. The app says so where it matters, because a guardian + * key on the same phone as an approver key collapses the two planes the contract works to keep + * apart. + * + * What the device gives us: the secret is written to the iOS keychain or Android keystore, not to + * app storage, and `requireAuthentication` means the OS will not release it without a successful + * biometric or passcode check. What it does not give us: protection from a rooted or jailbroken + * device, and no recovery if the device is lost — which is what the vault's guardian recovery is + * for. + */ +const KEY = 'skur.signer.v1'; + +const OPTIONS: SecureStore.SecureStoreOptions = { + requireAuthentication: true, + keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, + authenticationPrompt: 'Unlock your Skur signing key', +}; + +export type BiometricSupport = { + available: boolean; + enrolled: boolean; + /** What the device calls it, so the UI does not promise Face ID on a fingerprint phone. */ + label: string; +}; + +export async function biometricSupport(): Promise { + const [available, enrolled, types] = await Promise.all([ + LocalAuthentication.hasHardwareAsync(), + LocalAuthentication.isEnrolledAsync(), + LocalAuthentication.supportedAuthenticationTypesAsync(), + ]); + const label = types.includes(LocalAuthentication.AuthenticationType.FACIAL_RECOGNITION) + ? 'Face ID' + : types.includes(LocalAuthentication.AuthenticationType.FINGERPRINT) + ? 'fingerprint' + : 'device passcode'; + return { available, enrolled, label }; +} + +export async function hasSigner(): Promise { + // Checked without `requireAuthentication`, so merely asking whether a key exists does not + // prompt for a face. + const stored = await SecureStore.getItemAsync(KEY, { + keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, + }).catch(() => null); + return Boolean(stored); +} + +/** Generate a key and store it. Refuses to overwrite one that already exists. */ +export async function createSigner(): Promise { + if (await hasSigner()) throw new Error('a signing key already exists on this device'); + const keypair = Ed25519Keypair.generate(); + await SecureStore.setItemAsync(KEY, keypair.getSecretKey(), OPTIONS); + return keypair.toSuiAddress(); +} + +/** Import an existing key, so a signer already on a vault can use their phone. */ +export async function importSigner(secret: string): Promise { + const trimmed = secret.trim(); + // Validate before storing: a key that cannot be decoded is worse in the keychain than rejected. + const { secretKey } = decodeSuiPrivateKey(trimmed); + const keypair = Ed25519Keypair.fromSecretKey(secretKey); + await SecureStore.setItemAsync(KEY, trimmed, OPTIONS); + return keypair.toSuiAddress(); +} + +/** + * Unlock the key. Prompts for biometrics, and returns the keypair only for the duration of one + * action — nothing here caches it, because a cached signer is a signer that acts without a face. + */ +export async function unlockSigner(reason = 'Approve with your Skur key'): Promise { + const auth = await LocalAuthentication.authenticateAsync({ + promptMessage: reason, + cancelLabel: 'Cancel', + disableDeviceFallback: false, + }); + if (!auth.success) throw new Error('cancelled'); + const stored = await SecureStore.getItemAsync(KEY, OPTIONS); + if (!stored) throw new Error('no signing key on this device'); + const { secretKey } = decodeSuiPrivateKey(stored); + return Ed25519Keypair.fromSecretKey(secretKey); +} + +/** The address, read without unlocking — it is public, and screens need it constantly. */ +export async function signerAddress(): Promise { + const stored = await SecureStore.getItemAsync(KEY, { + keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, + }).catch(() => null); + if (!stored) return null; + try { + return Ed25519Keypair.fromSecretKey(decodeSuiPrivateKey(stored).secretKey).toSuiAddress(); + } catch { + return null; + } +} + +/** + * Forget the key. The vault does not care — the address stays a member until governance removes + * it, which is the point of recovery existing. + */ +export async function forgetSigner(): Promise { + await SecureStore.deleteItemAsync(KEY, { + keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, + }).catch(() => undefined); +} diff --git a/mobile/src/lib/polyfills.ts b/mobile/src/lib/polyfills.ts new file mode 100644 index 0000000..01e76ea --- /dev/null +++ b/mobile/src/lib/polyfills.ts @@ -0,0 +1,83 @@ +/** + * Must be imported before anything that touches crypto or BCS. + * + * Hermes is not a browser and not Node. Two things the Sui SDK assumes are missing or partial: + * a CSPRNG behind `crypto.getRandomValues`, which key generation needs, and the text codecs that + * BCS uses for every string it serialises. + */ +import 'react-native-get-random-values'; + +// Hermes ships TextEncoder and TextDecoder on recent React Native, but the version is not +// something this app should depend on — and a silent absence would surface much later as a +// corrupted transaction rather than a missing global. UTF-8 only, which is all BCS uses. +if (typeof globalThis.TextEncoder === 'undefined') { + class MinimalTextEncoder { + readonly encoding = 'utf-8'; + encode(input = ''): Uint8Array { + const bytes: number[] = []; + for (let i = 0; i < input.length; i++) { + let code = input.charCodeAt(i); + if (code >= 0xd800 && code <= 0xdbff && i + 1 < input.length) { + const low = input.charCodeAt(i + 1); + if (low >= 0xdc00 && low <= 0xdfff) { + code = ((code - 0xd800) << 10) + (low - 0xdc00) + 0x10000; + i++; + } + } + if (code < 0x80) bytes.push(code); + else if (code < 0x800) bytes.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f)); + else if (code < 0x10000) + bytes.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f)); + else + bytes.push( + 0xf0 | (code >> 18), + 0x80 | ((code >> 12) & 0x3f), + 0x80 | ((code >> 6) & 0x3f), + 0x80 | (code & 0x3f), + ); + } + return new Uint8Array(bytes); + } + } + globalThis.TextEncoder = MinimalTextEncoder as unknown as typeof TextEncoder; +} + +if (typeof globalThis.TextDecoder === 'undefined') { + class MinimalTextDecoder { + readonly encoding = 'utf-8'; + decode(input?: Uint8Array): string { + if (!input) return ''; + let out = ''; + for (let i = 0; i < input.length; ) { + const b = input[i++]; + if (b < 0x80) out += String.fromCharCode(b); + else if (b < 0xe0) out += String.fromCharCode(((b & 0x1f) << 6) | (input[i++] & 0x3f)); + else if (b < 0xf0) + out += String.fromCharCode( + ((b & 0x0f) << 12) | ((input[i++] & 0x3f) << 6) | (input[i++] & 0x3f), + ); + else { + const cp = + (((b & 0x07) << 18) | + ((input[i++] & 0x3f) << 12) | + ((input[i++] & 0x3f) << 6) | + (input[i++] & 0x3f)) - + 0x10000; + out += String.fromCharCode(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff)); + } + } + return out; + } + } + globalThis.TextDecoder = MinimalTextDecoder as unknown as typeof TextDecoder; +} + +/** Fail loudly at startup rather than mid-signature. */ +export function assertCryptoReady() { + if (typeof globalThis.crypto?.getRandomValues !== 'function') { + throw new Error('crypto.getRandomValues is unavailable; react-native-get-random-values did not load'); + } + if (new TextEncoder().encode('ß').length !== 2) { + throw new Error('TextEncoder is not producing UTF-8'); + } +} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx new file mode 100644 index 0000000..2ab3088 --- /dev/null +++ b/mobile/src/screens/Home.tsx @@ -0,0 +1,171 @@ +import { RefreshControl, Text, View } from 'react-native'; +import { + Mode, + Status, + describeReasons, + fmtAmount, + fmtDuration, + type VaultView, +} from '@skur/sdk'; +import { + Address, + Card, + Empty, + IconButton, + KV, + ModeBadge, + Notice, + Row, + Screen, + SectionLabel, + Tape, + TopBar, +} from '../components/ui'; +import { Identicon } from '../components/Identicon'; +import { TokenMark, coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwitch: () => void }) { + const C = useTheme(); + const { vaultId } = useStore(); + const q = useVaultView(vaultId); + + if (q.isLoading) { + return ( + }> + Reading the vault… + + ); + } + if (q.error || !q.data) { + return ( + } />}> + + Could not read that vault. Check the id and the network. + + + ); + } + + const v: VaultView = q.data; + const p = v.vault.policy; + const pending = v.proposals.filter((x) => x.status === Status.PENDING); + + return ( + } + title={v.vault.name} + right={} + /> + } + refreshControl={ + q.refetch()} tintColor={C.text2} /> + } + > + + {v.vault.mode !== Mode.NORMAL ? : null} + + {v.vault.mode === Mode.LOCKDOWN ? ( + + This vault is frozen. Nothing outgoing executes and no payment can be opened. Deposits + still work. Reopening needs {p.governanceThreshold} owner + {p.governanceThreshold === 1 ? '' : 's'}, {p.guardianThreshold} guardian + {p.guardianThreshold === 1 ? '' : 's'} and {fmtDuration(p.policyChangeDelay)}. + + ) : v.vault.mode === Mode.ELEVATED ? ( + + Elevated. Every payment is escalated one tier and the caps are halved. + {v.vault.postureReasons ? ` ${describeReasons(v.vault.postureReasons).join('; ')}.` : ''} + + ) : null} + + + + + Posture + + + + Awaiting action + + {pending.length} + + + + + + + Holdings + {v.assets.length === 0 ? ( + No asset is approved for this vault yet. + ) : ( + + {v.assets.map((a, i) => { + const d = coinDecimals(a.coinType); + const daily = a.limits.dailyMax; + const spent = a.velocity?.daySpent ?? 0n; + return ( + } + title={coinSymbol(a.coinType)} + subtitle={ + daily === 0n + ? 'no daily cap' + : `${fmtAmount(spent, d)} of ${fmtAmount(daily, d)} used today` + } + trailing={ + + {fmtAmount(a.balance, d)} + + } + last={i === v.assets.length - 1} + /> + ); + })} + + )} + + + {pending.length > 0 ? ( + + } + title={`${pending.length} proposal${pending.length === 1 ? '' : 's'} open`} + subtitle="Review what is waiting" + onPress={onOpenQueue} + chevron + last + /> + + ) : null} + + + What this vault enforces + + + + + + + + + This vault +

      + + + + ); +} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx new file mode 100644 index 0000000..9c1b965 --- /dev/null +++ b/mobile/src/screens/Onboard.tsx @@ -0,0 +1,156 @@ +import { useEffect, useState } from 'react'; +import { Text, View } from 'react-native'; +import { + Address, + Button, + Card, + Field, + Input, + Notice, + Screen, + SectionLabel, + Tabs, + TopBar, +} from '../components/ui'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { biometricSupport, createSigner, importSigner, type BiometricSupport } from '../lib/keystore'; +import { useStore } from '../state/store'; + +/** + * Setting up the key on this device. + * + * The screen is explicit that this is a hot key. An approver or executor key belongs on a phone; + * a guardian key does not, because a guardian's whole value is being a control plane an attacker + * has to breach separately — and a guardian key sitting next to an approver key on the same device + * collapses the two planes the contract works to keep apart. + */ +export function Onboard({ onDone }: { onDone: () => void }) { + const C = useTheme(); + const { refreshSigner } = useStore(); + const [mode, setMode] = useState<'create' | 'import'>('create'); + const [bio, setBio] = useState(null); + const [secret, setSecret] = useState(''); + const [address, setAddress] = useState(null); + const [error, setError] = useState(null); + const [busy, setBusy] = useState(false); + + useEffect(() => { + void biometricSupport().then(setBio); + }, []); + + const act = async () => { + setError(null); + setBusy(true); + try { + const addr = mode === 'create' ? await createSigner() : await importSigner(secret); + setAddress(addr); + await refreshSigner(); + } catch (e) { + setError(e instanceof Error ? e.message : String(e)); + } finally { + setBusy(false); + } + }; + + if (address) { + return ( + } + footer={} + > + + + The key is in this device's secure element. It is released for one action at a + time, after {bio?.label ?? 'a device check'}. + + + This device signs as +
      + + + This address holds no roles yet. An owner of a vault has to add it — as an approver, an + executor, or both — before it can do anything. Send them the address above. + + + Do not use this device for a guardian key. A guardian is the second control plane an + attacker has to breach; keeping it on the same phone as an approver key defeats the + point of having two. + + + + ); + } + + return ( + } + footer={ + + } + > + + + + {bio && !bio.enrolled ? ( + + No {bio.available ? bio.label : 'screen lock'} is set up on this device. Set one up + first — without it the key would sit unprotected. + + ) : null} + + {mode === 'create' ? ( + + + A new Ed25519 key is generated on the device and written to the secure element. It + never leaves the phone and is not backed up anywhere. + + + If you lose this device, the key is gone. That is what the vault's guardian + recovery is for: guardians can move your roles to a new key after a delay any owner + can cancel. + + + ) : ( + + + + + + Import a key that is already an approver or executor on your vault. Do not paste a + key that holds anything you are not prepared to have on a phone. + + + )} + + {error ? {error} : null} + + + ); +} diff --git a/mobile/src/screens/OpenVault.tsx b/mobile/src/screens/OpenVault.tsx new file mode 100644 index 0000000..eb44a69 --- /dev/null +++ b/mobile/src/screens/OpenVault.tsx @@ -0,0 +1,100 @@ +import { useState } from 'react'; +import { RefreshControl, Text, View } from 'react-native'; +import { useQuery } from '@tanstack/react-query'; +import { MODE_LABELS, describeRoles } from '@skur/sdk'; +import { Address, Button, Card, Empty, Field, Input, Notice, Row, Screen, SectionLabel, TopBar } from '../components/ui'; +import { Identicon } from '../components/Identicon'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { API_URL, CONFIGURED, NETWORK } from '../lib/config'; +import { useStore } from '../state/store'; + +/** Vaults the device's key holds a role in, via the indexer when one is configured. */ +function useMyVaults(address: string | null) { + return useQuery<{ vault_id: string; name: string; roles: number; mode: number }[]>({ + queryKey: ['my-vaults', NETWORK, address], + enabled: Boolean(address && API_URL), + retry: 1, + queryFn: async () => { + const res = await fetch(`${API_URL}/members/${address}/vaults`); + if (!res.ok) throw new Error(`the indexer returned ${res.status}`); + return (await res.json()).vaults; + }, + }); +} + +export function OpenVault() { + const C = useTheme(); + const { address, openVault } = useStore(); + const [manual, setManual] = useState(''); + const mine = useMyVaults(address); + const valid = /^0x[0-9a-fA-F]{10,66}$/.test(manual); + + return ( + } + refreshControl={ mine.refetch()} tintColor={C.text2} />} + > + + {!CONFIGURED ? ( + + No package is configured for {NETWORK}. Publish the Move package and set + EXPO_PUBLIC_SKUR_PACKAGE_ID. + + ) : null} + + + Yours + {!API_URL ? ( + + + Finding your vaults by address needs the indexer. Set EXPO_PUBLIC_SKUR_API, or open + a vault by its id below — reading one needs nothing but the chain. + + + ) : mine.isLoading ? ( + Looking… + ) : mine.error ? ( + The indexer is not reachable. You can still open a vault by id. + ) : mine.data && mine.data.length > 0 ? ( + + {mine.data.map((v, i) => ( + } + title={v.name} + subtitle={`${describeRoles(v.roles).join(' · ') || 'no role'} · ${MODE_LABELS[v.mode as 0 | 1 | 2]}`} + onPress={() => openVault(v.vault_id)} + chevron + last={i === mine.data!.length - 1} + /> + ))} + + ) : ( + + No vault on {NETWORK} lists this device's key as a signer yet. + {address ? '\n\nSend your address to an owner so they can add it.' : ''} + + )} + + + {address ? ( + + This device signs as +
      + + ) : null} + + + By id + + + + + + + + ); +} diff --git a/mobile/src/screens/Receive.tsx b/mobile/src/screens/Receive.tsx new file mode 100644 index 0000000..34fa9b4 --- /dev/null +++ b/mobile/src/screens/Receive.tsx @@ -0,0 +1,64 @@ +import { Text, View } from 'react-native'; +import { fmtAmount } from '@skur/sdk'; +import { Address, Card, Empty, Notice, Row, Screen, SectionLabel, TopBar } from '../components/ui'; +import { TokenMark, coinDecimals, coinSymbol } from '../components/TokenMark'; +import { Identicon } from '../components/Identicon'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +export function Receive() { + const C = useTheme(); + const { vaultId } = useStore(); + const q = useVaultView(vaultId); + + return ( + }> + + + + + {q.data?.vault.name ?? 'Treasury'} + + + + + Vault address +
      + + + + Deposits are never gated — in any mode, from any address. The controls exist to govern + money leaving; refusing money arriving would only strand it. + + + + Assets this vault accepts + {(q.data?.assets ?? []).filter((a) => a.limits.approved).length === 0 ? ( + No asset is approved yet. + ) : ( + + {q.data!.assets + .filter((a) => a.limits.approved) + .map((a, i, arr) => ( + } + title={coinSymbol(a.coinType)} + subtitle={`holding ${fmtAmount(a.balance, coinDecimals(a.coinType))}`} + last={i === arr.length - 1} + /> + ))} + + )} + + + + Sending a coin type this vault has not approved will fail. Approving one is a governance + action. + + + + ); +} diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx new file mode 100644 index 0000000..48cb08b --- /dev/null +++ b/mobile/src/screens/Security.tsx @@ -0,0 +1,169 @@ +import { useMemo } from 'react'; +import { Text, View } from 'react-native'; +import { + Mode, + Role, + computeMaxLoss, + fmtAmount, + fmtDuration, + hasRole, + postureItems, + tx as build, +} from '@skur/sdk'; +import { + Button, + Card, + Icon, + KV, + Notice, + Screen, + SectionLabel, + TopBar, + TxStatus, +} from '../components/ui'; +import { coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { PACKAGE_ID } from '../lib/config'; +import { useTx } from '../hooks/useTx'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +export function Security() { + const C = useTheme(); + const { vaultId, address } = useStore(); + const q = useVaultView(vaultId); + const tx = useTx(vaultId); + + const roles = address ? (q.data?.members.find((m) => m.address === address)?.roles ?? 0) : 0; + const canRaise = hasRole(roles, Role.GUARDIAN) || hasRole(roles, Role.OWNER); + + const posture = useMemo( + () => + q.data + ? postureItems({ + policy: q.data.vault.policy, + guardians: q.data.vault.guardianCount, + assets: q.data.assets.map((a) => ({ symbol: coinSymbol(a.coinType), limits: a.limits })), + }) + : [], + [q.data], + ); + + if (!q.data) { + return ( + }> + Reading… + + ); + } + + const v = q.data; + const p = v.vault.policy; + + return ( + } + footer={tx.state.phase !== 'idle' ? : null} + > + + + What holds + + {posture.map((item, i) => ( + + + + + + {item.text} + + + ))} + + + Confirmed controls and obvious gaps. This is not a score and does not claim to measure + absolute security. + + + + + In an incident + {canRaise ? ( + + + + + Freezing is immediate and stops all outgoing execution. Deposits keep working. + Reopening needs {p.governanceThreshold} owner + {p.governanceThreshold === 1 ? '' : 's'}, {p.guardianThreshold} guardian + {p.guardianThreshold === 1 ? '' : 's'} and {fmtDuration(p.policyChangeDelay)} — + whoever froze it cannot lift it alone. + + + ) : ( + + Raising the posture takes an owner or a guardian. This device's key holds + neither. + + )} + + + + Maximum possible loss + {v.assets.map((a) => { + const r = computeMaxLoss(p, a.limits, a.balance, v.vault.mode); + const d = coinDecimals(a.coinType); + return ( + + + {coinSymbol(a.coinType)} + + + + + + ); + })} + + Assumes every signer a tier needs is compromised and cooperating, and that no guardian + acts. An upper bound under those assumptions, never a guarantee. A 24-hour bucket + anchors on its first payment, so up to two days' allowance can leave across a + boundary. + + + + + ); +} diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx new file mode 100644 index 0000000..75a1707 --- /dev/null +++ b/mobile/src/screens/Send.tsx @@ -0,0 +1,222 @@ +import { useMemo, useState } from 'react'; +import { Text, View } from 'react-native'; +import { + Trust, + canPropose, + describeReasons, + fmtAmount, + fmtDuration, + parseAmount, + tx as build, +} from '@skur/sdk'; +import { + Address, + Button, + Card, + Field, + Input, + KV, + Notice, + Screen, + SectionLabel, + TierBadge, + TopBar, + TrustBadge, + TxStatus, +} from '../components/ui'; +import { coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { PACKAGE_ID } from '../lib/config'; +import { useTransferPreview, useVaultView } from '../hooks/useVault'; +import { useTx } from '../hooks/useTx'; +import { useStore } from '../state/store'; + +/** + * Opening a payment. + * + * The review is the vault's own classification, simulated live. The phone does not compute it, so + * it cannot promise something the vault would refuse — which is the point of `preview_transfer` + * being the same code `execute_transfer` runs. + */ +export function Send({ onDone }: { onDone: () => void }) { + const C = useTheme(); + const { vaultId, address, book } = useStore(); + const q = useVaultView(vaultId); + const tx = useTx(vaultId); + + const approved = (q.data?.assets ?? []).filter((a) => a.limits.approved); + const [coinType, setCoinType] = useState(''); + const [to, setTo] = useState(''); + const [amountText, setAmountText] = useState(''); + const [memo, setMemo] = useState(''); + + const asset = approved.find((a) => a.coinType === coinType) ?? approved[0]; + const activeType = asset?.coinType ?? ''; + const decimals = activeType ? coinDecimals(activeType) : 9; + const amount = useMemo(() => parseAmount(amountText, decimals) ?? 0n, [amountText, decimals]); + const validTo = /^0x[0-9a-fA-F]{1,64}$/.test(to); + + const known = q.data?.recipients.find((r) => r.address === to); + const labelled = book.find((b) => b.address === to); + const roles = address ? (q.data?.members.find((m) => m.address === address)?.roles ?? 0) : 0; + + const preview = useTransferPreview({ + vaultId, + coinType: activeType, + amount, + recipient: to, + sender: address, + enabled: Boolean(activeType) && validTo && amount > 0n, + }); + + // Mirrors what `propose_transfer` would refuse, so the form says why before a prompt appears. + const problems: string[] = []; + if (asset && amount > 0n) { + if ((known?.trust ?? Trust.UNKNOWN) === Trust.BLOCKED) problems.push('This recipient is blocked.'); + if (asset.limits.perTxMax !== 0n && amount > asset.limits.perTxMax) + problems.push(`Above the per-payment cap of ${fmtAmount(asset.limits.perTxMax, decimals)}.`); + const spent = asset.velocity?.daySpent ?? 0n; + if (asset.limits.dailyMax !== 0n && spent + amount > asset.limits.dailyMax) + problems.push(`Above what is left of today (${fmtAmount(asset.limits.dailyMax - spent, decimals)}).`); + if (amount > asset.balance) problems.push(`The vault holds ${fmtAmount(asset.balance, decimals)}.`); + } + + const mayPropose = canPropose(roles); + const ready = mayPropose && validTo && amount > 0n && problems.length === 0 && Boolean(activeType); + + if (approved.length === 0) { + return ( + }> + + No asset is approved for this vault yet. An owner has to approve one through governance + before anything can be paid. + + + ); + } + + return ( + } + footer={ + + + + + } + > + + + Opening a payment is not approving it. The vault scores it first and then says what it + needs. + + + {approved.length > 1 ? ( + + Asset + + {approved.map((a) => ( + + ))} + + + ) : null} + + + setTo(t.trim())} placeholder="0x…" autoCapitalize="none" autoCorrect={false} /> + + {validTo ? ( + + + + {known && known.paidCount > 0 + ? `paid ${known.paidCount} time${known.paidCount === 1 ? '' : 's'} before` + : 'never paid by this vault'} + + + ) : null} + + + + + + + + + + {!mayPropose ? ( + + This device's key cannot open payments in this vault. That takes an owner, + approver, executor or proposer role. + + ) : null} + + {problems.length > 0 ? ( + The vault would refuse this. {problems.join(' ')} + ) : null} + + {preview.data ? ( + + + What the vault will demand + + + + + + + {describeReasons(preview.data.reasons).length > 0 ? ( + + {describeReasons(preview.data.reasons).map((r) => ( + + • {r} + + ))} + + ) : null} + + ) : preview.isLoading ? ( + Asking the vault… + ) : null} + + + ); +} diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx new file mode 100644 index 0000000..ba50555 --- /dev/null +++ b/mobile/src/screens/Settings.tsx @@ -0,0 +1,111 @@ +import { useEffect, useState } from 'react'; +import { Alert, Text, View } from 'react-native'; +import { Address, Button, Card, KV, Notice, Row, Screen, SectionLabel, Tabs, TopBar } from '../components/ui'; +import { useScheme, type Scheme } from '../state/theme'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { API_URL, NETWORK, PACKAGE_ID, explorer } from '../lib/config'; +import { biometricSupport, forgetSigner, type BiometricSupport } from '../lib/keystore'; +import { useStore } from '../state/store'; + +export function Settings() { + const C = useTheme(); + const { scheme, setScheme } = useScheme(); + const { address, vaultId, closeVault, refreshSigner } = useStore(); + const [bio, setBio] = useState(null); + + useEffect(() => { + void biometricSupport().then(setBio); + }, []); + + const forget = () => + Alert.alert( + 'Forget this key?', + 'The key is deleted from this device and cannot be recovered. Your address stays a member of the vault until governance removes it — guardians can move your roles to a new key, which is what recovery is for.', + [ + { text: 'Cancel', style: 'cancel' }, + { + text: 'Forget it', + style: 'destructive', + onPress: () => { + void forgetSigner().then(refreshSigner); + }, + }, + ], + ); + + return ( + }> + + + Appearance + setScheme(s as Scheme)} + /> + + + + This device + + {address ? ( + <> + Signs as +
      + + + + + ) : ( + + No signing key on this device. + + )} + + + This is a hot key: appropriate for an approver or an executor, whose authority is + bounded by the policy. A guardian key belongs somewhere this phone is not. + + {address ? ( + + ) : null} + + + + Network + + + + + + + + {vaultId ? ( + + Vault + + + + + + ) : null} + + + Skur has not been audited. Do not put real value behind it until an independent audit is + complete. + + + + ); +} diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx new file mode 100644 index 0000000..a7d84eb --- /dev/null +++ b/mobile/src/screens/Transactions.tsx @@ -0,0 +1,108 @@ +import { RefreshControl, Text, View } from 'react-native'; +import { KIND_LABELS, Kind, Status, fmtAmount, fmtRelative, type Proposal } from '@skur/sdk'; +import { + Card, + Empty, + Notice, + Row, + Screen, + SectionLabel, + StatusBadge, + TierBadge, + TopBar, +} from '../components/ui'; +import { TokenMark, coinDecimals, coinSymbol } from '../components/TokenMark'; +import { Identicon } from '../components/Identicon'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +export function Transactions({ onOpen }: { onOpen: (id: bigint) => void }) { + const C = useTheme(); + const { vaultId } = useStore(); + const q = useVaultView(vaultId); + + const pending = (q.data?.proposals ?? []).filter((p) => p.status === Status.PENDING); + const settled = (q.data?.proposals ?? []).filter((p) => p.status !== Status.PENDING); + + const line = (p: Proposal) => { + if (p.kind === Kind.TRANSFER && p.asset) { + return `${fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset))}`; + } + return KIND_LABELS[p.kind]; + }; + + return ( + } + refreshControl={ + q.refetch()} tintColor={C.text2} /> + } + > + + {q.error ? Could not read the vault. : null} + + + Awaiting action + {pending.length === 0 ? ( + Nothing is waiting. + ) : ( + + {pending.map((p, i) => ( + + ) : ( + + ) + } + title={line(p)} + subtitle={`${p.memo || KIND_LABELS[p.kind]} · ${p.approvals.length}/${p.reqApprovals} approvals`} + trailing={p.kind === Kind.TRANSFER ? : } + onPress={() => onOpen(p.id)} + chevron + last={i === pending.length - 1} + /> + ))} + + )} + + + + Settled + {settled.length === 0 ? ( + Nothing has settled yet. + ) : ( + + {settled.map((p, i) => ( + + ) : ( + + ) + } + title={line(p)} + subtitle={ + + {fmtRelative(p.createdAt)} + + } + trailing={} + onPress={() => onOpen(p.id)} + chevron + last={i === settled.length - 1} + /> + ))} + + )} + + + + ); +} diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx new file mode 100644 index 0000000..574539b --- /dev/null +++ b/mobile/src/screens/TxDetail.tsx @@ -0,0 +1,249 @@ +import { Text, View } from 'react-native'; +import { + KIND_LABELS, + Kind, + Role, + Status, + Tier, + describeReasons, + fmtAmount, + fmtDuration, + fmtTimestamp, + hasRole, + policyReductions, + tx as build, +} from '@skur/sdk'; +import { + Address, + BackButton, + Button, + Card, + KV, + Notice, + Screen, + SectionLabel, + StatusBadge, + TierBadge, + TopBar, + TxStatus, +} from '../components/ui'; +import { coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { PACKAGE_ID } from '../lib/config'; +import { useTx } from '../hooks/useTx'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +/** + * One proposal, and the actions this device's key is actually allowed to take on it. + * + * Every button is gated on the role the contract requires, so a signer is never offered something + * the vault would refuse. The requirements shown are the ones pinned when the proposal was opened; + * at execution the vault re-derives them and applies whichever is stricter, which is why a payment + * can end up needing more than this says and never less. + */ +export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { + const C = useTheme(); + const { vaultId, address } = useStore(); + const q = useVaultView(vaultId); + const tx = useTx(vaultId); + + const p = q.data?.proposals.find((x) => x.id === id); + const roles = address ? (q.data?.members.find((m) => m.address === address)?.roles ?? 0) : 0; + + if (!p || !q.data) { + return ( + } title="Proposal" />}> + Reading… + + ); + } + + const isTransfer = p.kind === Kind.TRANSFER; + const voteRole = isTransfer ? Role.APPROVER : Role.OWNER; + const canVote = hasRole(roles, voteRole); + const canExecute = isTransfer ? hasRole(roles, Role.EXECUTOR) : roles !== 0; + const isGuardian = hasRole(roles, Role.GUARDIAN); + + const live = (set: string[], role: number) => + set.filter((a) => hasRole(q.data!.members.find((m) => m.address === a)?.roles ?? 0, role)).length; + const liveApprovals = live(p.approvals, Role.APPROVER); + const liveConfirmations = live(p.confirmations, Role.GUARDIAN); + const liveRejections = live(p.rejections, voteRole); + + const voted = address ? p.approvals.includes(address) : false; + const rejected = address ? p.rejections.includes(address) : false; + const confirmed = address ? p.confirmations.includes(address) : false; + + const timeMet = Date.now() >= p.executableAt; + const ready = liveApprovals >= p.reqApprovals && liveConfirmations >= p.reqGuardians && timeMet; + const open = p.status === Status.PENDING; + + const vetoable = + p.reductionMask !== 0 || + (isTransfer && p.tier === Tier.CRITICAL) || + p.kind === Kind.RECOVERY || + p.kind === Kind.MODE_RELAX; + + const reasons = describeReasons(p.reasons); + const reductions = p.newPolicy ? policyReductions(q.data.vault.policy, p.newPolicy) : []; + + const executeTx = () => { + if (isTransfer && p.asset) + return build.executeTransfer(PACKAGE_ID, { vaultId: vaultId!, coinType: p.asset, proposalId: id }); + if (p.kind === Kind.POLICY_UPDATE) return build.executePolicy(PACKAGE_ID, vaultId!, id); + if (p.kind === Kind.MEMBER_SET) return build.executeMember(PACKAGE_ID, vaultId!, id); + if (p.kind === Kind.RECIPIENT_TRUST) return build.executeRecipientTrust(PACKAGE_ID, vaultId!, id); + if (p.kind === Kind.MODE_RELAX) return build.executeModeRelax(PACKAGE_ID, vaultId!, id); + if (p.kind === Kind.RECOVERY) return build.executeRecovery(PACKAGE_ID, vaultId!, id); + if (p.kind === Kind.ASSET_LIMITS && p.asset) + return build.executeAssetLimits(PACKAGE_ID, { vaultId: vaultId!, coinType: p.asset, proposalId: id }); + throw new Error('nothing to execute for this kind'); + }; + + return ( + } title={`#${id} · ${KIND_LABELS[p.kind]}`} />} + footer={ + open ? ( + + + {canVote ? ( + + + + + ) : null} + {isGuardian && (p.reqGuardians > 0 || vetoable) ? ( + + ) : null} + {isGuardian && vetoable ? ( + + ) : null} + {canExecute ? ( + + ) : null} + + ) : null + } + > + + + {isTransfer ? : null} + + {p.reductionMask !== 0 ? ( + weakens the vault + ) : null} + + + {isTransfer && p.asset ? ( + + Leaves the vault + + {fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset))} + + + To +
      + + {p.memo ? ( + + {p.memo} + + ) : null} + + ) : null} + + {p.kind === Kind.RECOVERY ? ( + + Replace a lost signer + } /> + } last /> + + The roles move across unchanged and the policy is untouched. Any owner can cancel this + before it executes. + + + ) : null} + + {reasons.length > 0 ? ( + + Scored this way because + {reasons.map((r) => ( + + • {r} + + ))} + + ) : null} + + {reductions.length > 0 ? ( + + This change gives up: {reductions.join('; ')}. It waits{' '} + {fmtDuration(q.data.vault.policy.policyChangeDelay)} and any guardian can stop it. + + ) : null} + + + What it needs + + {p.reqGuardians > 0 ? ( + + ) : null} + {liveRejections > 0 ? : null} + + + } last /> + + + {!canVote && !canExecute && !isGuardian ? ( + + This device's key holds no role that can act on this proposal. You can read it. + + ) : null} + + + ); +} diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx new file mode 100644 index 0000000..4ddecb1 --- /dev/null +++ b/mobile/src/screens/Welcome.tsx @@ -0,0 +1,51 @@ +import { Text, View } from 'react-native'; +import { Button, Logo, Screen, Tape } from '../components/ui'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { NETWORK } from '../lib/config'; + +const POINTS: [string, string][] = [ + ['Approvals that follow the risk', 'The amount, the destination, today’s outflow and the vault’s posture decide how much sign-off a payment needs.'], + ['A brake you can reach', 'Freeze the vault from anywhere. Any guardian can veto a critical payment before it settles.'], + ['Your key stays on the phone', 'Held in the secure element behind your face or fingerprint, and released for one action at a time.'], +]; + +export function Welcome({ onStart }: { onStart: () => void }) { + const C = useTheme(); + return ( + + Get started + + } + > + + + + + A valid signature is not a safe payment + + + Skur decides how much authorization a payment needs, and whether it may settle right + now — enforced in Move, in a shared object anyone can read. + + + + + {POINTS.map(([title, body]) => ( + + {title} + + {body} + + + ))} + + + Sui · {NETWORK} · not audited + + + + ); +} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx new file mode 100644 index 0000000..10db624 --- /dev/null +++ b/mobile/src/state/store.tsx @@ -0,0 +1,128 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, + type ReactNode, +} from 'react'; +import { hasSigner, signerAddress } from '../lib/keystore'; + +/** + * What the app remembers between launches: which vault is open, the addresses you have labelled, + * and whether onboarding is done. None of it is authoritative — the vault is, and all of this is + * rebuilt from the chain on open. + */ +export type Labelled = { address: string; label: string }; + +type Store = { + ready: boolean; + /** Null until a key exists on the device. */ + address: string | null; + vaultId: string | null; + onboarded: boolean; + book: Labelled[]; + openVault: (id: string) => void; + closeVault: () => void; + finishOnboarding: () => void; + label: (address: string, label: string) => void; + unlabel: (address: string) => void; + /** Re-read the device key, after creating, importing or forgetting one. */ + refreshSigner: () => Promise; +}; + +const Ctx = createContext(null); +const K = { vault: 'skur.vault', onboarded: 'skur.onboarded', book: 'skur.book' } as const; + +export function StoreProvider({ children }: { children: ReactNode }) { + const [ready, setReady] = useState(false); + const [address, setAddress] = useState(null); + const [vaultId, setVaultId] = useState(null); + const [onboarded, setOnboarded] = useState(false); + const [book, setBook] = useState([]); + + const refreshSigner = useCallback(async () => { + setAddress((await hasSigner()) ? await signerAddress() : null); + }, []); + + useEffect(() => { + void (async () => { + const [v, o, b] = await Promise.all([ + AsyncStorage.getItem(K.vault), + AsyncStorage.getItem(K.onboarded), + AsyncStorage.getItem(K.book), + ]); + setVaultId(v); + setOnboarded(o === '1'); + try { + setBook(b ? (JSON.parse(b) as Labelled[]) : []); + } catch { + // A corrupted address book is an inconvenience, not a reason to fail to start. + setBook([]); + } + await refreshSigner(); + setReady(true); + })(); + }, [refreshSigner]); + + const openVault = useCallback((id: string) => { + setVaultId(id); + void AsyncStorage.setItem(K.vault, id); + }, []); + + const closeVault = useCallback(() => { + setVaultId(null); + void AsyncStorage.removeItem(K.vault); + }, []); + + const finishOnboarding = useCallback(() => { + setOnboarded(true); + void AsyncStorage.setItem(K.onboarded, '1'); + }, []); + + const persistBook = useCallback((next: Labelled[]) => { + setBook(next); + void AsyncStorage.setItem(K.book, JSON.stringify(next)); + }, []); + + const label = useCallback( + (addr: string, text: string) => + persistBook([ + ...book.filter((e) => e.address !== addr), + { address: addr, label: text }, + ]), + [book, persistBook], + ); + + const unlabel = useCallback( + (addr: string) => persistBook(book.filter((e) => e.address !== addr)), + [book, persistBook], + ); + + const value = useMemo( + () => ({ + ready, + address, + vaultId, + onboarded, + book, + openVault, + closeVault, + finishOnboarding, + label, + unlabel, + refreshSigner, + }), + [ready, address, vaultId, onboarded, book, openVault, closeVault, finishOnboarding, label, unlabel, refreshSigner], + ); + + return {children}; +} + +export function useStore(): Store { + const s = useContext(Ctx); + if (!s) throw new Error('StoreProvider missing'); + return s; +} diff --git a/mobile/src/state/theme.tsx b/mobile/src/state/theme.tsx new file mode 100644 index 0000000..62f7b97 --- /dev/null +++ b/mobile/src/state/theme.tsx @@ -0,0 +1,31 @@ +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react"; +import { useColorScheme } from "react-native"; +import { DARK, LIGHT, type Palette } from "../theme"; + +export type Scheme = "light" | "dark" | "system"; +const Ctx = createContext<{ C: Palette; scheme: Scheme; dark: boolean; setScheme: (s: Scheme) => void } | null>(null); +const KEY = "skur.theme"; + +/** One ground for the whole app, onboarding included, switchable in Settings and remembered. */ +export function ThemeProvider({ children }: { children: ReactNode }) { + const system = useColorScheme(); + const [scheme, setSchemeState] = useState("system"); + useEffect(() => { void AsyncStorage.getItem(KEY).then((v) => { if (v === "light" || v === "dark" || v === "system") setSchemeState(v); }); }, []); + const setScheme = useCallback((s: Scheme) => { setSchemeState(s); void AsyncStorage.setItem(KEY, s); }, []); + const dark = scheme === "system" ? system === "dark" : scheme === "dark"; + const value = useMemo(() => ({ C: dark ? DARK : LIGHT, scheme, dark, setScheme }), [dark, scheme, setScheme]); + return {children}; +} + +export function useTheme(): Palette { + const t = useContext(Ctx); + if (!t) throw new Error("ThemeProvider missing"); + return t.C; +} + +export function useScheme() { + const t = useContext(Ctx); + if (!t) throw new Error("ThemeProvider missing"); + return t; +} diff --git a/mobile/src/theme.ts b/mobile/src/theme.ts new file mode 100644 index 0000000..ec21780 --- /dev/null +++ b/mobile/src/theme.ts @@ -0,0 +1,39 @@ +/** Skur's two grounds. Same tokens in both, so a screen never needs to know which one is on. */ +export type Palette = { + canvas: string; card: string; card2: string; border: string; + text: string; text2: string; text3: string; + accent: string; accentBg: string; onAccent: string; + success: string; successBg: string; warning: string; warningBg: string; + error: string; errorBg: string; info: string; infoBg: string; + shadowOpacity: number; +}; + +export const LIGHT: Palette = { + canvas: "#ffffff", card: "#f6f7f9", card2: "#eceef2", border: "#e4e7ec", + text: "#101418", text2: "#667085", text3: "#98a2b3", + accent: "#ffd000", accentBg: "#fff6cc", onAccent: "#101418", + success: "#11875a", successBg: "#e6f6ec", warning: "#a86a00", warningBg: "#fff3d6", + error: "#b42318", errorBg: "#ffe4e2", info: "#1971c2", infoBg: "#e7f1ff", + shadowOpacity: 0.08, +}; + +export const DARK: Palette = { + canvas: "#212529", card: "#2b3035", card2: "#343a40", border: "#495057", + text: "#f8f9fa", text2: "#adb5bd", text3: "#6c757d", + accent: "#ffd000", accentBg: "#3d3400", onAccent: "#212529", + success: "#75b798", successBg: "#1b4332", warning: "#ffa94d", warningBg: "#4d2e05", + error: "#ea868f", errorBg: "#4a1c22", info: "#6ea8fe", infoBg: "#1b3a5c", + shadowOpacity: 0.4, +}; + +export const F = { + display: "SpaceGrotesk_700Bold", + displayMedium: "SpaceGrotesk_600SemiBold", + body: "DMSans_400Regular", + bodyMedium: "DMSans_500Medium", + bodyBold: "DMSans_700Bold", + mono: "DMMono_400Regular", + monoMedium: "DMMono_500Medium", +} as const; + +export const R = { sm: 8, md: 12, lg: 16, pill: 999 } as const; diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json new file mode 100644 index 0000000..661db12 --- /dev/null +++ b/mobile/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "expo/tsconfig.base", + "compilerOptions": { + "strict": true, + "noEmit": true, + "jsx": "react-jsx", + "moduleResolution": "bundler", + "module": "esnext", + "skipLibCheck": true + }, + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["node_modules", "ios", "android", ".expo"] +} diff --git a/package.json b/package.json index 9dbf745..7b0ebf4 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,12 @@ "app:dev": "cd app && npm run dev", "app:build": "cd app && npm run build", "test": "npm run move:test && npm run sdk:test", - "typecheck": "cd sdk && npm run typecheck && cd ../server && npm run typecheck && cd ../app && npm run typecheck", + "typecheck": "cd sdk && npm run typecheck && cd ../server && npm run typecheck && cd ../app && npm run typecheck && cd ../mobile && npm run typecheck", "sui:seed": "cd sdk && npm run seed", "sui:e2e": "cd sdk && npm run e2e", - "verify": "scripts/verify.sh" + "verify": "scripts/verify.sh", + "mobile:start": "cd mobile && npm start", + "mobile:ios": "cd mobile && npm run ios", + "mobile:android": "cd mobile && npm run android" } } \ No newline at end of file diff --git a/scripts/verify.sh b/scripts/verify.sh index 807f7fd..a9ac065 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -48,5 +48,10 @@ fi step "Interface · typecheck" bash -c "cd '$ROOT/app' && npm run --silent typecheck" step "Interface · build" bash -c "cd '$ROOT/app' && NEXT_TELEMETRY_DISABLED=1 npm run --silent build >/dev/null" +step "Mobile · typecheck" bash -c "cd '$ROOT/mobile' && npm run --silent typecheck" +# Bundling is the check that matters for mobile: it proves the Sui SDK and its ESM exports resolve +# under Metro and Hermes, which no typecheck can tell you. +step "Mobile · bundles for iOS" bash -c "cd '$ROOT/mobile' && npx expo export --platform ios --output-dir \"\$(mktemp -d)\" >/dev/null 2>&1" + printf '\n\033[1m%s passed, %s failed\033[0m\n' "$PASS" "$FAIL" [ "$FAIL" -eq 0 ] || exit 1 From 5c75aadb460f35697e80e8cb4faa67edfa023c42 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Tue, 6 Oct 2026 00:03:58 +0100 Subject: [PATCH 32/44] fix(mobile): polyfill Intl.PluralRules, which Hermes does not have MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The app built and installed but threw 'undefined cannot be used as a constructor' before React mounted, with no stack worth reading because it happened while the module graph was still loading. Bisecting the imports narrowed it to @mysten/sui/grpc, and reading the bundle at the line the stack named found it: the SDK builds an ordinal formatter at module scope — new Intl.PluralRules('en-US', { type: 'ordinal' }), used to say '1st command' in an error message. Hermes ships a partial Intl and leaves PluralRules out, so the constructor is undefined and importing anything from the SDK's client throws immediately. Polyfilled for English, installed only when genuinely absent, and assertCryptoReady now checks it at startup rather than letting it surface as a module-load failure. Metro also needed mjs in sourceExts, since the SDK's gRPC entry is built from .mjs chunks. The client is constructed lazily rather than at import. A top-level new in a module everything imports means any resolution problem crashes before there is a component tree to show an error in. Verified on an iPhone 17 Pro simulator: builds, installs, launches, and renders the welcome screen. I could not tap through the flow — this environment has no Simulator GUI and no idb_companion — so the screens beyond the first are verified by typecheck and bundle only. --- mobile/README.md | 10 ++++++-- mobile/metro.config.js | 8 ++++++- mobile/package.json | 2 +- mobile/src/lib/client.ts | 41 ++++++++++++++++++++++++++----- mobile/src/lib/polyfills.ts | 48 +++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 10 deletions(-) diff --git a/mobile/README.md b/mobile/README.md index 7bcbabc..3ea9d0f 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -61,8 +61,14 @@ Three things, all in [`src/lib/polyfills.ts`](src/lib/polyfills.ts) and much later as a corrupted transaction rather than a missing global, so there is a guarded UTF-8 fallback. - **The Sui SDK is ESM with an exports map and no CommonJS fallback**, and `@skur/sdk` resolves - through a symlink to a sibling directory. Metro needs `unstable_enablePackageExports` and the - workspace in `watchFolders`, or an edit to the SDK is invisible until the bundler restarts. + through a symlink to a sibling directory. Metro needs `unstable_enablePackageExports`, `mjs` in + `sourceExts`, and the workspace in `watchFolders`. +- **`Intl.PluralRules` does not exist in Hermes**, and the Sui SDK builds an ordinal formatter with + it at **module scope** — `new Intl.PluralRules("en-US", { type: "ordinal" })`, used to say "1st + command" in an error message. On Hermes the constructor is `undefined`, so importing anything + from the SDK's client throws `undefined cannot be used as a constructor` before a line of app + code runs, with no usable stack. An English-ordinals polyfill fixes it, and `assertCryptoReady` + checks it at startup. Transport is **gRPC-web over fetch**, which is what React Native can actually do — there is no HTTP/2 socket to reach for. JSON-RPC is not used anywhere: Sui switched it off on mainnet full diff --git a/mobile/metro.config.js b/mobile/metro.config.js index 37e0ea5..150d534 100644 --- a/mobile/metro.config.js +++ b/mobile/metro.config.js @@ -17,6 +17,12 @@ config.resolver.nodeModulesPaths = [ // The Sui SDK ships ESM with an exports map and no CommonJS fallback. config.resolver.unstable_enablePackageExports = true; -config.resolver.unstable_conditionNames = ['react-native', 'require', 'import', 'default']; +config.resolver.unstable_conditionNames = ['react-native', 'import', 'require', 'default']; + +// Its gRPC entry is built from `.mjs` chunks that import each other by explicit path. Expo's +// default sourceExts does not include `mjs`, so Metro would resolve those files without applying +// the transform — the module loads, every export is undefined, and the first `new` on one fails +// with "undefined cannot be used as a constructor" from somewhere with no stack. +config.resolver.sourceExts = [...config.resolver.sourceExts, 'mjs']; module.exports = config; diff --git a/mobile/package.json b/mobile/package.json index 402335a..a612d7b 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -42,4 +42,4 @@ "@types/react": "~19.2.2", "typescript": "~6.0.3" } -} +} \ No newline at end of file diff --git a/mobile/src/lib/client.ts b/mobile/src/lib/client.ts index 057c9fe..f78612b 100644 --- a/mobile/src/lib/client.ts +++ b/mobile/src/lib/client.ts @@ -1,12 +1,41 @@ import './polyfills'; -import { SuiGrpcClient } from '@mysten/sui/grpc'; +import * as grpc from '@mysten/sui/grpc'; import { GRPC_URL, NETWORK } from './config'; +import type { SuiGrpcClient } from '@mysten/sui/grpc'; /** - * One client for the app. + * One client for the app, built on first use rather than at import. * - * gRPC, not JSON-RPC: Sui switched JSON-RPC off on mainnet full nodes in July 2026 and is - * removing it entirely. The default transport is gRPC-web over fetch, which is what React Native - * can actually do — there is no HTTP/2 socket to reach for here. + * Constructing it at module scope means any resolution problem in the SDK throws during module + * initialisation — before React mounts, with no component tree to show an error in, and no stack + * that names the cause. Lazily, a failure is a message on a screen. + * + * gRPC, not JSON-RPC: Sui switched JSON-RPC off on mainnet full nodes in July 2026 and is removing + * it. The transport is gRPC-web over fetch, which is what React Native can actually do — there is + * no HTTP/2 socket to reach for here. + */ +let instance: SuiGrpcClient | null = null; + +export function getClient(): SuiGrpcClient { + if (instance) return instance; + const Ctor = grpc.SuiGrpcClient; + if (typeof Ctor !== 'function') { + throw new Error( + `@mysten/sui/grpc did not provide SuiGrpcClient under this bundler. Got ${typeof Ctor}; the module exported: ${Object.keys(grpc).join(', ') || '(nothing)'}`, + ); + } + instance = new Ctor({ network: NETWORK, baseUrl: GRPC_URL }); + return instance; +} + +/** + * A proxy, so callers can keep writing `client.core.getObject(...)` while construction stays + * lazy. Every property access builds the client on first touch. */ -export const client = new SuiGrpcClient({ network: NETWORK, baseUrl: GRPC_URL }); +export const client = new Proxy({} as SuiGrpcClient, { + get(_t, prop) { + const c = getClient() as unknown as Record; + const value = c[prop]; + return typeof value === 'function' ? value.bind(c) : value; + }, +}); diff --git a/mobile/src/lib/polyfills.ts b/mobile/src/lib/polyfills.ts index 01e76ea..008d44f 100644 --- a/mobile/src/lib/polyfills.ts +++ b/mobile/src/lib/polyfills.ts @@ -72,6 +72,49 @@ if (typeof globalThis.TextDecoder === 'undefined') { globalThis.TextDecoder = MinimalTextDecoder as unknown as typeof TextDecoder; } +/** + * Hermes ships a partial `Intl`, and `PluralRules` is one of the pieces it leaves out. + * + * This matters more than it sounds. The Sui SDK builds an ordinal formatter at **module scope** — + * `new Intl.PluralRules("en-US", { type: "ordinal" })`, used to say "1st command" in an error — + * so on Hermes the constructor is `undefined` and importing anything from the SDK's client throws + * `undefined cannot be used as a constructor` before a line of app code runs. There is no stack + * worth reading, because it happens while the module graph is still loading. + * + * English only, which is all the SDK asks for, and only installed when it is genuinely absent. + */ +if (typeof (globalThis as { Intl?: { PluralRules?: unknown } }).Intl?.PluralRules === 'undefined') { + class MinimalPluralRules { + #ordinal: boolean; + + constructor(_locales?: string | string[], options?: { type?: string }) { + this.#ordinal = options?.type === 'ordinal'; + } + + select(n: number): string { + if (!this.#ordinal) return n === 1 ? 'one' : 'other'; + // en-US ordinals: 1st, 2nd, 3rd, 4th … and the 11th/12th/13th exceptions. + const tens = Math.abs(n) % 100; + const units = Math.abs(n) % 10; + if (units === 1 && tens !== 11) return 'one'; + if (units === 2 && tens !== 12) return 'two'; + if (units === 3 && tens !== 13) return 'few'; + return 'other'; + } + + resolvedOptions() { + return { locale: 'en-US', type: this.#ordinal ? 'ordinal' : 'cardinal' }; + } + + static supportedLocalesOf(locales?: string | string[]): string[] { + return typeof locales === 'string' ? [locales] : (locales ?? []); + } + } + + const intl = ((globalThis as { Intl?: Record }).Intl ??= {} as Record); + intl.PluralRules = MinimalPluralRules; +} + /** Fail loudly at startup rather than mid-signature. */ export function assertCryptoReady() { if (typeof globalThis.crypto?.getRandomValues !== 'function') { @@ -80,4 +123,9 @@ export function assertCryptoReady() { if (new TextEncoder().encode('ß').length !== 2) { throw new Error('TextEncoder is not producing UTF-8'); } + // The SDK builds an ordinal formatter at module scope, so this has to work before it is imported. + const ordinals = new Intl.PluralRules('en-US', { type: 'ordinal' }); + if (ordinals.select(1) !== 'one' || ordinals.select(11) !== 'other') { + throw new Error('Intl.PluralRules is not producing English ordinals'); + } } From 379f28ae46ff7447233299c36f8f00403e46d337 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Tue, 6 Oct 2026 11:43:22 +0100 Subject: [PATCH 33/44] test(mobile): render every screen and press its buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I could not drive the app on a device: this machine has no Simulator GUI and no idb_companion. Rather than leave the screens past the first one unverified, they are rendered and pressed here — which is closer to the code than a touch, and repeatable in a way a hand-driven session is not. Twenty-eight tests. The ones that matter cover which action each role is offered, because the contract refuses an action the caller has no role for and an interface that offers it is lying to the person holding the phone. Each case asserts both halves — what appears and what does not. An approver gets Approve and Reject and not Execute; a guardian is never offered Approve on a payment; an agent is offered nothing at all; a disabled Execute does not fire when pressed. Two findings from the app itself: - The Send screen built its refusal message from two text nodes, so the reason a payment was refused read correctly to a person and was invisible to anything searching for it. One string now. - The action buttons had no stable identity, and the Execute button's label changes with its state — 'Not enough approvals yet' until it is ready, which is exactly the state worth testing. They carry testIDs now. And two about the testing library, recorded in the README so they do not cost the time twice: render and fireEvent are both asynchronous in version 14, and an un-awaited fireEvent does not fail its own test — it leaves React's work queue mid-flight and the next test renders an empty tree. --- mobile/README.md | 33 + mobile/jest.config.js | 37 + mobile/package-lock.json | 7512 +++++++++++++++++++++++++------ mobile/package.json | 8 +- mobile/src/components/ui.tsx | 4 +- mobile/src/screens/Send.tsx | 2 +- mobile/src/screens/TxDetail.tsx | 9 +- mobile/test/fixtures.ts | 121 + mobile/test/harness.tsx | 31 + mobile/test/mocks/client.ts | 5 + mobile/test/roles.test.tsx | 156 + mobile/test/screens.test.tsx | 171 + mobile/test/setup.tsx | 47 + mobile/tsconfig.json | 20 +- scripts/verify.sh | 4 + 15 files changed, 6676 insertions(+), 1484 deletions(-) create mode 100644 mobile/jest.config.js create mode 100644 mobile/test/fixtures.ts create mode 100644 mobile/test/harness.tsx create mode 100644 mobile/test/mocks/client.ts create mode 100644 mobile/test/roles.test.tsx create mode 100644 mobile/test/screens.test.tsx create mode 100644 mobile/test/setup.tsx diff --git a/mobile/README.md b/mobile/README.md index 3ea9d0f..db39538 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -26,6 +26,39 @@ control plane an attacker has to breach separately; keeping a guardian key on th approver key collapses the two planes the contract works to keep apart. The app says so where it matters, and the contract will refuse to give one address both roles anyway. +## Testing it + +```bash +npm test +``` + +Twenty-eight tests that render the real screens and press their real buttons. They exist in this +form because there is no way to send a touch to a device from a headless machine — no Simulator +GUI, no `idb_companion` — and because a render-and-press suite is repeatable in a way a +hand-driven simulator session is not. + +What they cover is the part of the interface that can actually hurt someone: **which action each +role is offered**. The contract refuses an action the caller has no role for, so an interface that +offers it is not merely unsafe, it is lying to the person holding the phone. So each case asserts +both halves — what appears, and what does not: + +- an approver is offered Approve and Reject, and not Execute; +- an executor the reverse; +- a guardian is never offered Approve on a payment, only Confirm and Veto; +- an **agent is offered nothing at all**, because proposing is the whole of its authority; +- a veto appears on a critical payment and on a weakening, and not on a routine one; +- approvals are counted against live roles, so a removed signer's approval shows as not counting; +- a disabled Execute does not fire when pressed. + +Two things about React Native Testing Library 14 that cost real time, recorded so they do not cost +it twice: **`render` and `fireEvent` are both asynchronous.** An un-awaited `fireEvent` does not +fail the test that fired it — it leaves React's work queue mid-flight, and the *next* test's render +resolves to an empty tree, which looks like a dozen unrelated failures. + +The action buttons carry `testID`s rather than being found by their labels, because the Execute +button's label changes with its state — "Not enough approvals yet" until it is ready — and that +state is exactly what is worth testing. + ## Running it ```bash diff --git a/mobile/jest.config.js b/mobile/jest.config.js new file mode 100644 index 0000000..aa51fbb --- /dev/null +++ b/mobile/jest.config.js @@ -0,0 +1,37 @@ +/** + * Tests render the real screens and fire their real handlers. + * + * This is how the app's behaviour is verified: this environment has no Simulator GUI and no + * idb_companion, so there is no way to send a touch to a running device. Rendering the component + * tree and pressing through it is both closer to the code and repeatable, which a hand-driven + * simulator session is not. + */ +const preset = require('jest-expo/jest-preset'); + +module.exports = { + preset: 'jest-expo', + // The Sui SDK's gRPC entry is built from `.mjs` chunks, which the preset's `\.[jt]sx?$` pattern + // does not match — so Jest would hand raw ESM to a CommonJS runtime. The same gap Metro had. + // + // The preset's own transforms are kept rather than replaced: they are what handle React Native's + // Flow-typed sources, and dropping them fails on the first `value(id: TimeoutID)` it meets. + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'mjs', 'json', 'node'], + transform: { ...preset.transform, '^.+\\.mjs$': preset.transform['\\.[jt]sx?$'] }, + setupFilesAfterEnv: ['/test/setup.tsx'], + testMatch: ['/test/**/*.test.tsx'], + // The Sui SDK and its dependencies ship ESM, which Jest has to transform rather than skip. + transformIgnorePatterns: [ + 'node_modules/(?!((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|react-native-svg|@mysten/.*|@skur/.*|@protobuf-ts/.*|@noble/.*|@scure/.*|valibot|graphql|gql.tada|poseidon-lite))', + ], + moduleNameMapper: { + // The screens import the client for its type and its proxy; tests supply their own data. + '^../lib/client$': '/test/mocks/client.ts', + '^../../lib/client$': '/test/mocks/client.ts', + // @skur/sdk is ESM with an exports map holding only `import`, which Jest's CommonJS resolver + // does not read. Point at the build output and let Babel transform it like any source file. + '^@skur/sdk$': '/../sdk/dist/index.js', + // Babel's helpers are required from the transformed SDK, which sits outside this package and + // so cannot resolve them on its own. + '^@babel/runtime/(.*)$': '/node_modules/@babel/runtime/$1', + }, +}; diff --git a/mobile/package-lock.json b/mobile/package-lock.json index f1ddffb..f0011ce 100644 --- a/mobile/package-lock.json +++ b/mobile/package-lock.json @@ -36,7 +36,12 @@ "react-native-screens": "~4.26.0" }, "devDependencies": { + "@testing-library/react-native": "^14.0.1", + "@types/jest": "^30.0.0", "@types/react": "~19.2.2", + "jest": "^29.7.0", + "jest-expo": "^57.0.5", + "react-test-renderer": "^19.2.3", "typescript": "~6.0.3" } }, @@ -428,6 +433,61 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-decorators": { "version": "7.29.7", "license": "MIT", @@ -477,6 +537,48 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.29.7", "license": "MIT", @@ -490,6 +592,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", "license": "MIT", @@ -500,6 +615,45 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", "license": "MIT", @@ -510,6 +664,38 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.29.7", "license": "MIT", @@ -983,6 +1169,13 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, "node_modules/@expo-google-fonts/dm-mono": { "version": "0.4.2", "license": "MIT AND OFL-1.1" @@ -1341,1619 +1534,4769 @@ "node": ">=12" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "license": "MIT", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "devOptional": true, + "license": "ISC", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@jest/types": { - "version": "29.6.3", + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "devOptional": true, "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "sprintf-js": "~1.0.2" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "devOptional": true, "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "engines": { + "node": ">=6" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "devOptional": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.6.0", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/bcs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-2.1.2.tgz", - "integrity": "sha512-fv6lyuZMTHN0xRlu4GYiV/UXUrdJDOHbXm1KfZYEU0sy/t+22yTrTVtWnAQv1Km7eyB3qHhwIrAG2aem4JMocw==", - "license": "Apache-2.0", + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", "dependencies": { - "@mysten/utils": "^0.4.1", - "@scure/base": "^2.3.0" + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/@mysten/bcs/node_modules/@scure/base": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", - "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "node_modules/@jest/core/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": ">=8" } }, - "node_modules/@mysten/sui": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-2.34.0.tgz", - "integrity": "sha512-Qf/xt10YIJv3Yo0hQTU70xPgimFfw2mudBzI/dylGXZNuhuQVmkmxUm0fz49BFPOFvBxWc/MRFl204zwpwRnXw==", - "license": "Apache-2.0", + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", "dependencies": { - "@graphql-typed-document-node/core": "^3.2.0", - "@mysten/bcs": "^2.1.2", - "@mysten/utils": "^0.4.1", - "@noble/curves": "^2.3.0", - "@noble/hashes": "^2.3.0", - "@protobuf-ts/grpcweb-transport": "^2.11.1", - "@protobuf-ts/runtime": "^2.11.1", - "@protobuf-ts/runtime-rpc": "^2.11.1", - "@scure/base": "^2.3.0", - "@scure/bip32": "^2.3.0", - "@scure/bip39": "^2.3.0", - "gql.tada": "^1.11.3", - "graphql": "^17.0.2", - "poseidon-lite": "0.3.0", - "valibot": "^1.4.2" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">=22" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/sui/node_modules/@noble/curves": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", - "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "devOptional": true, "license": "MIT", "dependencies": { - "@noble/hashes": "2.4.0" + "@jest/types": "^29.6.3" }, "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/sui/node_modules/@noble/hashes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", - "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "node_modules/@jest/diff-sequences": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@mysten/sui/node_modules/@scure/base": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", - "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "devOptional": true, "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/sui/node_modules/@scure/bip32": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.4.0.tgz", - "integrity": "sha512-i3DS0CptAocyvqE4n3SUkpzeQK4vJMFwWLofTwRiiKo2aWojBOfyMCgfKw9HVpO6fSY5AK86sHS/Uzn8kK9Few==", + "node_modules/@jest/environment/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "devOptional": true, "license": "MIT", "dependencies": { - "@noble/curves": "2.4.0", - "@noble/hashes": "2.4.0", - "@scure/base": "2.4.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/sui/node_modules/@scure/bip39": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.4.0.tgz", - "integrity": "sha512-82dxFbZUYboyOf0AXiydsQrFQ5Q4h9mX+O2UkE91ROYmsc0BKMGZLwDmy96Jpa2+vrtoxomjUhy1RPIgH/r2nA==", + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, "license": "MIT", "dependencies": { - "@noble/hashes": "2.4.0" + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@mysten/utils": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@mysten/utils/-/utils-0.4.1.tgz", - "integrity": "sha512-gffLJ84CbqG/CcOPuVlwXIRu37tFn0BtUx7CQtbLwJzWjUE7FU2Gq8BXWjzxImnvufcyLTaNWtCPG6wq22Zhog==", - "license": "Apache-2.0", + "node_modules/@jest/expect-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz", + "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==", + "dev": true, + "license": "MIT", "dependencies": { - "@scure/base": "^2.3.0" + "@jest/get-type": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@mysten/utils/node_modules/@scure/base": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", - "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", + "node_modules/@jest/expect/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@protobuf-ts/grpcweb-transport": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@protobuf-ts/grpcweb-transport/-/grpcweb-transport-2.11.1.tgz", - "integrity": "sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==", - "license": "Apache-2.0", "dependencies": { - "@protobuf-ts/runtime": "^2.11.1", - "@protobuf-ts/runtime-rpc": "^2.11.1" + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@protobuf-ts/runtime": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", - "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, - "node_modules/@protobuf-ts/runtime-rpc": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", - "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", - "license": "Apache-2.0", + "node_modules/@jest/expect/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", "dependencies": { - "@protobuf-ts/runtime": "^2.11.1" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native-async-storage/async-storage": { - "version": "2.2.0", + "node_modules/@jest/expect/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, "license": "MIT", "dependencies": { - "merge-options": "^3.0.4" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, - "peerDependencies": { - "react-native": "^0.0.0-0 || >=0.65 <1.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/assets-registry": { - "version": "0.86.3", + "node_modules/@jest/expect/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/babel-plugin-codegen": { - "version": "0.86.3", + "node_modules/@jest/expect/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.29.0", - "@react-native/codegen": "0.86.3" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/codegen": { - "version": "0.86.3", + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "devOptional": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.25.2", - "@babel/parser": "^7.29.0", - "hermes-parser": "0.36.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "tinyglobby": "^0.2.15", - "yargs": "^17.6.2" + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@babel/core": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/codegen/node_modules/hermes-estree": { - "version": "0.36.0", - "license": "MIT" - }, - "node_modules/@react-native/codegen/node_modules/hermes-parser": { - "version": "0.36.0", + "node_modules/@jest/fake-timers/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "devOptional": true, "license": "MIT", "dependencies": { - "hermes-estree": "0.36.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/community-cli-plugin": { - "version": "0.86.3", + "node_modules/@jest/fake-timers/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "devOptional": true, "license": "MIT", "dependencies": { - "@react-native/dev-middleware": "0.86.3", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "metro": "^0.84.3", - "metro-config": "^0.84.3", - "metro-core": "^0.84.3", - "semver": "^7.1.3" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - }, - "peerDependencies": { - "@react-native-community/cli": "*", - "@react-native/metro-config": "0.86.3" - }, - "peerDependenciesMeta": { - "@react-native-community/cli": { - "optional": true - }, - "@react-native/metro-config": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/debugger-frontend": { - "version": "0.86.3", - "license": "BSD-3-Clause", + "node_modules/@jest/get-type": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", + "dev": true, + "license": "MIT", "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@react-native/debugger-shell": { - "version": "0.86.3", + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", - "debug": "^4.4.0", - "fb-dotslash": "0.5.8" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/dev-middleware": { - "version": "0.86.3", + "node_modules/@jest/globals/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, "license": "MIT", "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.86.3", - "@react-native/debugger-shell": "0.86.3", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.3.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "serve-static": "^1.16.2", - "ws": "^7.5.10" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-native/gradle-plugin": { - "version": "0.86.3", + "node_modules/@jest/pattern": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", + "dev": true, "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.5.0" + }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@react-native/js-polyfills": { - "version": "0.86.3", + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", + "dev": true, "license": "MIT", "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/@react-native/normalize-colors": { - "version": "0.86.3", + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, "license": "MIT" }, - "node_modules/@react-native/virtualized-lists": { - "version": "0.86.3", + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, "license": "MIT", "dependencies": { - "invariant": "^2.2.4", - "nullthrows": "^1.1.1" + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "@types/react": "^19.2.0", - "react": "*", - "react-native": "0.86.3" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { - "@types/react": { + "node-notifier": { "optional": true } } }, - "node_modules/@react-navigation/bottom-tabs": { - "version": "7.19.1", + "node_modules/@jest/reporters/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/reporters/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, "license": "MIT", "dependencies": { - "@react-navigation/elements": "^2.9.42", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0" - }, - "peerDependencies": { - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@react-navigation/core": { - "version": "7.22.1", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", "dependencies": { - "@react-navigation/routers": "^7.6.4", - "escape-string-regexp": "^4.0.0", - "fast-deep-equal": "^3.1.3", - "nanoid": "^3.3.11", - "react-is": "^19.1.0", - "use-latest-callback": "^0.2.4", - "use-sync-external-store": "^1.5.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "peerDependencies": { - "react": ">= 18.2.0" + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@react-navigation/core/node_modules/react-is": { - "version": "19.3.0", - "license": "MIT" - }, - "node_modules/@react-navigation/elements": { - "version": "2.9.42", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "color": "^4.2.3", - "use-latest-callback": "^0.2.4", - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@react-native-masked-view/masked-view": ">= 0.2.0", - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" }, - "peerDependenciesMeta": { - "@react-native-masked-view/masked-view": { - "optional": true - } + "engines": { + "node": ">=10" } }, - "node_modules/@react-navigation/native": { - "version": "7.4.1", + "node_modules/@jest/reporters/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", "dependencies": { - "@react-navigation/core": "^7.22.1", - "escape-string-regexp": "^4.0.0", - "fast-deep-equal": "^3.1.3", - "nanoid": "^3.3.11", - "standard-navigation": "^0.0.8", - "use-latest-callback": "^0.2.4" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, - "peerDependencies": { - "react": ">= 18.2.0", - "react-native": "*" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@react-navigation/native-stack": { - "version": "7.19.1", - "license": "MIT", + "node_modules/@jest/reporters/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", "dependencies": { - "@react-navigation/elements": "^2.9.42", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0", - "warn-once": "^0.1.1" + "brace-expansion": "^1.1.7" }, - "peerDependencies": { - "@react-navigation/native": "^7.4.1", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" + "engines": { + "node": "*" } }, - "node_modules/@react-navigation/routers": { - "version": "7.6.4", + "node_modules/@jest/schemas": { + "version": "29.6.3", "license": "MIT", "dependencies": { - "nanoid": "^3.3.11" + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.12", - "license": "MIT" - }, - "node_modules/@skur/sdk": { - "resolved": "../sdk", - "link": true - }, - "node_modules/@tanstack/query-core": { - "version": "5.102.8", + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@tanstack/react-query": { - "version": "5.102.8", + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.102.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" }, - "peerDependencies": { - "react": "^18 || ^19" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/emscripten": { - "version": "1.41.6", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "*" + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "devOptional": true, "license": "MIT", "dependencies": { - "@types/istanbul-lib-report": "*" + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/node": { - "version": "22.20.3", + "node_modules/@jest/types": { + "version": "29.6.3", "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@types/react": { - "version": "19.2.18", - "devOptional": true, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", "license": "MIT", "dependencies": { - "csstype": "^3.2.2" + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@types/yargs": { - "version": "17.0.35", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "license": "MIT" - }, - "node_modules/@ungap/structured-clone": { - "version": "1.4.0", - "license": "ISC" - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.15", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=6.0.0" } }, - "node_modules/abort-controller": { - "version": "3.0.0", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", "license": "MIT", "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/accepts": { - "version": "2.0.0", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", "license": "MIT", "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } }, - "node_modules/acorn": { - "version": "8.18.0", - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" + "node_modules/@mysten/bcs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-2.1.2.tgz", + "integrity": "sha512-fv6lyuZMTHN0xRlu4GYiV/UXUrdJDOHbXm1KfZYEU0sy/t+22yTrTVtWnAQv1Km7eyB3qHhwIrAG2aem4JMocw==", + "license": "Apache-2.0", + "dependencies": { + "@mysten/utils": "^0.4.1", + "@scure/base": "^2.3.0" } }, - "node_modules/agent-base": { - "version": "7.1.4", + "node_modules/@mysten/bcs/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", "license": "MIT", - "engines": { - "node": ">= 14" + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/agent-cli-detector": { - "version": "0.1.7", - "license": "MIT", - "bin": { - "agent-cli-detector": "dist/cli.js" + "node_modules/@mysten/sui": { + "version": "2.34.0", + "resolved": "https://registry.npmjs.org/@mysten/sui/-/sui-2.34.0.tgz", + "integrity": "sha512-Qf/xt10YIJv3Yo0hQTU70xPgimFfw2mudBzI/dylGXZNuhuQVmkmxUm0fz49BFPOFvBxWc/MRFl204zwpwRnXw==", + "license": "Apache-2.0", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "@mysten/bcs": "^2.1.2", + "@mysten/utils": "^0.4.1", + "@noble/curves": "^2.3.0", + "@noble/hashes": "^2.3.0", + "@protobuf-ts/grpcweb-transport": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "@scure/base": "^2.3.0", + "@scure/bip32": "^2.3.0", + "@scure/bip39": "^2.3.0", + "gql.tada": "^1.11.3", + "graphql": "^17.0.2", + "poseidon-lite": "0.3.0", + "valibot": "^1.4.2" }, "engines": { - "node": ">=18.18" + "node": ">=22" } }, - "node_modules/anser": { - "version": "1.4.10", - "license": "MIT" - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", + "node_modules/@mysten/sui/node_modules/@noble/curves": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz", + "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==", "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" + "@noble/hashes": "2.4.0" }, "engines": { - "node": ">=8" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "license": "(MIT OR CC0-1.0)", + "node_modules/@mysten/sui/node_modules/@noble/hashes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz", + "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/@mysten/sui/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", "license": "MIT", - "engines": { - "node": ">=8" + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/@mysten/sui/node_modules/@scure/bip32": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-2.4.0.tgz", + "integrity": "sha512-i3DS0CptAocyvqE4n3SUkpzeQK4vJMFwWLofTwRiiKo2aWojBOfyMCgfKw9HVpO6fSY5AK86sHS/Uzn8kK9Few==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" + "@noble/curves": "2.4.0", + "@noble/hashes": "2.4.0", + "@scure/base": "2.4.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/arg": { - "version": "5.0.2", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0" - }, - "node_modules/asap": { - "version": "2.0.6", - "license": "MIT" - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.17", + "node_modules/@mysten/sui/node_modules/@scure/bip39": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-2.4.0.tgz", + "integrity": "sha512-82dxFbZUYboyOf0AXiydsQrFQ5Q4h9mX+O2UkE91ROYmsc0BKMGZLwDmy96Jpa2+vrtoxomjUhy1RPIgH/r2nA==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.8", - "semver": "^6.3.1" + "@noble/hashes": "2.4.0" }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node_modules/@mysten/utils": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@mysten/utils/-/utils-0.4.1.tgz", + "integrity": "sha512-gffLJ84CbqG/CcOPuVlwXIRu37tFn0BtUx7CQtbLwJzWjUE7FU2Gq8BXWjzxImnvufcyLTaNWtCPG6wq22Zhog==", + "license": "Apache-2.0", + "dependencies": { + "@scure/base": "^2.3.0" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", + "node_modules/@mysten/utils/node_modules/@scure/base": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz", + "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==", "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@protobuf-ts/grpcweb-transport": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/grpcweb-transport/-/grpcweb-transport-2.11.1.tgz", + "integrity": "sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==", + "license": "Apache-2.0", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.8", + "node_modules/@protobuf-ts/runtime": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime/-/runtime-2.11.1.tgz", + "integrity": "sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==", + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, + "node_modules/@protobuf-ts/runtime-rpc": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@protobuf-ts/runtime-rpc/-/runtime-rpc-2.11.1.tgz", + "integrity": "sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==", + "license": "Apache-2.0", + "dependencies": { + "@protobuf-ts/runtime": "^2.11.1" + } + }, + "node_modules/@react-native-async-storage/async-storage": { + "version": "2.2.0", "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.8" + "merge-options": "^3.0.4" }, "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + "react-native": "^0.0.0-0 || >=0.65 <1.0" } }, - "node_modules/babel-plugin-react-compiler": { - "version": "1.0.0", + "node_modules/@react-native/assets-registry": { + "version": "0.86.3", "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.0" + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/babel-plugin-react-native-web": { - "version": "0.21.2", - "license": "MIT" + "node_modules/@react-native/babel-plugin-codegen": { + "version": "0.86.3", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.86.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } }, - "node_modules/babel-plugin-syntax-hermes-parser": { - "version": "0.36.0", + "node_modules/@react-native/codegen": { + "version": "0.86.3", "license": "MIT", "dependencies": { - "hermes-parser": "0.36.0" + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" } }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "node_modules/@react-native/codegen/node_modules/hermes-estree": { "version": "0.36.0", "license": "MIT" }, - "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "node_modules/@react-native/codegen/node_modules/hermes-parser": { "version": "0.36.0", "license": "MIT", "dependencies": { "hermes-estree": "0.36.0" } }, - "node_modules/babel-plugin-transform-flow-enums": { - "version": "0.0.2", + "node_modules/@react-native/community-cli-plugin": { + "version": "0.86.3", "license": "MIT", "dependencies": { - "@babel/plugin-syntax-flow": "^7.12.1" - } - }, - "node_modules/badgin": { - "version": "1.2.3", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.4", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/barcode-detector": { - "version": "3.2.2", - "license": "MIT", - "dependencies": { - "zxing-wasm": "3.1.3" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.11.24", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" + "@react-native/dev-middleware": "0.86.3", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.84.3", + "metro-config": "^0.84.3", + "metro-core": "^0.84.3", + "semver": "^7.1.3" }, "engines": { - "node": ">=6.0.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.86.3" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } } }, - "node_modules/big-integer": { - "version": "1.6.52", - "license": "Unlicense", + "node_modules/@react-native/debugger-frontend": { + "version": "0.86.3", + "license": "BSD-3-Clause", "engines": { - "node": ">=0.6" - } - }, - "node_modules/bplist-creator": { - "version": "0.1.0", - "license": "MIT", - "dependencies": { - "stream-buffers": "2.2.x" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/bplist-parser": { - "version": "0.3.1", + "node_modules/@react-native/debugger-shell": { + "version": "0.86.3", "license": "MIT", "dependencies": { - "big-integer": "1.6.x" + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" }, "engines": { - "node": ">= 5.10.0" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/brace-expansion": { - "version": "5.0.12", + "node_modules/@react-native/dev-middleware": { + "version": "0.86.3", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.86.3", + "@react-native/debugger-shell": "0.86.3", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.3.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" }, "engines": { - "node": "20 || >=22" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/braces": { - "version": "3.0.3", + "node_modules/@react-native/gradle-plugin": { + "version": "0.86.3", "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, "engines": { - "node": ">=8" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/browserslist": { - "version": "4.29.0", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/@react-native/jest-preset": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/jest-preset/-/jest-preset-0.86.3.tgz", + "integrity": "sha512-oMmBwXUpTgJvGlcXQQPuiQLykoM8jsWYp6RwdJ2NWyIWzJcGp1rmSr3XV7istoIcUt0wdOVLtQs0A0nDm9ND+A==", + "devOptional": true, "license": "MIT", + "peer": true, "dependencies": { - "baseline-browser-mapping": "^2.11.23", - "caniuse-lite": "^1.0.30001810", - "electron-to-chromium": "^1.5.427", - "node-releases": "^2.0.55", - "update-browserslist-db": "^1.3.3" - }, - "bin": { - "browserslist": "cli.js" + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/js-polyfills": "0.86.3", + "babel-jest": "^29.7.0", + "jest-environment-node": "^29.7.0", + "regenerator-runtime": "^0.13.2" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "node": ">= 20.19.4" + }, + "peerDependencies": { + "react": "^19.2.3" } }, - "node_modules/camelcase": { - "version": "6.3.0", + "node_modules/@react-native/js-polyfills": { + "version": "0.86.3", "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001810", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" + "node_modules/@react-native/normalize-colors": { + "version": "0.86.3", + "license": "MIT" }, - "node_modules/chalk": { - "version": "4.1.2", + "node_modules/@react-native/virtualized-lists": { + "version": "0.86.3", "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" }, "engines": { - "node": ">=10" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "0.86.3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/chrome-launcher": { - "version": "0.15.2", - "license": "Apache-2.0", + "node_modules/@react-navigation/bottom-tabs": { + "version": "7.19.1", + "license": "MIT", "dependencies": { - "@types/node": "*", - "escape-string-regexp": "^4.0.0", - "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0" - }, - "bin": { - "print-chrome-path": "bin/print-chrome-path.js" + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0" }, - "engines": { - "node": ">=12.13.0" + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" } }, - "node_modules/chromium-edge-launcher": { - "version": "0.3.0", - "license": "Apache-2.0", + "node_modules/@react-navigation/core": { + "version": "7.22.1", + "license": "MIT", "dependencies": { - "@types/node": "*", + "@react-navigation/routers": "^7.6.4", "escape-string-regexp": "^4.0.0", - "is-wsl": "^2.2.0", - "lighthouse-logger": "^1.0.0", - "mkdirp": "^1.0.4" + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "react-is": "^19.1.0", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "react": ">= 18.2.0" } }, - "node_modules/ci-info": { - "version": "2.0.0", + "node_modules/@react-navigation/core/node_modules/react-is": { + "version": "19.3.0", "license": "MIT" }, - "node_modules/cli-cursor": { - "version": "2.1.0", + "node_modules/@react-navigation/elements": { + "version": "2.9.42", "license": "MIT", "dependencies": { - "restore-cursor": "^2.0.0" + "color": "^4.2.3", + "use-latest-callback": "^0.2.4", + "use-sync-external-store": "^1.5.0" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "@react-native-masked-view/masked-view": ">= 0.2.0", + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0" + }, + "peerDependenciesMeta": { + "@react-native-masked-view/masked-view": { + "optional": true + } } }, - "node_modules/cli-spinners": { - "version": "2.9.2", + "node_modules/@react-navigation/native": { + "version": "7.4.1", "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "@react-navigation/core": "^7.22.1", + "escape-string-regexp": "^4.0.0", + "fast-deep-equal": "^3.1.3", + "nanoid": "^3.3.11", + "standard-navigation": "^0.0.8", + "use-latest-callback": "^0.2.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*" } }, - "node_modules/cliui": { - "version": "8.0.1", - "license": "ISC", + "node_modules/@react-navigation/native-stack": { + "version": "7.19.1", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "@react-navigation/elements": "^2.9.42", + "color": "^4.2.3", + "sf-symbols-typescript": "^2.1.0", + "warn-once": "^0.1.1" }, - "engines": { - "node": ">=12" + "peerDependencies": { + "@react-navigation/native": "^7.4.1", + "react": ">= 18.2.0", + "react-native": "*", + "react-native-safe-area-context": ">= 4.0.0", + "react-native-screens": ">= 4.0.0" } }, - "node_modules/clone": { - "version": "1.0.4", + "node_modules/@react-navigation/routers": { + "version": "7.6.4", "license": "MIT", - "engines": { - "node": ">=0.8" + "dependencies": { + "nanoid": "^3.3.11" } }, - "node_modules/color": { - "version": "4.2.3", + "node_modules/@sinclair/typebox": { + "version": "0.27.12", + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@skur/sdk": { + "resolved": "../sdk", + "link": true + }, + "node_modules/@tanstack/query-core": { + "version": "5.102.8", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.102.8", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" + "@tanstack/query-core": "5.102.8" }, - "engines": { - "node": ">=12.5.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" } }, - "node_modules/color-convert": { - "version": "2.0.1", + "node_modules/@testing-library/react-native": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-14.0.1.tgz", + "integrity": "sha512-2r2e2y8SkUNRWKRXlUGqDYunB+AkbdXUPn49Bs5rpv9oxRb0K3USBVugbPbAKJjfj4w5Ba91NJ8LcQCZyopUZA==", + "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "jest-matcher-utils": "^30.4.1", + "picocolors": "^1.1.1", + "pretty-format": "^30.4.1", + "redent": "^3.0.0" }, "engines": { - "node": ">=7.0.0" + "node": "^22.13.0 || >=24" + }, + "peerDependencies": { + "jest": ">=29.0.0", + "react": ">=19.0.0", + "react-native": ">=0.78", + "test-renderer": "^1.0.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } } }, - "node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, - "node_modules/color-string": { - "version": "1.9.1", + "node_modules/@testing-library/react-native/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/commander": { - "version": "7.2.0", + "node_modules/@testing-library/react-native/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react-native/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/compressible": { - "version": "2.0.18", + "node_modules/@testing-library/react-native/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": ">= 1.43.0 < 2" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/compression": { - "version": "1.8.2", + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, "license": "MIT", - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "destroy": "1.2.0", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, "engines": { - "node": ">= 0.8.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 10" } }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "devOptional": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" } }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/compression/node_modules/negotiator": { - "version": "0.6.4", + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "devOptional": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "@babel/types": "^7.0.0" } }, - "node_modules/connect": { - "version": "3.7.0", + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "devOptional": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" - }, - "engines": { - "node": ">= 0.10.0" + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "devOptional": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@babel/types": "^7.28.2" } }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", + "node_modules/@types/emscripten": { + "version": "1.41.6", "license": "MIT" }, - "node_modules/content-type": { - "version": "2.1.0", + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "devOptional": true, "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "dependencies": { + "@types/node": "*" } }, - "node_modules/convert-source-map": { - "version": "2.0.0", + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", "license": "MIT" }, - "node_modules/core-js-compat": { - "version": "3.50.0", + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", "license": "MIT", "dependencies": { - "browserslist": "^4.28.7" - }, - "engines": { - "node": ">=6.4.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "@types/istanbul-lib-coverage": "*" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": ">= 8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/csstype": { - "version": "3.2.3", - "devOptional": true, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, "engines": { - "node": ">=6.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/deepmerge": { - "version": "4.3.1", + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/defaults": { - "version": "1.0.4", + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, "license": "MIT", "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" } }, - "node_modules/depd": { - "version": "2.0.0", + "node_modules/@types/node": { + "version": "22.20.3", "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "undici-types": "~6.21.0" } }, - "node_modules/destroy": { - "version": "1.2.0", + "node_modules/@types/react": { + "version": "19.2.18", + "devOptional": true, "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "dependencies": { + "csstype": "^3.2.2" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "license": "Apache-2.0", - "engines": { - "node": ">=8" + "node_modules/@types/react-reconciler": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.33.1.tgz", + "integrity": "sha512-0kF59ji2mKuHUd5wytHSpmORybMYVerJvq0K10pz9ZFoOlJ3e+w1LBjLshWpCrokeyQOioRodNbO4PH4ddvRfg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@types/react": "*" } }, - "node_modules/dnssd-advertise": { - "version": "1.1.6", + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "devOptional": true, "license": "MIT" }, - "node_modules/ee-first": { - "version": "1.1.1", + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, "license": "MIT" }, - "node_modules/electron-to-chromium": { - "version": "1.5.429", - "license": "ISC" + "node_modules/@types/yargs": { + "version": "17.0.35", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } }, - "node_modules/emoji-regex": { - "version": "8.0.0", + "node_modules/@types/yargs-parser": { + "version": "21.0.3", "license": "MIT" }, - "node_modules/encodeurl": { - "version": "1.0.2", + "node_modules/@ungap/structured-clone": { + "version": "1.4.0", + "license": "ISC" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.15", "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=10.0.0" } }, - "node_modules/error-stack-parser": { - "version": "2.1.4", + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abort-controller": { + "version": "3.0.0", "license": "MIT", "dependencies": { - "stackframe": "^1.3.4" + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" } }, - "node_modules/es-errors": { - "version": "1.3.0", + "node_modules/accepts": { + "version": "2.0.0", "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, "engines": { - "node": ">= 0.4" + "node": ">= 0.6" } }, - "node_modules/escalade": { - "version": "3.2.0", + "node_modules/acorn": { + "version": "8.18.0", "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=6" + "node": ">=0.4.0" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" } }, - "node_modules/etag": { - "version": "1.8.1", + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=0.4.0" } }, - "node_modules/event-target-shim": { - "version": "5.0.1", + "node_modules/agent-base": { + "version": "7.1.4", "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 14" } }, - "node_modules/expo": { - "version": "57.0.23", + "node_modules/agent-cli-detector": { + "version": "0.1.7", "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.20.0", - "@expo/cli": "^57.0.25", - "@expo/config": "~57.0.9", - "@expo/config-plugins": "~57.0.9", - "@expo/devtools": "~57.0.1", - "@expo/dom-webview": "~57.0.1", - "@expo/fingerprint": "^0.20.13", - "@expo/local-build-cache-provider": "^57.0.8", - "@expo/log-box": "^57.0.4", - "@expo/metro": "~56.0.2", - "@expo/metro-config": "~57.0.12", - "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~57.0.12", - "expo-asset": "~57.0.17", - "expo-constants": "~57.0.18", - "expo-file-system": "~57.0.7", - "expo-font": "~57.0.4", - "expo-keep-awake": "~57.0.2", - "expo-modules-autolinking": "~57.0.13", - "expo-modules-core": "~57.0.18", - "pretty-format": "^29.7.0", - "react-refresh": "^0.14.2", - "whatwg-url-minimum": "^0.1.2" - }, "bin": { - "expo": "bin/cli", - "expo-modules-autolinking": "bin/autolinking", - "fingerprint": "bin/fingerprint" - }, - "peerDependencies": { - "@expo/dom-webview": "*", - "@expo/metro-runtime": "*", - "react": "*", - "react-dom": "*", - "react-native": "*", - "react-native-web": "*", - "react-native-webview": "*" + "agent-cli-detector": "dist/cli.js" }, - "peerDependenciesMeta": { - "@expo/dom-webview": { - "optional": true - }, - "@expo/metro-runtime": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native-web": { - "optional": true - }, - "react-native-webview": { - "optional": true - } + "engines": { + "node": ">=18.18" } }, - "node_modules/expo-application": { - "version": "57.0.3", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } + "node_modules/anser": { + "version": "1.4.10", + "license": "MIT" }, - "node_modules/expo-camera": { - "version": "57.0.5", + "node_modules/ansi-escapes": { + "version": "4.3.2", "license": "MIT", "dependencies": { - "barcode-detector": "^3.0.0" + "type-fest": "^0.21.3" }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*", - "react-native-web": "*" + "engines": { + "node": ">=8" }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expo-clipboard": { - "version": "57.0.2", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/expo-constants": { - "version": "57.0.20", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.20.tgz", - "integrity": "sha512-WycPVvBgbluSa6yAh6DKnX646ZHrae0gV2ZLum5fioNkR+DiWyulq1+UfS++Jc6yfAh/l55NOirv6mt5cnQhSw==", + "node_modules/ansi-regex": { + "version": "5.0.1", "license": "MIT", - "dependencies": { - "@expo/env": "~2.4.3" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*" + "engines": { + "node": ">=8" } }, - "node_modules/expo-font": { - "version": "57.0.4", + "node_modules/ansi-styles": { + "version": "4.3.0", "license": "MIT", "dependencies": { - "fontfaceobserver": "^2.1.0" + "color-convert": "^2.0.1" }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expo-linking": { - "version": "57.0.10", - "license": "MIT", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "devOptional": true, + "license": "ISC", "dependencies": { - "expo-constants": "~57.0.18", - "invariant": "^2.2.4" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, - "peerDependencies": { - "react": "*", + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" + }, + "node_modules/asap": { + "version": "2.0.6", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/babel-plugin-react-native-web": { + "version": "0.21.2", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.0", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.0", + "license": "MIT" + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.0", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, + "node_modules/babel-plugin-transform-flow-enums": { + "version": "0.0.2", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-flow": "^7.12.1" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/badgin": { + "version": "1.2.3", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/barcode-detector": { + "version": "3.2.2", + "license": "MIT", + "dependencies": { + "zxing-wasm": "3.1.3" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.24", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/big-integer": { + "version": "1.6.52", + "license": "Unlicense", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bplist-creator": { + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "stream-buffers": "2.2.x" + } + }, + "node_modules/bplist-parser": { + "version": "0.3.1", + "license": "MIT", + "dependencies": { + "big-integer": "1.6.x" + }, + "engines": { + "node": ">= 5.10.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.3.0", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.2", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "destroy": "1.2.0", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/content-type": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.50.0", + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.7" + }, + "engines": { + "node": ">=6.4.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "devOptional": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dnssd-advertise": { + "version": "1.1.6", + "license": "MIT" + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.429", + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "devOptional": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect/node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expect/node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/expo": { + "version": "57.0.23", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "^57.0.25", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devtools": "~57.0.1", + "@expo/dom-webview": "~57.0.1", + "@expo/fingerprint": "^0.20.13", + "@expo/local-build-cache-provider": "^57.0.8", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~57.0.12", + "expo-asset": "~57.0.17", + "expo-constants": "~57.0.18", + "expo-file-system": "~57.0.7", + "expo-font": "~57.0.4", + "expo-keep-awake": "~57.0.2", + "expo-modules-autolinking": "~57.0.13", + "expo-modules-core": "~57.0.18", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-minimum": "^0.1.2" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-web": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-native-webview": { + "optional": true + } + } + }, + "node_modules/expo-application": { + "version": "57.0.3", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-camera": { + "version": "57.0.5", + "license": "MIT", + "dependencies": { + "barcode-detector": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "node_modules/expo-clipboard": { + "version": "57.0.2", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-constants": { + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.20.tgz", + "integrity": "sha512-WycPVvBgbluSa6yAh6DKnX646ZHrae0gV2ZLum5fioNkR+DiWyulq1+UfS++Jc6yfAh/l55NOirv6mt5cnQhSw==", + "license": "MIT", + "dependencies": { + "@expo/env": "~2.4.3" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "node_modules/expo-font": { + "version": "57.0.4", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-linking": { + "version": "57.0.10", + "license": "MIT", + "dependencies": { + "expo-constants": "~57.0.18", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-local-authentication": { + "version": "57.0.3", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-modules-autolinking": { + "version": "57.0.13", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.1.0", + "commander": "^7.2.0" + }, + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + } + }, + "node_modules/expo-modules-core": { + "version": "57.0.18", + "license": "MIT", + "dependencies": { + "@expo/expo-modules-macros-plugin": "0.6.1", + "expo-modules-jsi": "~57.1.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" + }, + "peerDependenciesMeta": { + "react-native-worklets": { + "optional": true + } + } + }, + "node_modules/expo-modules-jsi": { + "version": "57.1.0", + "license": "MIT", + "peerDependencies": { + "react-native": "*" + } + }, + "node_modules/expo-notifications": { + "version": "57.0.19", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "abort-controller": "^3.0.0", + "badgin": "^1.1.5", + "expo-application": "~57.0.3", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo-secure-store": { + "version": "57.0.4", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-server": { + "version": "57.0.3", + "license": "MIT", + "engines": { + "node": ">=20.16.0" + } + }, + "node_modules/expo-status-bar": { + "version": "57.0.1", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/cli": { + "version": "57.0.25", + "license": "MIT", + "dependencies": { + "@expo/code-signing-certificates": "^0.0.6", + "@expo/config": "~57.0.9", + "@expo/config-plugins": "~57.0.9", + "@expo/devcert": "^1.2.1", + "@expo/env": "~2.4.3", + "@expo/image-utils": "^0.11.5", + "@expo/inline-modules": "^0.1.7", + "@expo/json-file": "^11.0.1", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.12", + "@expo/metro-file-map": "^57.0.3", + "@expo/osascript": "^2.7.1", + "@expo/package-manager": "^1.13.1", + "@expo/plist": "^0.8.1", + "@expo/prebuild-config": "^57.0.16", + "@expo/require-utils": "^57.0.5", + "@expo/router-server": "^57.0.10", + "@expo/schema-utils": "^57.0.2", + "@expo/spawn-async": "^1.8.0", + "@expo/ws-tunnel": "^2.0.0", + "@expo/xcpretty": "^4.4.4", + "@react-native/dev-middleware": "0.86.3", + "accepts": "^1.3.8", + "agent-cli-detector": "0.1.7", + "arg": "^5.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "debug": "^4.3.4", + "dnssd-advertise": "^1.1.4", + "expo-server": "^57.0.3", + "fetch-nodeshim": "^0.4.10", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.2.1", + "multitars": "^1.0.2", + "node-forge": "^1.3.3", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^4.0.4", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "resolve-from": "^5.0.0", + "sandbox-cli-detector": "^0.2.0", + "semver": "^7.6.0", + "send": "^0.19.0", + "slugify": "^1.3.4", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "terminal-link": "^2.1.1", + "toqr": "^0.1.1", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1", + "zod": "^3.25.76" + }, + "bin": { + "expo-internal": "main.js" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { + "version": "57.0.10", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "@expo/metro-runtime": "^57.0.15", + "expo": "*", + "expo-constants": "^57.0.18", + "expo-font": "^57.0.4", + "expo-router": "*", + "expo-server": "^57.0.3", + "react": "*", + "react-dom": "*", + "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" + }, + "peerDependenciesMeta": { + "@expo/metro-runtime": { + "optional": true + }, + "expo-router": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/dom-webview": { + "version": "57.0.1", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/log-box": { + "version": "57.0.4", + "license": "MIT", + "dependencies": { + "@expo/dom-webview": "^57.0.1", + "anser": "^1.4.9", + "stacktrace-parser": "^0.1.10" + }, + "peerDependencies": { + "@expo/dom-webview": "^57.0.1", + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/@expo/metro-config": { + "version": "57.0.12", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~57.0.9", + "@expo/env": "~2.4.3", + "@expo/json-file": "~11.0.1", + "@expo/metro": "~56.0.2", + "@expo/require-utils": "^57.0.5", + "@expo/spawn-async": "^1.8.0", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.36.0", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/@expo/ws-tunnel": { + "version": "2.0.0", + "license": "MIT", + "peerDependencies": { + "ws": "^8.0.0" + } + }, + "node_modules/expo/node_modules/accepts": { + "version": "1.3.8", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/babel-preset-expo": { + "version": "57.0.12", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^57.0.19", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, + "node_modules/expo/node_modules/ci-info": { + "version": "3.9.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expo/node_modules/expo-asset": { + "version": "57.0.17", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.5", + "expo-constants": "~57.0.18" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/expo/node_modules/expo-file-system": { + "version": "57.0.7", + "license": "MIT", + "peerDependencies": { + "expo": "*", "react-native": "*" } }, - "node_modules/expo-local-authentication": { - "version": "57.0.3", + "node_modules/expo/node_modules/expo-keep-awake": { + "version": "57.0.2", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "node_modules/expo/node_modules/hermes-estree": { + "version": "0.36.1", + "license": "MIT" + }, + "node_modules/expo/node_modules/hermes-parser": { + "version": "0.36.1", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "node_modules/expo/node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/negotiator": { + "version": "0.6.3", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expo/node_modules/picomatch": { + "version": "4.0.7", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/expo/node_modules/ws": { + "version": "8.21.3", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "license": "Apache-2.0" + }, + "node_modules/fast-base64-decode": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "license": "(MIT OR Apache-2.0)", + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fetch-nodeshim": { + "version": "0.4.10", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "license": "MIT" + }, + "node_modules/fontfaceobserver": { + "version": "2.3.0", + "license": "BSD-2-Clause" + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getenv": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gql.tada": { + "version": "1.11.4", + "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.11.4.tgz", + "integrity": "sha512-UQnhJUhSM0MV8cpcgjci/7ET8LnmHx9o9FtZqU4sH+ILiBVG5rnfXJzNdzTN+Y7MuCz6Pp3XE/VPEVqmO969jw==", + "license": "MIT", + "dependencies": { + "@0no-co/graphql.web": "^1.3.2", + "@0no-co/graphqlsp": "^1.17.3", + "@gql.tada/cli-utils": "1.9.4", + "@gql.tada/internal": "1.2.2" + }, + "bin": { + "gql-tada": "bin/cli.js", + "gql.tada": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/graphql": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-17.0.2.tgz", + "integrity": "sha512-FRWbddMxfkjiB7z+aQDWIR+E34xo9I8c9mtK2RPv8PmMzKRvrdsreHL/Ui/TmwHJfhHChEtsFPyMHKI+xuarQQ==", + "license": "MIT", + "engines": { + "node": "^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-compiler": { + "version": "250829098.0.17", + "license": "MIT" + }, + "node_modules/hermes-estree": { + "version": "0.35.0", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.35.0", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.2", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "devOptional": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/invariant": { + "version": "2.2.4", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "devOptional": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, "license": "MIT", "dependencies": { - "invariant": "^2.2.4" + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "expo": "*" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/expo-modules-autolinking": { - "version": "57.0.13", + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, "license": "MIT", "dependencies": { - "@expo/require-utils": "^57.0.5", - "@expo/spawn-async": "^1.8.0", - "chalk": "^4.1.0", - "commander": "^7.2.0" + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" }, - "bin": { - "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expo-modules-core": { - "version": "57.0.18", + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, "license": "MIT", "dependencies": { - "@expo/expo-modules-macros-plugin": "0.6.1", - "expo-modules-jsi": "~57.1.0", - "invariant": "^2.2.4" + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "react": "*", - "react-native": "*", - "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "peerDependenciesMeta": { - "react-native-worklets": { + "node-notifier": { "optional": true } } }, - "node_modules/expo-modules-jsi": { - "version": "57.1.0", + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, "peerDependencies": { - "react-native": "*" + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/expo-notifications": { - "version": "57.0.19", + "node_modules/jest-config/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-config/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, "license": "MIT", "dependencies": { - "@expo/image-utils": "^0.11.5", - "abort-controller": "^3.0.0", - "badgin": "^1.1.5", - "expo-application": "~57.0.3", - "expo-constants": "~57.0.18" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jest-config/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/expo-secure-store": { - "version": "57.0.4", + "node_modules/jest-config/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jest-diff": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz", + "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==", + "dev": true, "license": "MIT", - "peerDependencies": { - "expo": "*" + "dependencies": { + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo-server": { - "version": "57.0.3", + "node_modules/jest-diff/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, "engines": { - "node": ">=20.16.0" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo-status-bar": { - "version": "57.0.1", + "node_modules/jest-diff/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expo/node_modules/@expo/cli": { - "version": "57.0.25", + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, "license": "MIT", "dependencies": { - "@expo/code-signing-certificates": "^0.0.6", - "@expo/config": "~57.0.9", - "@expo/config-plugins": "~57.0.9", - "@expo/devcert": "^1.2.1", - "@expo/env": "~2.4.3", - "@expo/image-utils": "^0.11.5", - "@expo/inline-modules": "^0.1.7", - "@expo/json-file": "^11.0.1", - "@expo/log-box": "^57.0.4", - "@expo/metro": "~56.0.2", - "@expo/metro-config": "~57.0.12", - "@expo/metro-file-map": "^57.0.3", - "@expo/osascript": "^2.7.1", - "@expo/package-manager": "^1.13.1", - "@expo/plist": "^0.8.1", - "@expo/prebuild-config": "^57.0.16", - "@expo/require-utils": "^57.0.5", - "@expo/router-server": "^57.0.10", - "@expo/schema-utils": "^57.0.2", - "@expo/spawn-async": "^1.8.0", - "@expo/ws-tunnel": "^2.0.0", - "@expo/xcpretty": "^4.4.4", - "@react-native/dev-middleware": "0.86.3", - "accepts": "^1.3.8", - "agent-cli-detector": "0.1.7", - "arg": "^5.0.2", - "bplist-creator": "0.1.0", - "bplist-parser": "^0.3.1", - "chalk": "^4.0.0", - "ci-info": "^3.3.0", - "compression": "^1.7.4", - "connect": "^3.7.0", - "debug": "^4.3.4", - "dnssd-advertise": "^1.1.4", - "expo-server": "^57.0.3", - "fetch-nodeshim": "^0.4.10", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "lan-network": "^0.2.1", - "multitars": "^1.0.2", - "node-forge": "^1.3.3", - "npm-package-arg": "^11.0.0", - "ora": "^3.4.0", - "picomatch": "^4.0.4", - "pretty-format": "^29.7.0", - "progress": "^2.0.3", - "prompts": "^2.3.2", - "resolve-from": "^5.0.0", - "sandbox-cli-detector": "^0.2.0", - "semver": "^7.6.0", - "send": "^0.19.0", - "slugify": "^1.3.4", - "stacktrace-parser": "^0.1.10", - "structured-headers": "^0.4.1", - "terminal-link": "^2.1.1", - "toqr": "^0.1.1", - "wrap-ansi": "^7.0.0", - "ws": "^8.12.1", - "zod": "^3.25.76" + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" }, - "bin": { - "expo-internal": "main.js" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "expo": "*", - "expo-router": "*", - "react-native": "*" + "canvas": "^2.5.0" }, "peerDependenciesMeta": { - "expo-router": { - "optional": true - }, - "react-native": { + "canvas": { "optional": true } } }, - "node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { - "version": "57.0.10", + "node_modules/jest-environment-jsdom/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.3.4" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-expo": { + "version": "57.0.5", + "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-57.0.5.tgz", + "integrity": "sha512-U08fwjaDBwnnbKnZcOA0WQbHfKqOWTCGku+IdCaekrLZmfbbZr3P1WqEsXHo6ntidQ3DmW+TT6G1aOp+ChYfKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.2.1", + "@jest/globals": "^29.2.1", + "babel-jest": "^29.2.1", + "jest-environment-jsdom": "^29.2.1", + "jest-snapshot": "^29.2.1", + "jest-watch-select-projects": "^2.0.0", + "jest-watch-typeahead": "2.2.1", + "json5": "^2.2.3", + "lodash": "^4.17.19", + "react-test-renderer": "19.2.3", + "server-only": "^0.0.1", + "stacktrace-js": "^2.0.2" + }, + "bin": { + "jest": "bin/jest.js" }, "peerDependencies": { - "@expo/metro-runtime": "^57.0.15", + "@react-native/jest-preset": "^0.86.3", "expo": "*", - "expo-constants": "^57.0.18", - "expo-font": "^57.0.4", - "expo-router": "*", - "expo-server": "^57.0.3", - "react": "*", - "react-dom": "*", - "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" + "react-native": "*", + "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "peerDependenciesMeta": { - "@expo/metro-runtime": { - "optional": true - }, - "expo-router": { - "optional": true - }, - "react-dom": { + "expo": { "optional": true }, "react-server-dom-webpack": { @@ -2961,229 +6304,231 @@ } } }, - "node_modules/expo/node_modules/@expo/dom-webview": { - "version": "57.0.1", + "node_modules/jest-get-type": { + "version": "29.6.3", "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expo/node_modules/@expo/log-box": { - "version": "57.0.4", + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "devOptional": true, "license": "MIT", "dependencies": { - "@expo/dom-webview": "^57.0.1", - "anser": "^1.4.9", - "stacktrace-parser": "^0.1.10" + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, - "peerDependencies": { - "@expo/dom-webview": "^57.0.1", - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/expo/node_modules/@expo/metro-config": { - "version": "57.0.12", + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.20.0", - "@babel/core": "^7.20.0", - "@babel/generator": "^7.20.5", - "@expo/config": "~57.0.9", - "@expo/env": "~2.4.3", - "@expo/json-file": "~11.0.1", - "@expo/metro": "~56.0.2", - "@expo/require-utils": "^57.0.5", - "@expo/spawn-async": "^1.8.0", - "@jridgewell/gen-mapping": "^0.3.13", - "@jridgewell/remapping": "^2.3.5", - "@jridgewell/sourcemap-codec": "^1.5.5", - "browserslist": "^4.25.0", - "chalk": "^4.1.0", - "debug": "^4.3.2", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "hermes-parser": "^0.36.0", - "jsc-safe-url": "^0.2.4", - "lightningcss": "^1.30.1", - "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "resolve-from": "^5.0.0" - }, - "peerDependencies": { - "expo": "*" + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, - "peerDependenciesMeta": { - "expo": { - "optional": true - } + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expo/node_modules/@expo/ws-tunnel": { - "version": "2.0.0", + "node_modules/jest-matcher-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz", + "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==", + "dev": true, "license": "MIT", - "peerDependencies": { - "ws": "^8.0.0" + "dependencies": { + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "jest-diff": "30.5.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/accepts": { - "version": "1.3.8", + "node_modules/jest-matcher-utils/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/babel-preset-expo": { - "version": "57.0.12", + "node_modules/jest-matcher-utils/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", - "dependencies": { - "@babel/generator": "^7.20.5", - "@babel/helper-module-imports": "^7.25.9", - "@babel/plugin-proposal-decorators": "^7.12.9", - "@babel/plugin-proposal-export-default-from": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-default-from": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-transform-async-generator-functions": "^7.25.4", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.25.0", - "@babel/plugin-transform-class-properties": "^7.25.4", - "@babel/plugin-transform-class-static-block": "^7.27.1", - "@babel/plugin-transform-classes": "^7.25.4", - "@babel/plugin-transform-destructuring": "^7.24.8", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.8", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.8", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-react-display-name": "^7.24.7", - "@babel/plugin-transform-react-jsx": "^7.28.6", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1", - "@babel/plugin-transform-runtime": "^7.24.7", - "@babel/plugin-transform-typescript": "^7.25.2", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/preset-typescript": "^7.23.0", - "@react-native/babel-plugin-codegen": "0.86.3", - "babel-plugin-react-compiler": "^1.0.0", - "babel-plugin-react-native-web": "~0.21.0", - "babel-plugin-syntax-hermes-parser": "^0.36.0", - "babel-plugin-transform-flow-enums": "^0.0.2", - "debug": "^4.3.4" - }, - "peerDependencies": { - "@babel/runtime": "^7.20.0", - "expo": "*", - "expo-widgets": "^57.0.19", - "react-refresh": ">=0.14.0 <1.0.0" + "engines": { + "node": ">=10" }, - "peerDependenciesMeta": { - "@babel/runtime": { - "optional": true - }, - "expo": { - "optional": true - }, - "expo-widgets": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expo/node_modules/ci-info": { - "version": "3.9.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" + }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/expo-asset": { - "version": "57.0.17", + "node_modules/jest-message-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", + "dev": true, "license": "MIT", "dependencies": { - "@expo/image-utils": "^0.11.5", - "expo-constants": "~57.0.18" + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.5.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.5.1", + "picomatch": "^4.0.3", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/expo-file-system": { - "version": "57.0.7", + "node_modules/jest-message-util/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", - "peerDependencies": { - "expo": "*", - "react-native": "*" + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/expo-keep-awake": { - "version": "57.0.2", + "node_modules/jest-message-util/node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*" + "dependencies": { + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/hermes-estree": { - "version": "0.36.1", + "node_modules/jest-message-util/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, "license": "MIT" }, - "node_modules/expo/node_modules/hermes-parser": { - "version": "0.36.1", + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", - "dependencies": { - "hermes-estree": "0.36.1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/expo/node_modules/mime-db": { - "version": "1.52.0", + "node_modules/jest-message-util/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=8" } }, - "node_modules/expo/node_modules/mime-types": { - "version": "2.1.35", + "node_modules/jest-message-util/node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" }, "engines": { - "node": ">= 0.6" - } - }, - "node_modules/expo/node_modules/negotiator": { - "version": "0.6.3", - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/expo/node_modules/picomatch": { + "node_modules/jest-message-util/node_modules/picomatch": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3192,353 +6537,496 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/expo/node_modules/ws": { - "version": "8.21.3", + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.3", - "license": "Apache-2.0" - }, - "node_modules/fast-base64-decode": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/fb-dotslash": { - "version": "0.5.8", - "license": "(MIT OR Apache-2.0)", - "bin": { - "dotslash": "bin/dotslash" + "dependencies": { + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" }, "engines": { - "node": ">=20" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/fetch-nodeshim": { - "version": "0.4.10", - "license": "MIT" - }, - "node_modules/fill-range": { - "version": "7.1.1", + "node_modules/jest-mock": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz", + "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==", + "dev": true, "license": "MIT", "dependencies": { - "to-regex-range": "^5.0.1" + "@jest/expect-utils": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-util": "30.5.1" }, "engines": { - "node": ">=8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/finalhandler": { - "version": "1.1.2", + "node_modules/jest-mock/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "@sinclair/typebox": "^0.34.0" }, "engines": { - "node": ">= 0.8" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", + "node_modules/jest-mock/node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "license": "MIT" - }, - "node_modules/flow-enums-runtime": { - "version": "0.0.6", + "node_modules/jest-mock/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, "license": "MIT" }, - "node_modules/fontfaceobserver": { - "version": "2.3.0", - "license": "BSD-2-Clause" + "node_modules/jest-mock/node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/fresh": { - "version": "0.5.2", + "node_modules/jest-mock/node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, "engines": { - "node": ">= 0.6" + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", + "node_modules/jest-mock/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, "license": "MIT", + "engines": { + "node": ">=12" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "license": "ISC", + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "devOptional": true, + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/getenv": { - "version": "2.0.0", + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/glob": { - "version": "13.0.6", - "license": "BlueOak-1.0.0", + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" }, "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/gql.tada": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/gql.tada/-/gql.tada-1.11.4.tgz", - "integrity": "sha512-UQnhJUhSM0MV8cpcgjci/7ET8LnmHx9o9FtZqU4sH+ILiBVG5rnfXJzNdzTN+Y7MuCz6Pp3XE/VPEVqmO969jw==", + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, "license": "MIT", "dependencies": { - "@0no-co/graphql.web": "^1.3.2", - "@0no-co/graphqlsp": "^1.17.3", - "@gql.tada/cli-utils": "1.9.4", - "@gql.tada/internal": "1.2.2" - }, - "bin": { - "gql-tada": "bin/cli.js", - "gql.tada": "bin/cli.js" + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, - "peerDependencies": { - "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "license": "ISC" - }, - "node_modules/graphql": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-17.0.2.tgz", - "integrity": "sha512-FRWbddMxfkjiB7z+aQDWIR+E34xo9I8c9mtK2RPv8PmMzKRvrdsreHL/Ui/TmwHJfhHChEtsFPyMHKI+xuarQQ==", + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { - "node": "^22.0.0 || ^24.0.0 || ^25.0.0 || >=26.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/has-flag": { - "version": "4.0.0", + "node_modules/jest-runner/node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/hasown": { - "version": "2.0.4", + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, "license": "MIT", "dependencies": { - "function-bind": "^1.1.2" + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/hermes-compiler": { - "version": "250829098.0.17", - "license": "MIT" - }, - "node_modules/hermes-estree": { - "version": "0.35.0", + "node_modules/jest-runtime/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, - "node_modules/hermes-parser": { - "version": "0.35.0", + "node_modules/jest-runtime/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "dev": true, "license": "MIT", "dependencies": { - "hermes-estree": "0.35.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/hosted-git-info": { - "version": "7.0.2", + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "10.4.3", - "license": "ISC" - }, - "node_modules/http-errors": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">= 0.8" + "node": "*" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": ">= 14" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "license": "MIT", - "engines": { - "node": ">= 4" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/invariant": { - "version": "2.2.4", + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "license": "MIT", + "node_modules/jest-runtime/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", "dependencies": { - "hasown": "^2.0.3" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "*" } }, - "node_modules/is-docker": { - "version": "2.2.1", - "license": "MIT", - "bin": { - "is-docker": "cli.js" + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "node_modules/jest-snapshot/node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-number": { - "version": "7.0.0", + "node_modules/jest-snapshot/node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, "engines": { - "node": ">=0.12.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-wsl": { - "version": "2.2.0", + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "license": "ISC" - }, - "node_modules/jest-get-type": { - "version": "29.6.3", + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3578,9 +7066,159 @@ "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watch-select-projects": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jest-watch-select-projects/-/jest-watch-select-projects-2.0.0.tgz", + "integrity": "sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.0", + "chalk": "^3.0.0", + "prompts": "^2.2.1" + } + }, + "node_modules/jest-watch-select-projects/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-2.2.1.tgz", + "integrity": "sha512-jYpYmUnTzysmVnwq49TAxlmtOAwp8QIqvZyoofQFn8fiWhEDZj33ZXzg3JA4nGnzWFm1hbWf3ADpteUokvXgFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^6.0.0", + "chalk": "^4.0.0", + "jest-regex-util": "^29.0.0", + "jest-watcher": "^29.0.0", + "slash": "^5.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0 || ^29.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-regex": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/char-regex": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.2.tgz", + "integrity": "sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -3644,6 +7282,101 @@ "version": "0.2.4", "license": "0BSD" }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/ws": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz", + "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/jsesc": { "version": "3.1.0", "license": "MIT", @@ -3654,6 +7387,13 @@ "node": ">=6" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "license": "MIT", @@ -3961,6 +7701,33 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "license": "MIT" @@ -4053,6 +7820,22 @@ "yallist": "^3.0.2" } }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/makeerror": { "version": "1.0.12", "license": "BSD-3-Clause", @@ -4064,6 +7847,16 @@ "version": "1.3.0", "license": "Apache-2.0" }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/memoize-one": { "version": "5.2.1", "license": "MIT" @@ -4370,6 +8163,16 @@ "node": ">=4" } }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/minimatch": { "version": "10.2.6", "license": "BlueOak-1.0.0", @@ -4424,6 +8227,13 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, "node_modules/negotiator": { "version": "1.1.0", "license": "MIT", @@ -4456,6 +8266,16 @@ "node": ">=18" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-package-arg": { "version": "11.0.3", "license": "ISC", @@ -4469,10 +8289,30 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "license": "MIT" }, + "node_modules/nwsapi": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.28.tgz", + "integrity": "sha512-IlVB7OS7qrOsVYlpnFIkETjMwT9jwvmocJmmM+GZU/PAB3uGi9Ezd7vcWhWBUnSc0ya4ppmQITOyP1ez9gg8cg==", + "dev": true, + "license": "MIT" + }, "node_modules/ob1": { "version": "0.84.5", "license": "MIT", @@ -4500,6 +8340,16 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/onetime": { "version": "2.0.1", "license": "MIT", @@ -4613,6 +8463,80 @@ "node": ">=4" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-png": { "version": "2.1.0", "license": "MIT", @@ -4623,6 +8547,19 @@ "node": ">=10" } }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "license": "MIT", @@ -4630,6 +8567,26 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "license": "MIT", @@ -4676,6 +8633,29 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/plist": { "version": "3.1.1", "license": "MIT", @@ -4788,6 +8768,53 @@ "node": ">= 6" } }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, "node_modules/range-parser": { "version": "1.2.1", "license": "MIT", @@ -4925,6 +8952,41 @@ "node": ">=0.10.0" } }, + "node_modules/react-test-renderer": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.2.3.tgz", + "integrity": "sha512-TMR1LnSFiWZMJkCgNf5ATSvAheTT2NvKIwiVwdBPHxjBI7n/JbWd4gaZ16DVd9foAXdvDz+sB5yxZTwMjPRxpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^19.2.3", + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.3" + } + }, + "node_modules/react-test-renderer/node_modules/react-is": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.0.tgz", + "integrity": "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/regenerate": { "version": "1.4.2", "license": "MIT" @@ -4979,6 +9041,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.12", "license": "MIT", @@ -4998,6 +9067,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "5.0.0", "license": "MIT", @@ -5005,10 +9087,20 @@ "node": ">=8" } }, - "node_modules/resolve-workspace-root": { - "version": "2.0.1", - "license": "MIT" - }, + "node_modules/resolve-workspace-root": { + "version": "2.0.1", + "license": "MIT" + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/restore-cursor": { "version": "2.0.0", "license": "MIT", @@ -5038,6 +9130,13 @@ ], "license": "MIT" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/sandbox-cli-detector": { "version": "0.2.0", "license": "MIT", @@ -5055,6 +9154,19 @@ "node": ">=11.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.27.0", "license": "MIT" @@ -5153,6 +9265,13 @@ "node": ">= 0.8" } }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "dev": true, + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "license": "ISC" @@ -5215,6 +9334,16 @@ "version": "1.0.5", "license": "MIT" }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/slugify": { "version": "1.6.9", "license": "MIT", @@ -5251,10 +9380,83 @@ "node": ">=0.10.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "devOptional": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-generator": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", + "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/stackframe": { "version": "1.3.4", "license": "MIT" }, + "node_modules/stacktrace-gps": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", + "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "0.5.6", + "stackframe": "^1.3.4" + } + }, + "node_modules/stacktrace-gps/node_modules/source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stacktrace-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz", + "integrity": "sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-stack-parser": "^2.0.6", + "stack-generator": "^2.0.5", + "stacktrace-gps": "^3.0.4" + } + }, "node_modules/stacktrace-parser": { "version": "0.1.11", "license": "MIT", @@ -5286,6 +9488,20 @@ "node": ">= 0.10.0" } }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/string-width": { "version": "4.2.3", "license": "MIT", @@ -5308,6 +9524,52 @@ "node": ">=8" } }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/structured-headers": { "version": "0.4.1", "license": "MIT" @@ -5343,6 +9605,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tagged-tag": { "version": "1.0.0", "license": "MIT", @@ -5387,6 +9656,114 @@ "version": "2.20.3", "license": "MIT" }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", + "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "devOptional": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/test-renderer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/test-renderer/-/test-renderer-1.3.0.tgz", + "integrity": "sha512-DXyHv7JrVmDc5dKpfVHFhJ0Evo/EFY3TqlNt8CR65ua3SCsI09K/mQDJmYUOnZz36GANYqjp0ApeRER/mOxktQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/react-reconciler": "~0.33.0", + "react-reconciler": "~0.34.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/test-renderer/node_modules/react-reconciler": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.34.0.tgz", + "integrity": "sha512-eVibvB1fc9j5Qf1KRkiM3GzRPBdjg2P6G6QV2f3P6Eb3OGMxRBhdg2rrUwjbV5JrQaJj8nOa8uajmmJA5tJWjQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.28.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "react": "^19.3.0" + } + }, + "node_modules/test-renderer/node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/throat": { "version": "5.0.0", "license": "MIT" @@ -5455,6 +9832,45 @@ "version": "0.1.1", "license": "MIT" }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.7.1", "license": "(MIT OR CC0-1.0)", @@ -5509,6 +9925,16 @@ "node": ">=4" } }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "license": "MIT", @@ -5544,6 +9970,17 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/use-latest-callback": { "version": "0.2.6", "license": "MIT", @@ -5572,6 +10009,21 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, "node_modules/valibot": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.5.0.tgz", @@ -5604,6 +10056,19 @@ "version": "1.0.1", "license": "MIT" }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/walker": { "version": "1.0.8", "license": "Apache-2.0", @@ -5622,10 +10087,58 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/whatwg-fetch": { "version": "3.6.20", "license": "MIT" }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/whatwg-url-minimum": { "version": "0.1.2", "license": "MIT" @@ -5658,6 +10171,27 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, "node_modules/ws": { "version": "7.5.13", "license": "MIT", @@ -5688,6 +10222,16 @@ "node": ">=10.0.0" } }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, "node_modules/xml2js": { "version": "0.6.0", "license": "MIT", @@ -5713,6 +10257,13 @@ "node": ">=8.0" } }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "license": "ISC", @@ -5760,6 +10311,19 @@ "node": ">=12" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "3.25.76", "license": "MIT", diff --git a/mobile/package.json b/mobile/package.json index a612d7b..62a6015 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -8,7 +8,8 @@ "start": "npm run sdk && expo start", "ios": "npm run sdk && expo run:ios", "android": "npm run sdk && expo run:android", - "typecheck": "npm run sdk && tsc --noEmit" + "typecheck": "npm run sdk && tsc --noEmit", + "test": "npm run sdk && jest" }, "dependencies": { "@expo-google-fonts/dm-mono": "^0.4.2", @@ -39,7 +40,12 @@ "react-native-screens": "~4.26.0" }, "devDependencies": { + "@testing-library/react-native": "^14.0.1", + "@types/jest": "^30.0.0", "@types/react": "~19.2.2", + "jest": "^29.7.0", + "jest-expo": "^57.0.5", + "react-test-renderer": "^19.2.3", "typescript": "~6.0.3" } } \ No newline at end of file diff --git a/mobile/src/components/ui.tsx b/mobile/src/components/ui.tsx index 1ceae7d..4da7814 100644 --- a/mobile/src/components/ui.tsx +++ b/mobile/src/components/ui.tsx @@ -150,12 +150,12 @@ export const ModeBadge = ({ mode }: { mode: Mode }) => {STATUS_LABELS[status]}; export const TrustBadge = ({ trust }: { trust: Trust }) => {TRUST_LABELS[trust]}; -export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md" }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm" }) { +export function Button({ children, onPress, kind = "primary", disabled, loading, icon, style, size = "md", testID }: { children: ReactNode; onPress?: () => void; kind?: "primary" | "secondary" | "danger" | "ghost"; disabled?: boolean; loading?: boolean; icon?: IconName; style?: StyleProp; size?: "md" | "sm"; testID?: string }) { const C = useTheme(); const s = useStyles(); const bg = kind === "primary" ? C.accent : kind === "danger" ? C.errorBg : kind === "secondary" ? C.card2 : "transparent"; const fg = kind === "primary" ? C.onAccent : kind === "danger" ? C.error : C.text; return ( - [s.btn, size === "sm" && { height: 36, paddingHorizontal: 14 }, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, style]}> + [s.btn, size === "sm" && { height: 36, paddingHorizontal: 14 }, { backgroundColor: bg, opacity: disabled ? 0.4 : pressed ? 0.8 : 1 }, style]}> {loading ? : <>{icon ? : null}{children}} ); diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index 75a1707..9869a7e 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -190,7 +190,7 @@ export function Send({ onDone }: { onDone: () => void }) { ) : null} {problems.length > 0 ? ( - The vault would refuse this. {problems.join(' ')} + {`The vault would refuse this. ${problems.join(' ')}`} ) : null} {preview.data ? ( diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx index 574539b..6b28c3f 100644 --- a/mobile/src/screens/TxDetail.tsx +++ b/mobile/src/screens/TxDetail.tsx @@ -113,7 +113,8 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { + ) : null} + + ); +} + +/** Placeholder blocks while a read is in flight, so the layout arrives before the numbers do. */ +export function Skeleton({ lines = 3 }: { lines?: number }) { + const C = useTheme(); + return ( + + {Array.from({ length: lines }, (_, i) => ( + + ))} + + ); +} + +/** + * Shown when the device believes it is offline. The data on screen is the cache, which is worth + * far more than a spinner — as long as its age is stated rather than implied. + */ +export function OfflineBanner({ asOf }: { asOf?: number }) { + const C = useTheme(); + const age = + asOf && asOf > 0 + ? ` — showing the vault as of ${new Date(asOf).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}` + : ''; + return ( + + + + Offline{age} + + + ); } export function Empty({ icon = "inbox", children }: { icon?: IconName; children: ReactNode }) { diff --git a/mobile/src/hooks/useOnline.ts b/mobile/src/hooks/useOnline.ts new file mode 100644 index 0000000..861ecf2 --- /dev/null +++ b/mobile/src/hooks/useOnline.ts @@ -0,0 +1,15 @@ +import { useNetworkState } from 'expo-network'; + +/** + * Whether the device believes it can reach anything. + * + * "Believes" is the honest word: a connected radio with a dead backhaul still reports reachable, + * so this gates banners and copy, never correctness — a read that fails shows its own error with + * a retry, whatever this says. + */ +export function useOnline(): boolean { + const state = useNetworkState(); + // Unknown is treated as online, because a false offline banner on launch teaches people to + // ignore the banner. + return state.isInternetReachable !== false && state.isConnected !== false; +} diff --git a/mobile/src/hooks/useTx.ts b/mobile/src/hooks/useTx.ts index e348bcd..7bfabe1 100644 --- a/mobile/src/hooks/useTx.ts +++ b/mobile/src/hooks/useTx.ts @@ -2,6 +2,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { useCallback, useState } from 'react'; import type { Transaction } from '@mysten/sui/transactions'; import { describeFailure } from '@skur/sdk'; +import { hapticError, hapticSuccess } from '../lib/haptics'; import { client } from '../lib/client'; import { NETWORK } from '../lib/config'; import { unlockSigner } from '../lib/keystore'; @@ -44,6 +45,7 @@ export function useTx(vaultId: string | null) { const message = describeFailure( result.FailedTransaction.status.error?.message ?? 'the vault refused it', ); + hapticError(); setState({ phase: 'error', message }); return null; } @@ -54,6 +56,7 @@ export function useTx(vaultId: string | null) { await queryClient.invalidateQueries({ queryKey: ['vault', NETWORK, vaultId] }); await queryClient.invalidateQueries({ queryKey: ['preview', NETWORK, vaultId] }); + hapticSuccess(); setState({ phase: 'done', digest }); return digest; } catch (e) { @@ -63,6 +66,7 @@ export function useTx(vaultId: string | null) { setState({ phase: 'cancelled' }); return null; } + hapticError(); setState({ phase: 'error', message: describeFailure(e) }); return null; } diff --git a/mobile/src/lib/haptics.ts b/mobile/src/lib/haptics.ts new file mode 100644 index 0000000..eda9ebc --- /dev/null +++ b/mobile/src/lib/haptics.ts @@ -0,0 +1,18 @@ +import * as Haptics from 'expo-haptics'; + +/** + * Touch feedback for the moments that matter: a transaction settling, a transaction refused. + * Wrapped so a platform without a haptic engine degrades to nothing instead of a rejection + * nobody handles. + */ +export function hapticSuccess() { + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success).catch(() => undefined); +} + +export function hapticError() { + Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error).catch(() => undefined); +} + +export function hapticTap() { + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light).catch(() => undefined); +} diff --git a/mobile/src/lib/links.ts b/mobile/src/lib/links.ts new file mode 100644 index 0000000..9675c47 --- /dev/null +++ b/mobile/src/lib/links.ts @@ -0,0 +1,43 @@ +/** + * Deep links the app answers to. + * + * skur://vault/0x… open that vault + * skur://proposal/42 open that proposal in the currently open vault + * skur://vault/0x…/proposal/42 open the vault, then the proposal + * + * Parsing is a pure function so it can be tested like one. The navigation side lives in App.tsx, + * because a link can arrive before the navigator is mounted or before a vault is open, and what + * to do then is a navigation decision, not a parsing one. + */ +export type ParsedLink = + | { kind: 'vault'; vaultId: string; proposalId?: string } + | { kind: 'proposal'; proposalId: string }; + +const VAULT_ID = /^0x[0-9a-fA-F]{10,64}$/; +const PROPOSAL_ID = /^\d{1,18}$/; + +export function parseLink(url: string): ParsedLink | null { + let path: string; + try { + // skur://vault/0x1 parses with 'vault' as the host, not the path — normalise both shapes, + // and expo dev-client URLs (exp+skur://expo-development-client/…) fall through to null. + const u = new URL(url); + if (!/^(skur|exp\+skur):$/.test(u.protocol)) return null; + path = `${u.host}${u.pathname}`; + } catch { + return null; + } + const parts = path.split('/').filter(Boolean); + + if (parts[0] === 'vault' && parts[1] && VAULT_ID.test(parts[1])) { + if (parts[2] === 'proposal' && parts[3] && PROPOSAL_ID.test(parts[3])) { + return { kind: 'vault', vaultId: parts[1], proposalId: parts[3] }; + } + if (parts.length === 2) return { kind: 'vault', vaultId: parts[1] }; + return null; + } + if (parts[0] === 'proposal' && parts[1] && PROPOSAL_ID.test(parts[1]) && parts.length === 2) { + return { kind: 'proposal', proposalId: parts[1] }; + } + return null; +} diff --git a/mobile/src/lib/notifications.ts b/mobile/src/lib/notifications.ts new file mode 100644 index 0000000..cd16bea --- /dev/null +++ b/mobile/src/lib/notifications.ts @@ -0,0 +1,75 @@ +import Constants from 'expo-constants'; +import * as Linking from 'expo-linking'; +import * as Notifications from 'expo-notifications'; +import { useEffect } from 'react'; +import { API_URL } from './config'; + +/** + * Push, end to end: the indexer watches the chain, decides who a thing concerns, and sends it to + * Expo's push service; the device registers its token as a subscription; a tap on the banner opens + * the exact proposal, through the same deep-link path a pasted URL takes. + * + * Remote push needs an EAS project id — Expo's service will not mint a token without one — so + * everything here degrades honestly: no project id, no indexer, or no permission each produce a + * stated reason in Settings rather than a silent nothing. + */ +Notifications.setNotificationHandler({ + handleNotification: async (n) => { + const severity = (n.request.content.data as { severity?: string } | null)?.severity; + return { + // An alert interrupts; information waits in the tray. + shouldShowBanner: true, + shouldShowList: true, + shouldPlaySound: severity === 'alert', + shouldSetBadge: false, + }; + }, +}); + +function projectId(): string | null { + const extra = Constants.expoConfig?.extra as { eas?: { projectId?: string } } | undefined; + return extra?.eas?.projectId ?? Constants.easConfig?.projectId ?? null; +} + +export type PushResult = { ok: true; token: string } | { ok: false; reason: string }; + +export async function enablePush(vaultId: string, address: string): Promise { + if (!API_URL) { + return { ok: false, reason: 'Push needs the indexer. Set EXPO_PUBLIC_SKUR_API.' }; + } + if (!projectId()) { + return { + ok: false, + reason: 'Push needs an EAS project id in app.json (extra.eas.projectId). Local and dev builds without one cannot receive remote notifications.', + }; + } + const perm = await Notifications.requestPermissionsAsync(); + if (!perm.granted) { + return { ok: false, reason: 'Notifications are off for Skur in system settings.' }; + } + const token = (await Notifications.getExpoPushTokenAsync({ projectId: projectId()! })).data; + const res = await fetch(`${API_URL}/subscriptions`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ vaultId, address, channel: 'push', endpoint: token, events: [] }), + }); + if (!res.ok) return { ok: false, reason: `The indexer refused the registration (${res.status}).` }; + return { ok: true, token }; +} + +/** + * Tapping a notification routes through the same deep-link path as a pasted URL, including the + * cold start — the response that launched the app is read back, because the listener was not + * alive to hear it. + */ +export function useNotificationTaps() { + useEffect(() => { + const open = (response: Notifications.NotificationResponse | null) => { + const url = (response?.notification.request.content.data as { url?: string } | null)?.url; + if (url && url.startsWith('skur://')) void Linking.openURL(url); + }; + void Notifications.getLastNotificationResponseAsync().then(open); + const sub = Notifications.addNotificationResponseReceivedListener(open); + return () => sub.remove(); + }, []); +} diff --git a/mobile/src/lib/persist.ts b/mobile/src/lib/persist.ts new file mode 100644 index 0000000..03b4daa --- /dev/null +++ b/mobile/src/lib/persist.ts @@ -0,0 +1,31 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister'; + +/** + * The query cache survives a restart, so opening the app offline shows the vault as it last was — + * with its age stated — instead of a spinner that will never resolve. + * + * The serializer is the part that matters: vault data is full of bigints, and a plain + * JSON.stringify throws on the first one. Persistence would then fail silently on exactly the + * data it exists for, which is the kind of bug that passes every demo and fails the first user + * with a balance. + */ +const TAG = '__skur_bigint__'; + +export function serialize(value: unknown): string { + return JSON.stringify(value, (_k, v) => (typeof v === 'bigint' ? { [TAG]: v.toString() } : v)); +} + +export function deserialize(text: string): unknown { + return JSON.parse(text, (_k, v) => + v && typeof v === 'object' && TAG in v ? BigInt((v as Record)[TAG]) : v, + ); +} + +export const persister = createAsyncStoragePersister({ + storage: AsyncStorage, + key: 'skur.querycache.v1', + serialize, + deserialize: deserialize as (s: string) => never, + throttleTime: 2_000, +}); diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index 2ab3088..d584b3b 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -11,6 +11,7 @@ import { Address, Card, Empty, + ErrorState, IconButton, KV, ModeBadge, @@ -18,6 +19,7 @@ import { Row, Screen, SectionLabel, + Skeleton, Tape, TopBar, } from '../components/ui'; @@ -36,16 +38,24 @@ export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwi if (q.isLoading) { return ( }> - Reading the vault… + ); } if (q.error || !q.data) { + const message = q.error instanceof Error ? q.error.message : ''; + const badId = /not found|deleted|invalid|parse/i.test(message); return ( } />}> - - Could not read that vault. Check the id and the network. - + q.refetch()} + /> ); } diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx index 9c1b965..5fc6fac 100644 --- a/mobile/src/screens/Onboard.tsx +++ b/mobile/src/screens/Onboard.tsx @@ -1,3 +1,4 @@ +import { usePreventScreenCapture } from 'expo-screen-capture'; import { useEffect, useState } from 'react'; import { Text, View } from 'react-native'; import { @@ -26,6 +27,10 @@ import { useStore } from '../state/store'; * collapses the two planes the contract works to keep apart. */ export function Onboard({ onDone }: { onDone: () => void }) { + // No screenshots and no screen recording while this screen can hold a private key. The OS also + // blanks it in the app switcher. Nothing stops a second phone pointed at the first — the copy + // on the import path says to treat the key accordingly. + usePreventScreenCapture(); const C = useTheme(); const { refreshSigner } = useStore(); const [mode, setMode] = useState<'create' | 'import'>('create'); diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index ba50555..f3427b9 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -6,6 +6,7 @@ import { useTheme } from '../state/theme'; import { F } from '../theme'; import { API_URL, NETWORK, PACKAGE_ID, explorer } from '../lib/config'; import { biometricSupport, forgetSigner, type BiometricSupport } from '../lib/keystore'; +import { enablePush, type PushResult } from '../lib/notifications'; import { useStore } from '../state/store'; export function Settings() { @@ -13,6 +14,8 @@ export function Settings() { const { scheme, setScheme } = useScheme(); const { address, vaultId, closeVault, refreshSigner } = useStore(); const [bio, setBio] = useState(null); + const [push, setPush] = useState(null); + const [pushBusy, setPushBusy] = useState(false); useEffect(() => { void biometricSupport().then(setBio); @@ -82,6 +85,34 @@ export function Settings() { ) : null} + {vaultId && address ? ( + + Notifications + + {push && !push.ok ? {push.reason} : null} + {push?.ok ? ( + + This device hears about proposals that need its role, vetoes, freezes and the + circuit breaker. Tapping one opens the exact proposal. + + ) : null} + + ) : null} + Network diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx index a7d84eb..1b032c0 100644 --- a/mobile/src/screens/Transactions.tsx +++ b/mobile/src/screens/Transactions.tsx @@ -3,10 +3,11 @@ import { KIND_LABELS, Kind, Status, fmtAmount, fmtRelative, type Proposal } from import { Card, Empty, - Notice, + ErrorState, Row, Screen, SectionLabel, + Skeleton, StatusBadge, TierBadge, TopBar, @@ -41,7 +42,8 @@ export function Transactions({ onOpen }: { onOpen: (id: bigint) => void }) { } > - {q.error ? Could not read the vault. : null} + {q.isLoading ? : null} + {q.error ? q.refetch()} /> : null} Awaiting action diff --git a/mobile/test/lib.test.tsx b/mobile/test/lib.test.tsx new file mode 100644 index 0000000..c1a5373 --- /dev/null +++ b/mobile/test/lib.test.tsx @@ -0,0 +1,126 @@ +import { Text } from 'react-native'; +import { parseLink } from '../src/lib/links'; +import { deserialize, serialize } from '../src/lib/persist'; +import { ErrorBoundary } from '../src/components/ErrorBoundary'; +import { OfflineBanner, TxProgress } from '../src/components/ui'; +import { renderScreen } from './harness'; +import { fireEvent, render } from '@testing-library/react-native'; + +describe('the links the app answers to', () => { + it('parses a vault link', () => { + expect(parseLink('skur://vault/0xabc123def456')).toEqual({ kind: 'vault', vaultId: '0xabc123def456' }); + }); + + it('parses a proposal in the open vault', () => { + expect(parseLink('skur://proposal/42')).toEqual({ kind: 'proposal', proposalId: '42' }); + }); + + it('parses a vault and a proposal together — the shape a push notification carries', () => { + expect(parseLink('skur://vault/0xabc123def456/proposal/7')).toEqual({ + kind: 'vault', + vaultId: '0xabc123def456', + proposalId: '7', + }); + }); + + it('ignores the dev client’s own URLs instead of treating them as navigation', () => { + expect(parseLink('exp+skur://expo-development-client/?url=http%3A%2F%2Flocalhost')).toBeNull(); + }); + + it('refuses what only looks like a link', () => { + expect(parseLink('skur://vault/not-an-id')).toBeNull(); + expect(parseLink('skur://proposal/42/extra')).toBeNull(); + expect(parseLink('skur://vault/0xabc/proposal/NaN')).toBeNull(); + expect(parseLink('https://vault/0xabc123def456')).toBeNull(); + expect(parseLink('')).toBeNull(); + }); +}); + +describe('the cache that survives a restart', () => { + it('round-trips bigints, which plain JSON would throw on', () => { + const data = { balance: 1_000_000_000_000n, nested: [{ amount: 42n }], name: 'Treasury', n: 7 }; + expect(deserialize(serialize(data))).toEqual(data); + }); + + it('leaves everything else exactly as it was', () => { + const data = { s: 'text', b: true, x: null, list: [1, 2, 3] }; + expect(deserialize(serialize(data))).toEqual(data); + }); +}); + +describe('the last line between a crash and a white screen', () => { + const Bomb = () => { + throw new Error('exploded in render'); + }; + + it('shows what happened and that nothing was signed', async () => { + // The boundary logs the crash; the test does not need to also print it. + const quiet = jest.spyOn(console, 'error').mockImplementation(() => undefined); + const r = await render( + + + , + ); + expect(r.queryByText(/Something broke in the app/)).not.toBeNull(); + expect(r.queryByText(/Nothing was signed/)).not.toBeNull(); + expect(r.queryByText(/exploded in render/)).not.toBeNull(); + quiet.mockRestore(); + }); + + it('restart remounts and recovers when the cause was transient', async () => { + const quiet = jest.spyOn(console, 'error').mockImplementation(() => undefined); + let shouldThrow = true; + const Flaky = () => { + if (shouldThrow) throw new Error('transient'); + return recovered; + }; + const r = await render( + + + , + ); + shouldThrow = false; + await fireEvent.press(r.getByText('Restart')); + expect(r.queryByText('recovered')).not.toBeNull(); + quiet.mockRestore(); + }); +}); + +describe('a transaction, step by step', () => { + it('is silent when nothing is happening', async () => { + // The harness providers render wrapper views, so the tree is not null — but nothing in it + // should say anything. + const r = await renderScreen(); + expect(r.queryByText(/./)).toBeNull(); + }); + + it('names the step it is on', async () => { + const r = await renderScreen(); + expect(r.queryByText('Sign and send')).not.toBeNull(); + expect(r.queryByText('Settle on the network')).not.toBeNull(); + }); + + it('a declined fingerprint is a decision, not an error', async () => { + const r = await renderScreen(); + expect(r.queryByText('Cancelled.')).not.toBeNull(); + }); + + it('an error is the contract’s sentence, not a code', async () => { + const r = await renderScreen( + , + ); + expect(r.queryByText(/activation delay/)).not.toBeNull(); + }); +}); + +describe('being offline', () => { + it('states the age of what is on screen', async () => { + const r = await renderScreen(); + expect(r.queryByText(/Offline — showing the vault as of 9:30/)).not.toBeNull(); + }); + + it('says only that it is offline when there is nothing cached to date', async () => { + const r = await renderScreen(); + expect(r.queryByText('Offline')).not.toBeNull(); + }); +}); diff --git a/mobile/test/setup.tsx b/mobile/test/setup.tsx index 66ea330..6f33a9e 100644 --- a/mobile/test/setup.tsx +++ b/mobile/test/setup.tsx @@ -45,3 +45,30 @@ console.warn = (...args: unknown[]) => { if (typeof args[0] === 'string' && args[0].includes('not wrapped in act')) return; warn(...args); }; + +jest.mock('expo-haptics', () => ({ + notificationAsync: jest.fn(async () => undefined), + impactAsync: jest.fn(async () => undefined), + NotificationFeedbackType: { Success: 'success', Error: 'error' }, + ImpactFeedbackStyle: { Light: 'light' }, +})); + +jest.mock('expo-screen-capture', () => ({ usePreventScreenCapture: jest.fn() })); + +jest.mock('expo-network', () => ({ + useNetworkState: jest.fn(() => ({ isConnected: true, isInternetReachable: true })), +})); + +jest.mock('expo-notifications', () => ({ + setNotificationHandler: jest.fn(), + requestPermissionsAsync: jest.fn(async () => ({ granted: true })), + getExpoPushTokenAsync: jest.fn(async () => ({ data: 'ExponentPushToken[test]' })), + getLastNotificationResponseAsync: jest.fn(async () => null), + addNotificationResponseReceivedListener: jest.fn(() => ({ remove: jest.fn() })), +})); + +jest.mock('expo-linking', () => ({ + useURL: jest.fn(() => null), + openURL: jest.fn(async () => true), + createURL: jest.fn((p: string) => `skur://${p}`), +})); diff --git a/server/migrations/003_push.sql b/server/migrations/003_push.sql new file mode 100644 index 0000000..5beb6e4 --- /dev/null +++ b/server/migrations/003_push.sql @@ -0,0 +1,10 @@ +-- Device push, delivered through Expo's push service. The endpoint is the device's Expo push +-- token; the delivery loop refuses anything that does not look like one. +ALTER TABLE subscriptions DROP CONSTRAINT IF EXISTS subscriptions_channel_check; +ALTER TABLE subscriptions + ADD CONSTRAINT subscriptions_channel_check + CHECK (channel IN ('webhook', 'email', 'log', 'push')); + +-- Every notification carries the deep link that opens the thing it is about, so tapping one lands +-- on the proposal rather than on the home screen with homework. +ALTER TABLE notifications ADD COLUMN IF NOT EXISTS link TEXT; diff --git a/server/src/api.ts b/server/src/api.ts index 8d39c9f..c71a910 100644 --- a/server/src/api.ts +++ b/server/src/api.ts @@ -187,9 +187,9 @@ export function makeApi() { send(res, { error: 'vaultId, address, channel and endpoint are required' }); return; } - if (!['webhook', 'email', 'log'].includes(channel)) { + if (!['webhook', 'email', 'log', 'push'].includes(channel)) { res.status(400); - send(res, { error: 'channel must be webhook, email or log' }); + send(res, { error: 'channel must be webhook, email, log or push' }); return; } const { rows } = await pool.query( diff --git a/server/src/notify.ts b/server/src/notify.ts index de2b070..175cacf 100644 --- a/server/src/notify.ts +++ b/server/src/notify.ts @@ -2,7 +2,9 @@ import { createHmac } from 'node:crypto'; import type { PoolClient } from 'pg'; import { fmtDuration, type DecodedEvent } from '@skur/sdk'; import { pool } from './db.ts'; -import { rulesFor } from './rules.ts'; +import { buildExpoPushMessage, rulesFor } from './rules.ts'; + +const EXPO_PUSH_URL = 'https://exp.host/--/api/v2/push/send'; /** * Queue notifications for an event. The unique constraint on @@ -34,8 +36,8 @@ export async function queueNotifications( for (const row of rows) { const res = await c.query( `INSERT INTO notifications ( - subscription_id, network, vault_id, tx_digest, event_index, rule, title, body, severity - ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) + subscription_id, network, vault_id, tx_digest, event_index, rule, title, body, severity, link + ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) ON CONFLICT DO NOTHING`, [ row.id, @@ -47,6 +49,7 @@ export async function queueNotifications( r.title, r.body, r.severity, + r.link ?? `skur://vault/${event.vault}`, ], ); queued += res.rowCount ?? 0; @@ -70,10 +73,11 @@ export async function deliverPending(limit = 25): Promise { title: string; body: string; severity: string; + link: string | null; attempts: number; }>( `SELECT n.id, s.channel, s.endpoint, s.secret, n.vault_id, n.rule, n.title, n.body, - n.severity, n.attempts + n.severity, n.link, n.attempts FROM notifications n JOIN subscriptions s ON s.id = n.subscription_id WHERE n.delivered_at IS NULL AND n.attempts < 6 AND s.active @@ -90,6 +94,7 @@ export async function deliverPending(limit = 25): Promise { title: n.title, body: n.body, severity: n.severity, + link: n.link, }); try { if (n.channel === 'webhook') { @@ -99,6 +104,18 @@ export async function deliverPending(limit = 25): Promise { } const res = await fetch(n.endpoint, { method: 'POST', headers, body: payload }); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); + } else if (n.channel === 'push') { + const res = await fetch(EXPO_PUSH_URL, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify([buildExpoPushMessage(n)]), + }); + if (!res.ok) throw new Error(`expo push: ${res.status} ${res.statusText}`); + const body = (await res.json()) as { data?: { status: string; message?: string }[] }; + const ticket = body.data?.[0]; + if (ticket && ticket.status !== 'ok') { + throw new Error(`expo push ticket: ${ticket.message ?? ticket.status}`); + } } else if (n.channel === 'log') { console.log(`[${n.severity}] ${n.title} — ${n.body}`); } else { diff --git a/server/src/rules.ts b/server/src/rules.ts index 86d7c1a..86c3c77 100644 --- a/server/src/rules.ts +++ b/server/src/rules.ts @@ -28,8 +28,15 @@ type Rule = { body: string; severity: 'info' | 'action' | 'alert'; roles: number; + /** The deep link that opens what this is about. Defaults to the vault itself. */ + link?: string; }; +/** skur://vault/0x…[/proposal/n] — the scheme the mobile app answers to. */ +export function linkTo(vault: string, proposal?: bigint): string { + return proposal === undefined ? `skur://vault/${vault}` : `skur://vault/${vault}/proposal/${proposal}`; +} + const fmtAmount = (v: bigint) => v.toLocaleString('en-US'); export function rulesFor({ event }: DecodedEvent): Rule[] { @@ -55,6 +62,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { .join(' '), severity: 'action', roles: who, + link: linkTo(event.vault, event.proposal), }); if (event.tier === Tier.CRITICAL) { out.push({ @@ -63,6 +71,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { body: `${fmtAmount(event.amount)} to ${short(event.recipient)}, at ${(event.exposureBps / 100).toFixed(1)}% of holdings. You can veto it until it executes.`, severity: 'alert', roles: Role.GUARDIAN, + link: linkTo(event.vault, event.proposal), }); } } else { @@ -72,6 +81,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { body: `Opened by ${short(event.proposer)}.`, severity: 'action', roles: who, + link: linkTo(event.vault, event.proposal), }); } @@ -83,6 +93,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { body: `It cannot take effect before ${new Date(event.executableAt).toUTCString()}, and any guardian can veto it until then.`, severity: 'alert', roles: Role.GUARDIAN | Role.OWNER, + link: linkTo(event.vault, event.proposal), }); } if (event.kind === Kind.RECOVERY) { @@ -92,6 +103,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { body: `Proposed by ${short(event.proposer)}. Any owner can cancel it before it executes.`, severity: 'alert', roles: Role.OWNER, + link: linkTo(event.vault, event.proposal), }); } return out; @@ -107,6 +119,7 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { body: `Proposal #${event.proposal} is fully approved. It executes once its waiting period has elapsed.`, severity: 'action', roles: Role.EXECUTOR, + link: linkTo(event.vault, event.proposal), }, ]; @@ -242,3 +255,38 @@ export function rulesFor({ event }: DecodedEvent): Rule[] { } } +/** What Expo's push service accepts, built where a test can look at it. */ +export type ExpoPushMessage = { + to: string; + title: string; + body: string; + sound: 'default'; + priority: 'high' | 'default'; + data: { url: string }; +}; + +const EXPO_TOKEN = /^(ExponentPushToken|ExpoPushToken)\[[^\]]+\]$/; + +export function buildExpoPushMessage(n: { + endpoint: string; + title: string; + body: string; + severity: string; + link: string | null; + vault_id: string; +}): ExpoPushMessage { + if (!EXPO_TOKEN.test(n.endpoint)) { + // Refused here rather than by Expo, so the row records a reason instead of burning its six + // attempts on a 400. + throw new Error(`not an Expo push token: ${n.endpoint.slice(0, 24)}…`); + } + return { + to: n.endpoint, + title: n.title, + body: n.body, + sound: 'default', + // An alert is worth waking a phone for; information is not. + priority: n.severity === 'alert' ? 'high' : 'default', + data: { url: n.link ?? `skur://vault/${n.vault_id}` }, + }; +} diff --git a/server/test/notify.test.ts b/server/test/notify.test.ts index d72654c..b8d1da5 100644 --- a/server/test/notify.test.ts +++ b/server/test/notify.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; import { Kind, Mode, Role, Status, Tier, Trust, type DecodedEvent } from '@skur/sdk'; -import { rulesFor } from '../src/rules.ts'; +import { buildExpoPushMessage, linkTo, rulesFor } from '../src/rules.ts'; /** * The rules decide who gets interrupted. Getting this wrong in either direction is a real failure: @@ -224,3 +224,53 @@ describe('the things everyone hears about', () => { ).toEqual([]); }); }); + + +describe('push delivery to a device', () => { + const queued = { + endpoint: 'ExponentPushToken[abc123]', + title: 'A critical payment is open and can be vetoed', + body: 'Body.', + severity: 'alert', + link: 'skur://vault/0xV/proposal/7', + vault_id: '0xV', + }; + + it('builds what Expo accepts, with the deep link in the data', () => { + const m = buildExpoPushMessage(queued); + expect(m.to).toBe('ExponentPushToken[abc123]'); + expect(m.data.url).toBe('skur://vault/0xV/proposal/7'); + expect(m.sound).toBe('default'); + }); + + it('wakes a phone for an alert and not for information', () => { + expect(buildExpoPushMessage(queued).priority).toBe('high'); + expect(buildExpoPushMessage({ ...queued, severity: 'info' }).priority).toBe('default'); + }); + + it('refuses an endpoint that is not an Expo token, before Expo has to', () => { + expect(() => buildExpoPushMessage({ ...queued, endpoint: 'https://example.com/hook' })).toThrow( + /not an Expo push token/, + ); + }); + + it('falls back to the vault link when a rule carried none', () => { + expect(buildExpoPushMessage({ ...queued, link: null }).data.url).toBe('skur://vault/0xV'); + }); +}); + +describe('the links the rules carry', () => { + it('a payment notification opens that payment', () => { + const rules = rulesFor( + wrap({ ...openedBase, tier: Tier.CRITICAL, reqGuardians: 1 }), + ); + for (const r of rules) { + expect(r.link).toBe('skur://vault/0xV/proposal/7'); + } + }); + + it('linkTo composes the scheme the app parses', () => { + expect(linkTo('0xabc')).toBe('skur://vault/0xabc'); + expect(linkTo('0xabc', 42n)).toBe('skur://vault/0xabc/proposal/42'); + }); +}); From 62428cd5cf3237ff316011bc197344cefff64efe Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Tue, 6 Oct 2026 16:40:16 +0100 Subject: [PATCH 36/44] =?UTF-8?q?fix(mobile):=20survive=20a=20real=20Andro?= =?UTF-8?q?id=20device=20=E2=80=94=20Hermes=20gaps,=20keystore=20design,?= =?UTF-8?q?=20onboarding=20persistence?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Everything here was found by driving the app on an Android emulator against a live localnet, not by tests. Each fix carries the test that would have caught it. Hermes polyfills (ran fine in Jest/Node, died on device): - structuredClone: the Sui SDK clones commands while building every transaction, so tx.build() threw 'undefined is not a function' after the user had already passed the biometric prompt. - AbortSignal.timeout / .any / .abort and AbortSignal.prototype.throwIfAborted: waitForTransaction uses all of them, so a payment executed on chain and then the app crashed while waiting to report it. - Promise.withResolvers: used by the gRPC transport. Keystore redesign — the address now lives in its own non-authenticated entry: - On Android, any read of an authenticated keystore entry raises the system biometric prompt no matter what the read passes, so signerAddress() cost a fingerprint at every launch and decoded the secret key just to show something public. - unlockSigner no longer pre-authenticates with LocalAuthentication before the gated read prompts again: one fingerprint per action instead of two, and the one that remains is the one that actually releases the key. Onboarding never persisted: - Onboard awaited refreshSigner() right after creating the key, which swapped the screen out before its Continue button — the only caller of finishOnboarding — could be pressed. Every cold start began at the welcome tour. The confirmation screen now stays until Continue, and a device that already holds a key skips the tour regardless. Stored state is validated on restore: - The previous build wrote an EVM address under the same storage key; restoring it pointed every screen at a vault that cannot exist on Sui. The open-vault id must now be a normalised Sui object id (0x + 64 hex) on load and in the manual-entry form. - Only settled queries are persisted: a query dehydrated while pending is rehydrated as a promise nothing resolves, and react-query rejects it over the UI on restore. --- mobile/App.tsx | 10 ++- mobile/src/hooks/useTx.ts | 1 + mobile/src/lib/keystore.ts | 57 ++++++++------- mobile/src/lib/polyfills.ts | 117 +++++++++++++++++++++++++++++++ mobile/src/screens/Onboard.tsx | 16 ++++- mobile/src/screens/OpenVault.tsx | 6 +- mobile/src/state/store.tsx | 15 +++- mobile/test/lib.test.tsx | 39 ++++++++++- 8 files changed, 229 insertions(+), 32 deletions(-) diff --git a/mobile/App.tsx b/mobile/App.tsx index d33b21e..1a82763 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -63,7 +63,11 @@ const persistOptions = { persister, maxAge: 24 * 3_600_000, dehydrateOptions: { - shouldDehydrateQuery: (q: { queryKey: readonly unknown[] }) => q.queryKey[0] === 'vault', + // Only settled vault reads. A query dehydrated while still pending is rehydrated as a + // promise that nothing will ever resolve — react-query rejects it on restore and logs a + // warning over the UI. + shouldDehydrateQuery: (q: { queryKey: readonly unknown[]; state: { status: string } }) => + q.queryKey[0] === 'vault' && q.state.status === 'success', }, }; @@ -240,7 +244,9 @@ function Root() { setNavReady(true)}> - {!onboarded && !seenWelcome ? ( + {!onboarded && !address && !seenWelcome ? ( + // A device that already holds a key never re-sees the tour, even if the onboarded flag + // was lost — the key is the stronger evidence. setSeenWelcome(true)} /> ) : !address ? ( diff --git a/mobile/src/hooks/useTx.ts b/mobile/src/hooks/useTx.ts index 7bfabe1..2853050 100644 --- a/mobile/src/hooks/useTx.ts +++ b/mobile/src/hooks/useTx.ts @@ -67,6 +67,7 @@ export function useTx(vaultId: string | null) { return null; } hapticError(); + if (__DEV__) console.error('tx failed', e, e instanceof Error ? e.stack : ''); setState({ phase: 'error', message: describeFailure(e) }); return null; } diff --git a/mobile/src/lib/keystore.ts b/mobile/src/lib/keystore.ts index 181e229..c19afe2 100644 --- a/mobile/src/lib/keystore.ts +++ b/mobile/src/lib/keystore.ts @@ -21,6 +21,14 @@ import { decodeSuiPrivateKey } from '@mysten/sui/cryptography'; * for. */ const KEY = 'skur.signer.v1'; +/** + * The address, in its own entry without `requireAuthentication`. An address is public — screens + * show it constantly — and on Android any read of an authenticated keystore entry raises the + * system biometric prompt no matter what options the *read* passes. Keeping the address beside + * the secret meant a fingerprint prompt just to launch the app, and pulled the secret into JS + * memory to derive something that was never secret. + */ +const ADDR = 'skur.signer.addr.v1'; const OPTIONS: SecureStore.SecureStoreOptions = { requireAuthentication: true, @@ -28,6 +36,10 @@ const OPTIONS: SecureStore.SecureStoreOptions = { authenticationPrompt: 'Unlock your Skur signing key', }; +const ADDR_OPTIONS: SecureStore.SecureStoreOptions = { + keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, +}; + export type BiometricSupport = { available: boolean; enrolled: boolean; @@ -50,20 +62,19 @@ export async function biometricSupport(): Promise { } export async function hasSigner(): Promise { - // Checked without `requireAuthentication`, so merely asking whether a key exists does not - // prompt for a face. - const stored = await SecureStore.getItemAsync(KEY, { - keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, - }).catch(() => null); - return Boolean(stored); + // The address entry is the existence marker: it is not auth-gated, so asking whether a key + // exists never prompts for a face. + return Boolean(await signerAddress()); } /** Generate a key and store it. Refuses to overwrite one that already exists. */ export async function createSigner(): Promise { if (await hasSigner()) throw new Error('a signing key already exists on this device'); const keypair = Ed25519Keypair.generate(); + const address = keypair.toSuiAddress(); await SecureStore.setItemAsync(KEY, keypair.getSecretKey(), OPTIONS); - return keypair.toSuiAddress(); + await SecureStore.setItemAsync(ADDR, address, ADDR_OPTIONS); + return address; } /** Import an existing key, so a signer already on a vault can use their phone. */ @@ -72,8 +83,10 @@ export async function importSigner(secret: string): Promise { // Validate before storing: a key that cannot be decoded is worse in the keychain than rejected. const { secretKey } = decodeSuiPrivateKey(trimmed); const keypair = Ed25519Keypair.fromSecretKey(secretKey); + const address = keypair.toSuiAddress(); await SecureStore.setItemAsync(KEY, trimmed, OPTIONS); - return keypair.toSuiAddress(); + await SecureStore.setItemAsync(ADDR, address, ADDR_OPTIONS); + return address; } /** @@ -81,13 +94,16 @@ export async function importSigner(secret: string): Promise { * action — nothing here caches it, because a cached signer is a signer that acts without a face. */ export async function unlockSigner(reason = 'Approve with your Skur key'): Promise { - const auth = await LocalAuthentication.authenticateAsync({ - promptMessage: reason, - cancelLabel: 'Cancel', - disableDeviceFallback: false, - }); - if (!auth.success) throw new Error('cancelled'); - const stored = await SecureStore.getItemAsync(KEY, OPTIONS); + // One prompt, raised by the OS for the key release itself. A separate LocalAuthentication + // check before the read meant two fingerprints per action — and the second one was the only + // one that actually protected anything. + let stored: string | null; + try { + stored = await SecureStore.getItemAsync(KEY, { ...OPTIONS, authenticationPrompt: reason }); + } catch { + // The OS prompt was dismissed or failed. A decision, not an error. + throw new Error('cancelled'); + } if (!stored) throw new Error('no signing key on this device'); const { secretKey } = decodeSuiPrivateKey(stored); return Ed25519Keypair.fromSecretKey(secretKey); @@ -95,15 +111,7 @@ export async function unlockSigner(reason = 'Approve with your Skur key'): Promi /** The address, read without unlocking — it is public, and screens need it constantly. */ export async function signerAddress(): Promise { - const stored = await SecureStore.getItemAsync(KEY, { - keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, - }).catch(() => null); - if (!stored) return null; - try { - return Ed25519Keypair.fromSecretKey(decodeSuiPrivateKey(stored).secretKey).toSuiAddress(); - } catch { - return null; - } + return await SecureStore.getItemAsync(ADDR, ADDR_OPTIONS).catch(() => null); } /** @@ -114,4 +122,5 @@ export async function forgetSigner(): Promise { await SecureStore.deleteItemAsync(KEY, { keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, }).catch(() => undefined); + await SecureStore.deleteItemAsync(ADDR, ADDR_OPTIONS).catch(() => undefined); } diff --git a/mobile/src/lib/polyfills.ts b/mobile/src/lib/polyfills.ts index 008d44f..b808839 100644 --- a/mobile/src/lib/polyfills.ts +++ b/mobile/src/lib/polyfills.ts @@ -129,3 +129,120 @@ export function assertCryptoReady() { throw new Error('Intl.PluralRules is not producing English ordinals'); } } + +/** + * Hermes has neither `structuredClone` (used by the Sui SDK while building a transaction — the + * resolver splices cloned commands) nor `Promise.withResolvers` (used by its gRPC transport). + * Without the first, every `tx.build()` dies with "undefined is not a function" *after* the user + * has already passed the biometric prompt, which reads like a signing failure and is not. + * + * The clone below covers what the SDK actually clones — plain objects, arrays, strings, numbers, + * bytes — not the full HTML algorithm. Uint8Array is the one typed case that matters: transaction + * arguments carry BCS bytes, and JSON round-tripping would quietly turn them into objects. + */ +if (typeof (globalThis as { structuredClone?: unknown }).structuredClone !== 'function') { + const clone = (value: unknown, seen: WeakMap): unknown => { + if (value === null || typeof value !== 'object') return value; + const hit = seen.get(value); + if (hit) return hit; + if (value instanceof Uint8Array) return new Uint8Array(value); + if (value instanceof ArrayBuffer) return value.slice(0); + if (value instanceof Date) return new Date(value.getTime()); + if (value instanceof Map) { + const out = new Map(); + seen.set(value, out); + for (const [k, v] of value) out.set(clone(k, seen), clone(v, seen)); + return out; + } + if (value instanceof Set) { + const out = new Set(); + seen.set(value, out); + for (const v of value) out.add(clone(v, seen)); + return out; + } + if (Array.isArray(value)) { + const out: unknown[] = []; + seen.set(value, out); + for (const v of value) out.push(clone(v, seen)); + return out; + } + const out: Record = {}; + seen.set(value, out); + for (const [k, v] of Object.entries(value)) out[k] = clone(v, seen); + return out; + }; + (globalThis as { structuredClone?: unknown }).structuredClone = (value: unknown) => + clone(value, new WeakMap()); +} + +if (typeof (Promise as { withResolvers?: unknown }).withResolvers !== 'function') { + (Promise as { withResolvers?: unknown }).withResolvers = function withResolvers() { + let resolve!: (value: T | PromiseLike) => void; + let reject!: (reason?: unknown) => void; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; + }; +} + +/** + * Hermes (via React Native) ships `AbortController` but not the static helpers on `AbortSignal`. + * The Sui client's `waitForTransaction` builds its deadline with `AbortSignal.timeout` and merges + * it with the caller's signal via `AbortSignal.any` — so without these, a payment executes on + * chain and then the app throws while *waiting to report it*, which is the worst possible place + * to fail. + */ +type AbortSignalStatics = { + timeout?: (ms: number) => AbortSignal; + any?: (signals: Iterable) => AbortSignal; + abort?: (reason?: unknown) => AbortSignal; +}; +const signalStatics = AbortSignal as unknown as AbortSignalStatics; + +if (typeof signalStatics.timeout !== 'function') { + signalStatics.timeout = (ms: number) => { + const controller = new AbortController(); + setTimeout(() => { + controller.abort(new Error(`signal timed out after ${ms}ms`)); + }, ms); + return controller.signal; + }; +} + +if (typeof signalStatics.any !== 'function') { + signalStatics.any = (signals: Iterable) => { + const controller = new AbortController(); + for (const signal of signals) { + if (signal.aborted) { + controller.abort(signal.reason); + break; + } + signal.addEventListener('abort', () => controller.abort(signal.reason), { once: true }); + } + return controller.signal; + }; +} + +if (typeof signalStatics.abort !== 'function') { + signalStatics.abort = (reason?: unknown) => { + const controller = new AbortController(); + controller.abort(reason); + return controller.signal; + }; +} + +/** + * React Native's own `AbortSignal` predates `throwIfAborted`. The Sui client calls it on every + * poll of `waitForTransaction`. + */ +type AbortSignalWithThrow = AbortSignal & { throwIfAborted?: () => void }; +const signalProto = AbortSignal.prototype as AbortSignalWithThrow; +if (typeof signalProto.throwIfAborted !== 'function') { + signalProto.throwIfAborted = function throwIfAborted(this: AbortSignal) { + if (this.aborted) { + throw (this as { reason?: unknown }).reason ?? new Error('the operation was aborted'); + } + }; +} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx index 5fc6fac..a0bab95 100644 --- a/mobile/src/screens/Onboard.tsx +++ b/mobile/src/screens/Onboard.tsx @@ -49,8 +49,10 @@ export function Onboard({ onDone }: { onDone: () => void }) { setBusy(true); try { const addr = mode === 'create' ? await createSigner() : await importSigner(secret); + // Only the local state. Refreshing the store's signer here would swap this screen out from + // under the user before the confirmation — and its Continue button is what records that + // onboarding finished. Without that record, every cold start began at the welcome tour. setAddress(addr); - await refreshSigner(); } catch (e) { setError(e instanceof Error ? e.message : String(e)); } finally { @@ -62,7 +64,17 @@ export function Onboard({ onDone }: { onDone: () => void }) { return ( } - footer={} + footer={ + + } > diff --git a/mobile/src/screens/OpenVault.tsx b/mobile/src/screens/OpenVault.tsx index eb44a69..60471ce 100644 --- a/mobile/src/screens/OpenVault.tsx +++ b/mobile/src/screens/OpenVault.tsx @@ -28,7 +28,9 @@ export function OpenVault() { const { address, openVault } = useStore(); const [manual, setManual] = useState(''); const mine = useMyVaults(address); - const valid = /^0x[0-9a-fA-F]{10,66}$/.test(manual); + // Exactly a normalised Sui object id. The looser shapes this used to accept — an EVM address + // is 40 hex chars — all name vaults that cannot exist on a Sui network. + const valid = /^0x[0-9a-fA-F]{64}$/.test(manual.trim()); return ( - diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx index 10db624..8126739 100644 --- a/mobile/src/state/store.tsx +++ b/mobile/src/state/store.tsx @@ -36,6 +36,14 @@ type Store = { const Ctx = createContext(null); const K = { vault: 'skur.vault', onboarded: 'skur.onboarded', book: 'skur.book' } as const; +/** + * A normalised Sui object id: 0x and exactly 32 bytes of hex. Storage is validated on load + * because this app's storage keys are older than its chain — an earlier build wrote an EVM + * address (40 hex chars) under the same key, and restoring it silently points every screen at a + * vault that cannot exist. + */ +const SUI_ID = /^0x[0-9a-fA-F]{64}$/; + export function StoreProvider({ children }: { children: ReactNode }) { const [ready, setReady] = useState(false); const [address, setAddress] = useState(null); @@ -54,7 +62,12 @@ export function StoreProvider({ children }: { children: ReactNode }) { AsyncStorage.getItem(K.onboarded), AsyncStorage.getItem(K.book), ]); - setVaultId(v); + if (v && SUI_ID.test(v)) { + setVaultId(v); + } else if (v) { + // Residue from before, or hand-edited: drop it rather than show a vault that can't load. + void AsyncStorage.removeItem(K.vault); + } setOnboarded(o === '1'); try { setBook(b ? (JSON.parse(b) as Labelled[]) : []); diff --git a/mobile/test/lib.test.tsx b/mobile/test/lib.test.tsx index c1a5373..1e00340 100644 --- a/mobile/test/lib.test.tsx +++ b/mobile/test/lib.test.tsx @@ -1,10 +1,12 @@ import { Text } from 'react-native'; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { parseLink } from '../src/lib/links'; +import { StoreProvider, useStore } from '../src/state/store'; import { deserialize, serialize } from '../src/lib/persist'; import { ErrorBoundary } from '../src/components/ErrorBoundary'; import { OfflineBanner, TxProgress } from '../src/components/ui'; import { renderScreen } from './harness'; -import { fireEvent, render } from '@testing-library/react-native'; +import { act, fireEvent, render } from '@testing-library/react-native'; describe('the links the app answers to', () => { it('parses a vault link', () => { @@ -124,3 +126,38 @@ describe('being offline', () => { expect(r.queryByText('Offline')).not.toBeNull(); }); }); + +describe('restoring the open vault', () => { + const EVM = '0xD3f026024e015e1eC841a88D983883d4a017ED52'; // 40 hex — an EVM address + const SUI = '0x' + 'ab'.repeat(32); // 64 hex — a normalised Sui object id + + async function restoredVaultId(stored: string | null): Promise { + if (stored === null) await AsyncStorage.removeItem('skur.vault'); + else await AsyncStorage.setItem('skur.vault', stored); + let seen: string | null = null; + function Probe() { + const s = useStore(); + if (s.ready) seen = s.vaultId; + return null; + } + await renderScreen( + + + , + ); + // The store loads asynchronously; flush until ready. + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 0)); + }); + return seen; + } + + it('restores a Sui object id', async () => { + expect(await restoredVaultId(SUI)).toBe(SUI); + }); + + it('discards an EVM address left by an earlier build', async () => { + expect(await restoredVaultId(EVM)).toBeNull(); + expect(await AsyncStorage.getItem('skur.vault')).toBeNull(); + }); +}); From abbc2b37f4a9c3fde25a681c1917052722404431 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:06:33 +0100 Subject: [PATCH 37/44] feat(mobile): the full 21-screen product design, in brand, light and dark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every screen from the design reference, rebuilt on the real chain instead of sample data, in Skur's own palette (ink ground, #ffd000 accent) with a dark-mode switch that flips the whole app and a Light/Dark/System control that can hand the choice back to the OS. Onboarding (1–7), one flow with back navigation: - Launch, feature tour (3 pages, pager dots), create-or-join fork - Create Account: name + email, local-only, with the honest line in place of a password — the signing key in the secure element is the credential - Create Organisation: name, local description, the network pinned by the build - Add Members: roster with role chips mapped to contract capabilities, guardian warning - Connect Wallet: device key first (create/import, one biometric), the six external wallets listed and marked 'Soon' rather than pretending; creating an organisation builds the vault on chain and opens it — thresholds clamped to the roster, because a 2-of-1 vault is a locked box and the contract rightly refuses one Main app on five tabs (8–21): Home dashboard (treasury value, pending/member stats, recent activity — and no fiat figure the app cannot know), Treasury overview (portfolio bar, send/request, per-asset bars, the enforcement card), Transactions with All/Sent/ Received, New Transaction with a send/request toggle, proposal details with a Details card, live on-chain simulation sheet, review-before-signing checks and an approval-flow timeline, Team with governance-routed invitations, Roles & Permissions, Spending Policies with an owner-gated editor that proposes rather than decrees, Security Center with a controls meter over the existing posture/brake/max-loss, Activity Logs derived from what actually happened, Settings with profile and appearance, Help & Support. Root gate fixed: creating the key mid-flow no longer unmounts onboarding one step before it creates the organisation — the flow owns the screen until it says it is done. 59 tests (14 new), typecheck clean, both platforms bundle; the create-org path verified live on the Android emulator: key → faucet → vault on chain → funded dashboard. --- mobile/App.tsx | 267 +++++++++++---- mobile/src/components/kit.tsx | 265 +++++++++++++++ mobile/src/lib/roles.ts | 64 ++++ mobile/src/screens/ActivityLog.tsx | 143 ++++++++ mobile/src/screens/Dashboard.tsx | 191 +++++++++++ mobile/src/screens/Help.tsx | 92 ++++++ mobile/src/screens/Home.tsx | 100 +++--- mobile/src/screens/More.tsx | 64 ++++ mobile/src/screens/Onboard.tsx | 173 ---------- mobile/src/screens/Policies.tsx | 176 ++++++++++ mobile/src/screens/Roles.tsx | 37 +++ mobile/src/screens/Security.tsx | 25 +- mobile/src/screens/Send.tsx | 51 ++- mobile/src/screens/Settings.tsx | 190 +++++++---- mobile/src/screens/Team.tsx | 183 +++++++++++ mobile/src/screens/Transactions.tsx | 176 ++++++---- mobile/src/screens/TxDetail.tsx | 182 ++++++++++- mobile/src/screens/Welcome.tsx | 51 --- mobile/src/screens/onboarding/AddMembers.tsx | 161 +++++++++ .../src/screens/onboarding/ConnectWallet.tsx | 305 ++++++++++++++++++ .../src/screens/onboarding/CreateAccount.tsx | 97 ++++++ mobile/src/screens/onboarding/CreateOrg.tsx | 69 ++++ mobile/src/screens/onboarding/Launch.tsx | 45 +++ mobile/src/screens/onboarding/Start.tsx | 47 +++ mobile/src/screens/onboarding/Tour.tsx | 70 ++++ mobile/src/state/store.tsx | 35 +- mobile/test/design.test.tsx | 176 ++++++++++ mobile/test/roles.test.tsx | 4 +- 28 files changed, 2983 insertions(+), 456 deletions(-) create mode 100644 mobile/src/components/kit.tsx create mode 100644 mobile/src/lib/roles.ts create mode 100644 mobile/src/screens/ActivityLog.tsx create mode 100644 mobile/src/screens/Dashboard.tsx create mode 100644 mobile/src/screens/Help.tsx create mode 100644 mobile/src/screens/More.tsx delete mode 100644 mobile/src/screens/Onboard.tsx create mode 100644 mobile/src/screens/Policies.tsx create mode 100644 mobile/src/screens/Roles.tsx create mode 100644 mobile/src/screens/Team.tsx delete mode 100644 mobile/src/screens/Welcome.tsx create mode 100644 mobile/src/screens/onboarding/AddMembers.tsx create mode 100644 mobile/src/screens/onboarding/ConnectWallet.tsx create mode 100644 mobile/src/screens/onboarding/CreateAccount.tsx create mode 100644 mobile/src/screens/onboarding/CreateOrg.tsx create mode 100644 mobile/src/screens/onboarding/Launch.tsx create mode 100644 mobile/src/screens/onboarding/Start.tsx create mode 100644 mobile/src/screens/onboarding/Tour.tsx create mode 100644 mobile/test/design.test.tsx diff --git a/mobile/App.tsx b/mobile/App.tsx index 1a82763..53278a6 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -32,16 +32,30 @@ import { persister } from './src/lib/persist'; import { StoreProvider, useStore } from './src/state/store'; import { ThemeProvider, useScheme, useTheme } from './src/state/theme'; import { F } from './src/theme'; + +import { Launch } from './src/screens/onboarding/Launch'; +import { Tour } from './src/screens/onboarding/Tour'; +import { Start } from './src/screens/onboarding/Start'; +import { CreateAccount } from './src/screens/onboarding/CreateAccount'; +import { CreateOrg, type OrgDraft } from './src/screens/onboarding/CreateOrg'; +import { AddMembers, type MemberDraft } from './src/screens/onboarding/AddMembers'; +import { ConnectWallet } from './src/screens/onboarding/ConnectWallet'; + +import { ActivityLog } from './src/screens/ActivityLog'; +import { Dashboard } from './src/screens/Dashboard'; +import { Help } from './src/screens/Help'; import { Home } from './src/screens/Home'; -import { Onboard } from './src/screens/Onboard'; +import { More } from './src/screens/More'; import { OpenVault } from './src/screens/OpenVault'; +import { Policies } from './src/screens/Policies'; import { Receive } from './src/screens/Receive'; +import { Roles } from './src/screens/Roles'; import { Security } from './src/screens/Security'; import { Send } from './src/screens/Send'; import { Settings } from './src/screens/Settings'; +import { Team } from './src/screens/Team'; import { Transactions } from './src/screens/Transactions'; import { TxDetail } from './src/screens/TxDetail'; -import { Welcome } from './src/screens/Welcome'; /** * Reads are cached to disk, so a cold start offline shows the vault as it last was — the offline @@ -72,57 +86,135 @@ const persistOptions = { }; /** Route params are serialisable by contract, so a proposal id travels as a string. */ -type ActivityParams = { Queue: undefined; Proposal: { id: string } }; +type ProposalsParams = { Queue: undefined; Proposal: { id: string }; New: undefined }; +type TeamParams = { Members: undefined; Roles: undefined }; +type MoreParams = { + Menu: undefined; + SecurityCenter: undefined; + Policies: undefined; + Logs: undefined; + ReceiveScreen: undefined; + SettingsScreen: undefined; + Help: undefined; +}; type TabParams = { + Home: undefined; Treasury: undefined; - Activity: NavigatorScreenParams; - Pay: undefined; - Receive: undefined; - Security: undefined; - Settings: undefined; + Proposals: NavigatorScreenParams; + Team: NavigatorScreenParams; + More: NavigatorScreenParams; }; const Tab = createBottomTabNavigator(); -const ActivityNav = createNativeStackNavigator(); +const ProposalsNav = createNativeStackNavigator(); +const TeamNav = createNativeStackNavigator(); +const MoreNav = createNativeStackNavigator(); const navRef = createNavigationContainerRef(); /** - * The queue and a proposal are a real stack, not a component swapped by local state. That is what - * makes Android's hardware back close the proposal instead of the app, gives iOS its swipe-back, - * and gives a deep link something to target. + * Stacks, not component swaps: Android's hardware back closes the inner screen instead of the + * app, iOS keeps its swipe-back, and a deep link has something to target. */ -function ActivityStack() { +function ProposalsStack() { return ( - - + + {({ navigation }) => ( navigation.navigate('Proposal', { id: id.toString() })} /> )} - - - {({ route, navigation }: NativeStackScreenProps) => ( + + + {({ route, navigation }: NativeStackScreenProps) => ( navigation.goBack()} /> )} - - + + + {({ navigation }) => navigation.navigate('Queue')} />} + + ); } -function TreasuryTab() { +function TeamStack() { + return ( + + + {({ navigation }) => navigation.navigate('Roles')} />} + + + {({ navigation }) => navigation.goBack()} />} + + + ); +} + +function MoreStack() { + return ( + + + {({ navigation }) => ( + + navigation.navigate( + screen === 'Security' + ? 'SecurityCenter' + : screen === 'Receive' + ? 'ReceiveScreen' + : screen === 'Settings' + ? 'SettingsScreen' + : screen, + ) + } + /> + )} + + + + {({ navigation }) => navigation.goBack()} />} + + + {({ navigation }) => navigation.goBack()} />} + + + + {({ navigation }) => ( + navigation.navigate('Help')} + onOpenSecurity={() => navigation.navigate('SecurityCenter')} + /> + )} + + + {({ navigation }) => navigation.goBack()} />} + + + ); +} + +function HomeTab() { const navigation = useNavigation>(); const { closeVault } = useStore(); return ( - navigation.navigate('Activity', { screen: 'Queue' })} + navigation.navigate('Proposals', { screen: 'Queue' })} + onOpenProposal={(id) => navigation.navigate('Proposals', { screen: 'Proposal', params: { id: id.toString() } })} + onOpenTreasury={() => navigation.navigate('Treasury')} onSwitch={closeVault} /> ); } -function PayTab() { +function TreasuryTab() { const navigation = useNavigation>(); - // After a payment opens, land on the queue — that is where it now lives. - return navigation.navigate('Activity', { screen: 'Queue' })} />; + const { closeVault } = useStore(); + return ( + navigation.navigate('Proposals', { screen: 'Queue' })} + onSend={() => navigation.navigate('Proposals', { screen: 'New' })} + onRequest={() => navigation.navigate('More', { screen: 'ReceiveScreen' })} + onSwitch={closeVault} + /> + ); } /** The banner sits above the tabs, with the age of what is on screen. */ @@ -149,27 +241,24 @@ function Tabs() { tabBarLabelStyle: { fontFamily: F.bodyMedium, fontSize: 11 }, tabBarIcon: ({ color }) => { const name = - route.name === 'Treasury' + route.name === 'Home' ? 'home' - : route.name === 'Activity' - ? 'list' - : route.name === 'Pay' - ? 'arrow-up-right' - : route.name === 'Receive' - ? 'download' - : route.name === 'Security' - ? 'shield' - : 'settings'; + : route.name === 'Treasury' + ? 'pie-chart' + : route.name === 'Proposals' + ? 'list' + : route.name === 'Team' + ? 'users' + : 'more-horizontal'; return ; }, })} > + - - - - - + + + ); @@ -180,8 +269,7 @@ function Tabs() { * * A link can arrive before the navigator mounts, before the store loads, or before any vault is * open — tapping a notification cold-starts the app into exactly that state. So links queue, and - * the queue drains when everything the link needs is ready. The old build lost early links for - * precisely this reason. + * the queue drains when everything the link needs is ready. */ function DeepLinks({ navReady }: { navReady: boolean }) { const url = Linking.useURL(); @@ -201,23 +289,93 @@ function DeepLinks({ navReady }: { navReady: boolean }) { useEffect(() => { const link = pending.current; if (!link || !navReady || !ready || !address || !vaultId) return; - const proposalId = link.kind === 'proposal' ? link.proposalId : link.proposalId; + const proposalId = link.proposalId; pending.current = null; if (proposalId && navRef.isReady()) { - navRef.navigate('Activity', { screen: 'Proposal', params: { id: proposalId } }); + navRef.navigate('Proposals', { screen: 'Proposal', params: { id: proposalId } }); } }); return null; } +type OnboardStep = 'launch' | 'tour' | 'start' | 'account' | 'org' | 'members' | 'wallet'; + +/** + * Screens 1–7 as one flow. "Create" walks the whole path and ends with the vault created on + * chain; "Join" skips the organisation and lands on the key, then the vault picker. + */ +function Onboarding({ onDone }: { onDone: () => void }) { + const { address } = useStore(); + // A device that already holds a key skips the marketing and goes straight to the fork — but a + // key created mid-flow must NOT reset the flow, so this is the initial step only. + const [step, setStep] = useState(address ? 'start' : 'launch'); + const [org, setOrg] = useState(null); + const [members, setMembers] = useState([]); + const [joining, setJoining] = useState(false); + + switch (step) { + case 'launch': + return setStep('tour')} />; + case 'tour': + return setStep('start')} />; + case 'start': + return ( + { + setJoining(false); + setStep('account'); + }} + onJoin={() => { + setJoining(true); + setStep('account'); + }} + /> + ); + case 'account': + return ( + setStep('start')} onDone={() => setStep(joining ? 'wallet' : 'org')} /> + ); + case 'org': + return ( + setStep('account')} + onDone={(draft) => { + setOrg(draft); + setStep('members'); + }} + /> + ); + case 'members': + return ( + setStep('org')} + onDone={(list) => { + setMembers(list); + setStep('wallet'); + }} + /> + ); + case 'wallet': + return ( + setStep(joining ? 'account' : 'members')} + onDone={onDone} + /> + ); + } +} + /** An introduction, a key to set up, a vault to pick, or the vault. */ function Root() { useNotificationTaps(); const C = useTheme(); const { dark } = useScheme(); const { ready, onboarded, address, vaultId, finishOnboarding } = useStore(); - const [seenWelcome, setSeenWelcome] = useState(false); const [navReady, setNavReady] = useState(false); if (!ready) { @@ -244,16 +402,15 @@ function Root() { setNavReady(true)}> - {!onboarded && !address && !seenWelcome ? ( - // A device that already holds a key never re-sees the tour, even if the onboarded flag - // was lost — the key is the stronger evidence. - setSeenWelcome(true)} /> - ) : !address ? ( - - ) : !vaultId ? ( - - ) : ( + {address && vaultId ? ( + ) : !onboarded || !address ? ( + // The flow owns the screen until it says it is done. Creating the key mid-flow flips + // `address`, and an address-based gate here would unmount the flow one step before it + // creates the organisation — which is exactly the bug this ordering exists to prevent. + + ) : ( + )} ); diff --git a/mobile/src/components/kit.tsx b/mobile/src/components/kit.tsx new file mode 100644 index 0000000..ef11b68 --- /dev/null +++ b/mobile/src/components/kit.tsx @@ -0,0 +1,265 @@ +import type { ReactNode } from 'react'; +import { Switch, Text, View } from 'react-native'; +import { Icon, type IconName } from './ui'; +import { useTheme } from '../state/theme'; +import { F, R } from '../theme'; + +/** + * The pieces the product screens are drawn with, beyond the base kit in ui.tsx: checklists, + * meters, bars, avatars, pager dots and timelines. Pure presentation — nothing here reads the + * chain or holds state. + */ + +/** A green-check feature or control line, used by the tour, the security center and sign review. */ +export function CheckItem({ + title, + detail, + ok = true, + icon, +}: { + title: string; + detail?: string; + ok?: boolean | 'warn'; + icon?: IconName; +}) { + const C = useTheme(); + const color = ok === true ? C.success : ok === 'warn' ? C.warning : C.error; + const name: IconName = icon ?? (ok === true ? 'check-circle' : ok === 'warn' ? 'alert-circle' : 'x-circle'); + return ( + + + + + + {title} + {detail ? ( + {detail} + ) : null} + + + ); +} + +/** A settings row with a switch on the right. */ +export function SwitchRow({ + title, + subtitle, + value, + onChange, + icon, +}: { + title: string; + subtitle?: string; + value: boolean; + onChange: (v: boolean) => void; + icon?: IconName; +}) { + const C = useTheme(); + return ( + + {icon ? : null} + + {title} + {subtitle ? {subtitle} : null} + + + + ); +} + +/** A labelled progress meter: posture, approvals collected, budget used. 0..1. */ +export function Meter({ value, label, trailing }: { value: number; label?: string; trailing?: string }) { + const C = useTheme(); + const clamped = Math.max(0, Math.min(1, value)); + return ( + + {label || trailing ? ( + + {label ? {label} : } + {trailing ? {trailing} : null} + + ) : null} + + + + + ); +} + +export type Slice = { label: string; value: number; color: string }; + +/** One stacked bar for the whole portfolio, with a legend — the honest cousin of a donut. */ +export function PortfolioBar({ slices }: { slices: Slice[] }) { + const C = useTheme(); + const total = slices.reduce((s, x) => s + x.value, 0); + if (total <= 0) return null; + return ( + + + {slices.map((s) => ( + + ))} + + + {slices.map((s) => ( + + + {s.label} + + {((s.value / total) * 100).toFixed(1)}% + + + ))} + + + ); +} + +/** Vertical bars, one per item, scaled to the largest. */ +export function BarChart({ items }: { items: { label: string; value: number }[] }) { + const C = useTheme(); + const max = Math.max(...items.map((i) => i.value), 1); + return ( + + {items.map((i) => ( + + + + {i.label} + + + ))} + + ); +} + +/** Initials in a circle, for people the chain only knows as addresses. */ +export function Avatar({ name, size = 36 }: { name: string; size?: number }) { + const C = useTheme(); + const initials = name + .split(/\s+/) + .filter(Boolean) + .slice(0, 2) + .map((w) => w[0]!.toUpperCase()) + .join(''); + return ( + + {initials || '•'} + + ); +} + +/** Pager dots for the tour. */ +export function Dots({ count, index }: { count: number; index: number }) { + const C = useTheme(); + return ( + + {Array.from({ length: count }).map((_, i) => ( + + ))} + + ); +} + +/** + * One step on an approval timeline. The rail is drawn by the items themselves so the line never + * outruns the content. + */ +export function TimelineStep({ + title, + subtitle, + state, + last = false, + trailing, +}: { + title: string; + subtitle?: ReactNode; + state: 'done' | 'active' | 'todo'; + last?: boolean; + trailing?: ReactNode; +}) { + const C = useTheme(); + const color = state === 'done' ? C.success : state === 'active' ? C.accent : C.text3; + return ( + + + + {state === 'done' ? : null} + + {!last ? : null} + + + + {title} + {trailing} + + {subtitle ? ( + {subtitle} + ) : null} + + + ); +} + +/** A big stat with a caption, for the dashboard's value and count cards. */ +export function Stat({ value, label, tone }: { value: string; label: string; tone?: 'accent' | 'plain' }) { + const C = useTheme(); + return ( + + + {value} + + {label} + + ); +} diff --git a/mobile/src/lib/roles.ts b/mobile/src/lib/roles.ts new file mode 100644 index 0000000..b0d374f --- /dev/null +++ b/mobile/src/lib/roles.ts @@ -0,0 +1,64 @@ +import { Role } from '@skur/sdk'; + +/** + * The roles the app talks about, mapped to the bits the contract enforces. + * + * The contract's vocabulary is capabilities (owner, approver, executor, proposer, guardian); the + * product's vocabulary is job titles. This file is the only place the two meet, so a title can + * never quietly drift from what the key can actually do. + */ +export type RoleId = 'owner' | 'admin' | 'signer' | 'guardian' | 'viewer'; + +export type RoleSpec = { + id: RoleId; + title: string; + /** What this role may do, in the words the Roles & Permissions screen shows. */ + grants: string; + bits: number; +}; + +export const ROLE_SPECS: RoleSpec[] = [ + { + id: 'owner', + title: 'Owner', + grants: 'Full access to all features: governance, approvals, execution and policy.', + bits: Role.OWNER | Role.APPROVER | Role.EXECUTOR, + }, + { + id: 'admin', + title: 'Admin', + grants: 'Manage day-to-day money movement: approve and execute payments.', + bits: Role.APPROVER | Role.EXECUTOR, + }, + { + id: 'signer', + title: 'Signer', + grants: 'Approve transactions and proposals. Cannot execute or change policy.', + bits: Role.APPROVER, + }, + { + id: 'guardian', + title: 'Guardian', + grants: 'An independent brake: veto critical payments, freeze the vault, confirm recovery. Holds no treasury role by design.', + bits: Role.GUARDIAN, + }, + { + id: 'viewer', + title: 'Viewer', + grants: 'View-only access. A vault is a shared object, so viewers need no on-chain role at all.', + bits: 0, + }, +]; + +export const roleSpec = (id: RoleId): RoleSpec => ROLE_SPECS.find((r) => r.id === id)!; + +/** The closest title for a member's bits, for badges on the team list. */ +export function titleForBits(bits: number): string { + if (bits & Role.GUARDIAN) return 'Guardian'; + if (bits & Role.OWNER) return 'Owner'; + if ((bits & Role.APPROVER) !== 0 && (bits & Role.EXECUTOR) !== 0) return 'Admin'; + if (bits & Role.APPROVER) return 'Signer'; + if (bits & Role.EXECUTOR) return 'Executor'; + if (bits & Role.PROPOSER) return 'Agent'; + return 'Viewer'; +} diff --git a/mobile/src/screens/ActivityLog.tsx b/mobile/src/screens/ActivityLog.tsx new file mode 100644 index 0000000..5e87490 --- /dev/null +++ b/mobile/src/screens/ActivityLog.tsx @@ -0,0 +1,143 @@ +import { useMemo, useState } from 'react'; +import { RefreshControl, View } from 'react-native'; +import { KIND_LABELS, Kind, Status, fmtAmount, fmtRelative, short, type Proposal } from '@skur/sdk'; +import { + BackButton, + Card, + CircleIcon, + Empty, + ErrorState, + Row, + Screen, + Skeleton, + Tabs, + TopBar, + type IconName, +} from '../components/ui'; +import { coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +type Filter = 'all' | 'approvals' | 'system'; +type Entry = { key: string; icon: IconName; tone: 'ok' | 'warn' | 'bad' | 'info' | 'dark'; title: string; sub: string; at: number; kind: Filter }; + +/** + * Screen 19 — the audit trail, derived from the proposals the chain records. Approvals are listed + * by signer; "system" is everything that changes the vault itself rather than moving money. + */ +export function ActivityLog({ onBack }: { onBack: () => void }) { + const C = useTheme(); + const { vaultId } = useStore(); + const q = useVaultView(vaultId); + const [filter, setFilter] = useState('all'); + + const entries = useMemo(() => { + const out: Entry[] = []; + const system = new Set([Kind.POLICY_UPDATE, Kind.MEMBER_SET, Kind.ASSET_LIMITS, Kind.MODE_RELAX, Kind.RECOVERY, Kind.RECIPIENT_TRUST]); + for (const p of (q.data?.proposals ?? []) as Proposal[]) { + const isSystem = system.has(p.kind); + const what = + p.kind === Kind.TRANSFER && p.asset + ? `${fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset))}` + : KIND_LABELS[p.kind]; + out.push({ + key: `${p.id}-open`, + icon: isSystem ? 'settings' : 'arrow-up-right', + tone: 'info', + title: `${KIND_LABELS[p.kind]} opened`, + sub: `#${p.id} · ${what} · by ${short(p.proposer)} · ${fmtRelative(p.createdAt)}`, + at: p.createdAt, + kind: isSystem ? 'system' : 'all', + }); + for (const a of p.approvals) { + out.push({ + key: `${p.id}-ap-${a}`, + icon: 'check', + tone: 'ok', + title: `Approved by ${short(a)}`, + sub: `#${p.id} · ${what}`, + at: p.createdAt + 1, + kind: 'approvals', + }); + } + for (const r of p.rejections) { + out.push({ + key: `${p.id}-rj-${r}`, + icon: 'x', + tone: 'warn', + title: `Rejected by ${short(r)}`, + sub: `#${p.id} · ${what}`, + at: p.createdAt + 1, + kind: 'approvals', + }); + } + for (const g of p.confirmations) { + out.push({ + key: `${p.id}-cf-${g}`, + icon: 'shield', + tone: 'info', + title: `Guardian confirmed · ${short(g)}`, + sub: `#${p.id} · ${what}`, + at: p.createdAt + 1, + kind: 'approvals', + }); + } + if (p.status !== Status.PENDING) { + out.push({ + key: `${p.id}-end`, + icon: p.status === Status.EXECUTED ? 'check-circle' : p.status === Status.VETOED ? 'slash' : 'x-circle', + tone: p.status === Status.EXECUTED ? 'ok' : p.status === Status.VETOED ? 'bad' : 'warn', + title: + p.status === Status.EXECUTED + ? `${KIND_LABELS[p.kind]} executed` + : p.status === Status.VETOED + ? `${KIND_LABELS[p.kind]} vetoed` + : `${KIND_LABELS[p.kind]} closed`, + sub: `#${p.id} · ${what}`, + at: p.createdAt + 2, + kind: isSystem ? 'system' : 'all', + }); + } + } + return out.sort((a, b) => b.at - a.at); + }, [q.data]); + + const visible = entries.filter((e) => filter === 'all' || e.kind === filter); + + return ( + } title="Activity Logs" />} + refreshControl={ q.refetch()} tintColor={C.text2} />} + > + + + {q.isLoading ? : null} + {q.error ? q.refetch()} /> : null} + {!q.isLoading && visible.length === 0 ? ( + Nothing in this view yet. + ) : ( + + {visible.map((e, i) => ( + } + title={e.title} + subtitle={e.sub} + last={i === visible.length - 1} + /> + ))} + + )} + + + ); +} diff --git a/mobile/src/screens/Dashboard.tsx b/mobile/src/screens/Dashboard.tsx new file mode 100644 index 0000000..17c2cb5 --- /dev/null +++ b/mobile/src/screens/Dashboard.tsx @@ -0,0 +1,191 @@ +import { RefreshControl, Text, View } from 'react-native'; +import { KIND_LABELS, Kind, Mode, Status, fmtAmount, fmtRelative, type Proposal } from '@skur/sdk'; +import { + Card, + Empty, + ErrorState, + IconButton, + ModeBadge, + Notice, + Row, + Screen, + SectionLabel, + Skeleton, + StatusBadge, + Tape, + TierBadge, + TopBar, +} from '../components/ui'; +import { Stat } from '../components/kit'; +import { Identicon } from '../components/Identicon'; +import { TokenMark, coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +/** + * Screen 8 — the dashboard. The treasury's value, what is waiting, who is on it, and what just + * happened. No fiat figures: this app has no price oracle, and a made-up dollar number on a + * treasury screen is worse than none. + */ +export function Dashboard({ + onOpenProposals, + onOpenProposal, + onOpenTreasury, + onSwitch, +}: { + onOpenProposals: () => void; + onOpenProposal: (id: bigint) => void; + onOpenTreasury: () => void; + onSwitch: () => void; +}) { + const C = useTheme(); + const { vaultId } = useStore(); + const q = useVaultView(vaultId); + + if (q.isLoading) { + return ( + }> + + + ); + } + if (q.error || !q.data) { + const message = q.error instanceof Error ? q.error.message : ''; + const badId = /not found|deleted|invalid|parse/i.test(message); + return ( + } />}> + q.refetch()} + /> + + ); + } + + const v = q.data; + const pending = v.proposals.filter((x) => x.status === Status.PENDING); + const recent = [...v.proposals].sort((a, b) => b.createdAt - a.createdAt).slice(0, 3); + const primary = [...v.assets].sort((a, b) => + Number(b.balance / 10n ** BigInt(coinDecimals(b.coinType))) - Number(a.balance / 10n ** BigInt(coinDecimals(a.coinType))), + )[0]; + + const line = (p: Proposal) => + p.kind === Kind.TRANSFER && p.asset + ? fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset)) + : KIND_LABELS[p.kind]; + + return ( + } + title={v.vault.name} + right={} + /> + } + refreshControl={ + q.refetch()} tintColor={C.text2} /> + } + > + + {v.vault.mode !== Mode.NORMAL ? : null} + {v.vault.mode === Mode.LOCKDOWN ? ( + This vault is frozen. Nothing outgoing executes. Deposits still work. + ) : v.vault.mode === Mode.ELEVATED ? ( + Elevated: every payment is escalated one tier and the caps are halved. + ) : null} + + + + Total treasury value + + + + {primary ? fmtAmount(primary.balance, coinDecimals(primary.coinType)) : '0'} + + {' '} + {primary ? coinSymbol(primary.coinType) : ''} + + + + {v.assets.length === 1 + ? 'one asset approved' + : `across ${v.assets.length} assets — see Treasury for the breakdown`} + + + + + {v.assets.slice(0, 2).map((a) => ( + + ))} + + + + + + + + + + Recent activity + + View all + + + {recent.length === 0 ? ( + Nothing has happened yet. Fund the vault, or open the first payment. + ) : ( + + {recent.map((p, i) => ( + + ) : ( + + ) + } + title={line(p)} + subtitle={`${p.memo || KIND_LABELS[p.kind]} · ${fmtRelative(p.createdAt)}`} + trailing={ + p.status === Status.PENDING && p.kind === Kind.TRANSFER ? ( + + ) : ( + + ) + } + onPress={() => onOpenProposal(p.id)} + chevron + last={i === recent.length - 1} + /> + ))} + + )} + + + + } + title="Treasury" + subtitle="Balances, breakdown, send and request" + onPress={onOpenTreasury} + chevron + last + /> + + + + ); +} diff --git a/mobile/src/screens/Help.tsx b/mobile/src/screens/Help.tsx new file mode 100644 index 0000000..ec41547 --- /dev/null +++ b/mobile/src/screens/Help.tsx @@ -0,0 +1,92 @@ +import { useState } from 'react'; +import { Linking, Text, View } from 'react-native'; +import { BackButton, Button, Card, CircleIcon, Expandable, Row, Screen, SectionLabel, TopBar } from '../components/ui'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; + +const SUPPORT_EMAIL = 'support@skur.app'; +const DOCS_URL = 'https://github.com/Emmyhack/skur#readme'; +const ISSUES_URL = 'https://github.com/Emmyhack/skur/issues/new'; + +const FAQS: [string, string][] = [ + [ + 'What happens if I lose my phone?', + 'The key is gone with it — it never leaves the secure element. Your address is still a member of the vault, and guardian recovery can move your roles to a new key after a delay any owner can cancel. The treasury is never at the mercy of one device.', + ], + [ + 'Why does a payment sometimes wait?', + 'The vault scores every payment by amount, destination and today’s outflow. High-risk and critical payments carry a timelock so a theft in progress can be vetoed before it settles.', + ], + [ + 'Can the app move money on its own?', + 'No. Every rule is enforced by a Move object on Sui. The app proposes, approves and executes only what the vault itself permits — and only after the OS releases the key behind your biometric.', + ], + [ + 'Who can see the vault?', + 'Anyone. A vault is a shared object; balances, policy and proposals are public reads. What is gated is money leaving, never reading.', + ], +]; + +/** Screen 21 — help: answers first, humans second. */ +export function Help({ onBack }: { onBack: () => void }) { + const C = useTheme(); + const [open, setOpen] = useState(0); + return ( + } title="Help & Support" />} + footer={ + + } + > + + + + Need assistance? + We're here to help. + + + + FAQs · Common questions + {FAQS.map(([question, answer], i) => ( + setOpen(open === i ? null : i)} + > + {answer} + + ))} + + + + } + title="Documentation" + subtitle="Learn more about Skur" + onPress={() => void Linking.openURL(DOCS_URL)} + chevron + /> + } + title="Contact Support" + subtitle={SUPPORT_EMAIL} + onPress={() => void Linking.openURL(`mailto:${SUPPORT_EMAIL}`)} + chevron + /> + } + title="Report an Issue" + subtitle="Bug or feedback" + onPress={() => void Linking.openURL(ISSUES_URL)} + chevron + last + /> + + + + ); +} diff --git a/mobile/src/screens/Home.tsx b/mobile/src/screens/Home.tsx index d584b3b..37c471b 100644 --- a/mobile/src/screens/Home.tsx +++ b/mobile/src/screens/Home.tsx @@ -1,20 +1,13 @@ import { RefreshControl, Text, View } from 'react-native'; -import { - Mode, - Status, - describeReasons, - fmtAmount, - fmtDuration, - type VaultView, -} from '@skur/sdk'; +import { Mode, describeReasons, fmtAmount, fmtDuration, type VaultView } from '@skur/sdk'; import { Address, + Button, Card, Empty, ErrorState, IconButton, KV, - ModeBadge, Notice, Row, Screen, @@ -23,14 +16,29 @@ import { Tape, TopBar, } from '../components/ui'; -import { Identicon } from '../components/Identicon'; +import { BarChart, PortfolioBar } from '../components/kit'; import { TokenMark, coinDecimals, coinSymbol } from '../components/TokenMark'; import { useTheme } from '../state/theme'; import { F } from '../theme'; import { useVaultView } from '../hooks/useVault'; import { useStore } from '../state/store'; -export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwitch: () => void }) { +/** + * Screen 9 — the treasury overview: total balance, the portfolio breakdown, send/request, and + * what the vault enforces. Shares are by normalised units, not price — this app carries no + * oracle, and a breakdown that silently guessed at dollars would be a lie with a legend. + */ +export function Home({ + onOpenQueue, + onSwitch, + onSend, + onRequest, +}: { + onOpenQueue?: () => void; + onSwitch: () => void; + onSend?: () => void; + onRequest?: () => void; +}) { const C = useTheme(); const { vaultId } = useStore(); const q = useVaultView(vaultId); @@ -62,22 +70,25 @@ export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwi const v: VaultView = q.data; const p = v.vault.policy; - const pending = v.proposals.filter((x) => x.status === Status.PENDING); + + const palette = [C.accent, C.info, C.success, C.warning, C.error]; + const normalized = v.assets.map((a, i) => ({ + label: coinSymbol(a.coinType), + value: Number(a.balance) / 10 ** coinDecimals(a.coinType), + color: palette[i % palette.length], + })); + const primary = [...v.assets].sort( + (a, b) => Number(b.balance) / 10 ** coinDecimals(b.coinType) - Number(a.balance) / 10 ** coinDecimals(a.coinType), + )[0]; return ( } - title={v.vault.name} - right={} - /> - } + top={} />} refreshControl={ q.refetch()} tintColor={C.text2} /> } > - + {v.vault.mode !== Mode.NORMAL ? : null} {v.vault.mode === Mode.LOCKDOWN ? ( @@ -95,20 +106,27 @@ export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwi ) : null} - - - Posture - - - - Awaiting action - - {pending.length} - + Total balance + + {primary ? fmtAmount(primary.balance, coinDecimals(primary.coinType)) : '0'} + {primary ? coinSymbol(primary.coinType) : ''} + + {normalized.length > 1 ? ( + + - + ) : null} + + + + + Holdings {v.assets.length === 0 ? ( @@ -142,16 +160,10 @@ export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwi )} - {pending.length > 0 ? ( - - } - title={`${pending.length} proposal${pending.length === 1 ? '' : 's'} open`} - subtitle="Review what is waiting" - onPress={onOpenQueue} - chevron - last - /> + {normalized.length > 0 ? ( + + Asset breakdown + ({ label: n.label, value: n.value }))} /> ) : null} @@ -171,6 +183,12 @@ export function Home({ onOpenQueue, onSwitch }: { onOpenQueue: () => void; onSwi /> + {onOpenQueue ? ( + + + + ) : null} + This vault
      diff --git a/mobile/src/screens/More.tsx b/mobile/src/screens/More.tsx new file mode 100644 index 0000000..fa6f539 --- /dev/null +++ b/mobile/src/screens/More.tsx @@ -0,0 +1,64 @@ +import { View } from 'react-native'; +import { Card, CircleIcon, Row, Screen, TopBar } from '../components/ui'; + +/** The fifth tab: everything that is not money-in-motion, one tap deep. */ +export function More({ + onOpen, +}: { + onOpen: (screen: 'Security' | 'Policies' | 'Logs' | 'Receive' | 'Settings' | 'Help') => void; +}) { + return ( + }> + + + } + title="Security Center" + subtitle="Posture, the brake, maximum possible loss" + onPress={() => onOpen('Security')} + chevron + /> + } + title="Spending Policies" + subtitle="The rules every payment is scored against" + onPress={() => onOpen('Policies')} + chevron + /> + } + title="Activity Logs" + subtitle="Everything that happened, by whom" + onPress={() => onOpen('Logs')} + chevron + /> + } + title="Receive" + subtitle="The vault's address and accepted assets" + onPress={() => onOpen('Receive')} + chevron + last + /> + + + } + title="Settings" + subtitle="Profile, wallet, appearance, notifications" + onPress={() => onOpen('Settings')} + chevron + /> + } + title="Help & Support" + subtitle="FAQs, documentation, contact" + onPress={() => onOpen('Help')} + chevron + last + /> + + + + ); +} diff --git a/mobile/src/screens/Onboard.tsx b/mobile/src/screens/Onboard.tsx deleted file mode 100644 index a0bab95..0000000 --- a/mobile/src/screens/Onboard.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { usePreventScreenCapture } from 'expo-screen-capture'; -import { useEffect, useState } from 'react'; -import { Text, View } from 'react-native'; -import { - Address, - Button, - Card, - Field, - Input, - Notice, - Screen, - SectionLabel, - Tabs, - TopBar, -} from '../components/ui'; -import { useTheme } from '../state/theme'; -import { F } from '../theme'; -import { biometricSupport, createSigner, importSigner, type BiometricSupport } from '../lib/keystore'; -import { useStore } from '../state/store'; - -/** - * Setting up the key on this device. - * - * The screen is explicit that this is a hot key. An approver or executor key belongs on a phone; - * a guardian key does not, because a guardian's whole value is being a control plane an attacker - * has to breach separately — and a guardian key sitting next to an approver key on the same device - * collapses the two planes the contract works to keep apart. - */ -export function Onboard({ onDone }: { onDone: () => void }) { - // No screenshots and no screen recording while this screen can hold a private key. The OS also - // blanks it in the app switcher. Nothing stops a second phone pointed at the first — the copy - // on the import path says to treat the key accordingly. - usePreventScreenCapture(); - const C = useTheme(); - const { refreshSigner } = useStore(); - const [mode, setMode] = useState<'create' | 'import'>('create'); - const [bio, setBio] = useState(null); - const [secret, setSecret] = useState(''); - const [address, setAddress] = useState(null); - const [error, setError] = useState(null); - const [busy, setBusy] = useState(false); - - useEffect(() => { - void biometricSupport().then(setBio); - }, []); - - const act = async () => { - setError(null); - setBusy(true); - try { - const addr = mode === 'create' ? await createSigner() : await importSigner(secret); - // Only the local state. Refreshing the store's signer here would swap this screen out from - // under the user before the confirmation — and its Continue button is what records that - // onboarding finished. Without that record, every cold start began at the welcome tour. - setAddress(addr); - } catch (e) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setBusy(false); - } - }; - - if (address) { - return ( - } - footer={ - - } - > - - - The key is in this device's secure element. It is released for one action at a - time, after {bio?.label ?? 'a device check'}. - - - This device signs as -
      - - - This address holds no roles yet. An owner of a vault has to add it — as an approver, an - executor, or both — before it can do anything. Send them the address above. - - - Do not use this device for a guardian key. A guardian is the second control plane an - attacker has to breach; keeping it on the same phone as an approver key defeats the - point of having two. - - - - ); - } - - return ( - } - footer={ - - } - > - - - - {bio && !bio.enrolled ? ( - - No {bio.available ? bio.label : 'screen lock'} is set up on this device. Set one up - first — without it the key would sit unprotected. - - ) : null} - - {mode === 'create' ? ( - - - A new Ed25519 key is generated on the device and written to the secure element. It - never leaves the phone and is not backed up anywhere. - - - If you lose this device, the key is gone. That is what the vault's guardian - recovery is for: guardians can move your roles to a new key after a delay any owner - can cancel. - - - ) : ( - - - - - - Import a key that is already an approver or executor on your vault. Do not paste a - key that holds anything you are not prepared to have on a phone. - - - )} - - {error ? {error} : null} - - - ); -} diff --git a/mobile/src/screens/Policies.tsx b/mobile/src/screens/Policies.tsx new file mode 100644 index 0000000..82ea9f7 --- /dev/null +++ b/mobile/src/screens/Policies.tsx @@ -0,0 +1,176 @@ +import { useState } from 'react'; +import { Text, View } from 'react-native'; +import { Role, fmtAmount, fmtDuration, hasRole, tx as build, type Policy } from '@skur/sdk'; +import { + BackButton, + Button, + Card, + Field, + Input, + Notice, + Screen, + SectionLabel, + Sheet, + Skeleton, + TopBar, + TxStatus, +} from '../components/ui'; +import { CheckItem } from '../components/kit'; +import { coinDecimals, coinSymbol } from '../components/TokenMark'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { PACKAGE_ID } from '../lib/config'; +import { useTx } from '../hooks/useTx'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +/** + * Screen 17 — the spending policy, shown as the rules it actually is: which band an amount falls + * into, what each band demands, and what unknown recipients wait. Editing routes through + * governance like every other change — the phone proposes, it never decrees. + */ +export function Policies({ onBack }: { onBack: () => void }) { + const C = useTheme(); + const { vaultId, address } = useStore(); + const q = useVaultView(vaultId); + const tx = useTx(vaultId); + const [editing, setEditing] = useState(false); + const [low, setLow] = useState(''); + const [high, setHigh] = useState(''); + const [critical, setCritical] = useState(''); + + if (q.isLoading || !q.data) { + return ( + } title="Spending Policies" />}> + + + ); + } + + const p = q.data.vault.policy; + const asset = q.data.assets[0]; + const d = asset ? coinDecimals(asset.coinType) : 9; + const sym = asset ? coinSymbol(asset.coinType) : ''; + const myRoles = address ? (q.data.members.find((m) => m.address === address)?.roles ?? 0) : 0; + const isOwner = hasRole(myRoles, Role.OWNER); + + const parsed = { + low: low === '' ? p.approvalsLow : Number(low), + high: high === '' ? p.approvalsHigh : Number(high), + critical: critical === '' ? p.approvalsCritical : Number(critical), + }; + const sane = + [parsed.low, parsed.high, parsed.critical].every((n) => Number.isInteger(n) && n >= 1 && n <= 20) && + parsed.low <= parsed.high && + parsed.high <= parsed.critical; + const changed = parsed.low !== p.approvalsLow || parsed.high !== p.approvalsHigh || parsed.critical !== p.approvalsCritical; + + const propose = () => { + const next: Policy = { ...p, approvalsLow: parsed.low, approvalsHigh: parsed.high, approvalsCritical: parsed.critical }; + void tx + .run(() => build.proposePolicy(PACKAGE_ID, { vaultId: vaultId!, policy: next }), 'Propose this policy change') + .then((digest) => { + if (digest) setEditing(false); + }); + }; + + return ( + } title="Spending Policies" />} + footer={ + isOwner ? ( + + + + + ) : null + } + > + + Policy rules + + + + + + + + + {asset ? ( + + Per-asset caps · {sym} + + + + ) : null} + + + These rules are enforced by the vault object itself, not by this app. Changing them is a + governance proposal: it collects {p.governanceThreshold} owner approval + {p.governanceThreshold === 1 ? '' : 's'}, waits {fmtDuration(p.policyChangeDelay)}, and any + guardian can veto a change that weakens the vault. + + + + setEditing(false)} title="Edit policies"> + + + + + + + + + + + {!sane ? ( + Each band must need at least one approval, and never fewer than the band below it. + ) : null} + + + Everything not shown here carries over unchanged. Loosening any rule waits{' '} + {fmtDuration(p.policyChangeDelay)} and can be vetoed. + + + + + ); +} diff --git a/mobile/src/screens/Roles.tsx b/mobile/src/screens/Roles.tsx new file mode 100644 index 0000000..087577f --- /dev/null +++ b/mobile/src/screens/Roles.tsx @@ -0,0 +1,37 @@ +import { Text, View } from 'react-native'; +import { BackButton, Badge, Card, Screen, TopBar } from '../components/ui'; +import { CircleIcon } from '../components/ui'; +import { ROLE_SPECS } from '../lib/roles'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; + +const ICONS = { owner: 'key', admin: 'sliders', signer: 'edit-3', guardian: 'shield', viewer: 'eye' } as const; + +/** + * Screen 16 — what each role may do. These map one-to-one onto the capabilities the contract + * enforces, so nothing promised here can drift from what a key can actually sign. + */ +export function Roles({ onBack }: { onBack: () => void }) { + const C = useTheme(); + return ( + } title="Roles & Permissions" />}> + + {ROLE_SPECS.map((r) => ( + + + + {r.title} + {r.id === 'guardian' ? Separate plane : null} + + {r.grants} + + ))} + + Each role has specific permissions to ensure security and control. A guardian deliberately + holds no treasury role: its whole value is being a brake an attacker has to breach + separately, so the contract refuses to combine it with any of the others. + + + + ); +} diff --git a/mobile/src/screens/Security.tsx b/mobile/src/screens/Security.tsx index 48cb08b..da5f6bd 100644 --- a/mobile/src/screens/Security.tsx +++ b/mobile/src/screens/Security.tsx @@ -13,6 +13,7 @@ import { import { Button, Card, + CircleIcon, Icon, KV, Notice, @@ -21,6 +22,7 @@ import { TopBar, TxStatus, } from '../components/ui'; +import { Meter } from '../components/kit'; import { coinDecimals, coinSymbol } from '../components/TokenMark'; import { useTheme } from '../state/theme'; import { F } from '../theme'; @@ -60,13 +62,34 @@ export function Security() { const v = q.data; const p = v.vault.policy; + const holding = posture.filter((i) => i.ok === 'ok').length; + const allOk = holding === posture.length; return ( } + top={} footer={tx.state.phase !== 'idle' ? : null} > + + + + + {allOk ? 'Your assets are protected' : 'Posture has gaps'} + + + Enforced by the vault object, not by this app. + + + + + + + What holds diff --git a/mobile/src/screens/Send.tsx b/mobile/src/screens/Send.tsx index 9869a7e..20bbdea 100644 --- a/mobile/src/screens/Send.tsx +++ b/mobile/src/screens/Send.tsx @@ -19,6 +19,7 @@ import { Notice, Screen, SectionLabel, + Tabs, TierBadge, TopBar, TrustBadge, @@ -46,6 +47,7 @@ export function Send({ onDone }: { onDone: () => void }) { const tx = useTx(vaultId); const approved = (q.data?.assets ?? []).filter((a) => a.limits.approved); + const [direction, setDirection] = useState<'send' | 'request'>('send'); const [coinType, setCoinType] = useState(''); const [to, setTo] = useState(''); const [amountText, setAmountText] = useState(''); @@ -87,7 +89,7 @@ export function Send({ onDone }: { onDone: () => void }) { if (approved.length === 0) { return ( - }> + }> No asset is approved for this vault yet. An owner has to approve one through governance before anything can be paid. @@ -96,9 +98,38 @@ export function Send({ onDone }: { onDone: () => void }) { ); } + if (direction === 'request') { + return ( + }> + + + + Deposits are never gated — in any mode, from any address. Share this vault's address + and the funds land directly on it. + + + Vault address +
      + + + Sending a coin type this vault has not approved will fail. Approving one is a + governance action. + + + + ); + } + return ( } + top={} footer={ @@ -134,6 +165,14 @@ export function Send({ onDone }: { onDone: () => void }) { } > + Opening a payment is not approving it. The vault scores it first and then says what it needs. @@ -178,7 +217,13 @@ export function Send({ onDone }: { onDone: () => void }) { - + {amount > 0n ? ( + + = {amount.toString()} base units + + ) : null} + + diff --git a/mobile/src/screens/Settings.tsx b/mobile/src/screens/Settings.tsx index f3427b9..25d05b0 100644 --- a/mobile/src/screens/Settings.tsx +++ b/mobile/src/screens/Settings.tsx @@ -1,21 +1,46 @@ import { useEffect, useState } from 'react'; import { Alert, Text, View } from 'react-native'; -import { Address, Button, Card, KV, Notice, Row, Screen, SectionLabel, Tabs, TopBar } from '../components/ui'; +import Constants from 'expo-constants'; +import { + Address, + Button, + Card, + Field, + IconButton, + Input, + KV, + Notice, + Row, + Screen, + SectionLabel, + Sheet, + Tabs, + TopBar, +} from '../components/ui'; +import { Avatar, SwitchRow } from '../components/kit'; import { useScheme, type Scheme } from '../state/theme'; import { useTheme } from '../state/theme'; import { F } from '../theme'; -import { API_URL, NETWORK, PACKAGE_ID, explorer } from '../lib/config'; +import { API_URL, NETWORK, PACKAGE_ID } from '../lib/config'; import { biometricSupport, forgetSigner, type BiometricSupport } from '../lib/keystore'; import { enablePush, type PushResult } from '../lib/notifications'; import { useStore } from '../state/store'; -export function Settings() { +/** + * Screen 20 — settings: who you are, the organisation, the wallet on this device, security, + * notifications and appearance. Dark mode is a switch and a precise preference — the switch flips + * ground, the segmented control underneath can hand the choice back to the system. + */ +export function Settings({ onOpenHelp, onOpenSecurity }: { onOpenHelp?: () => void; onOpenSecurity?: () => void }) { const C = useTheme(); - const { scheme, setScheme } = useScheme(); - const { address, vaultId, closeVault, refreshSigner } = useStore(); + const { scheme, dark, setScheme } = useScheme(); + const { address, vaultId, profile, saveProfile, closeVault, refreshSigner } = useStore(); const [bio, setBio] = useState(null); const [push, setPush] = useState(null); const [pushBusy, setPushBusy] = useState(false); + const [editing, setEditing] = useState(false); + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); useEffect(() => { void biometricSupport().then(setBio); @@ -27,57 +52,60 @@ export function Settings() { 'The key is deleted from this device and cannot be recovered. Your address stays a member of the vault until governance removes it — guardians can move your roles to a new key, which is what recovery is for.', [ { text: 'Cancel', style: 'cancel' }, - { - text: 'Forget it', - style: 'destructive', - onPress: () => { - void forgetSigner().then(refreshSigner); - }, - }, + { text: 'Forget it', style: 'destructive', onPress: () => void forgetSigner().then(refreshSigner) }, ], ); + const version = Constants.expoConfig?.version ?? '1.0.0'; + return ( }> - - Appearance - setScheme(s as Scheme)} + + } + title={profile?.name ?? 'No name set'} + subtitle={profile?.email || 'No email — only used for notifications'} + trailing={ + { + setName(profile?.name ?? ''); + setEmail(profile?.email ?? ''); + setEditing(true); + }} + /> + } + last /> - + + + {vaultId ? ( + + Organisation + + + + + + ) : null} - This device + Wallets {address ? ( <> - Signs as + This device signs as
      - + ) : ( - - No signing key on this device. - + No signing key on this device. )} - - This is a hot key: appropriate for an approver or an executor, whose authority is - bounded by the policy. A guardian key belongs somewhere this phone is not. - {address ? ( {push && !push.ok ? {push.reason} : null} - {push?.ok ? ( - - This device hears about proposals that need its role, vetoes, freezes and the - circuit breaker. Tapping one opens the exact proposal. - - ) : null} ) : null} - Network + Appearance + setScheme(v ? 'dark' : 'light')} + icon="moon" + /> + + setScheme(s as Scheme)} + /> + + + + About + + + + + - {vaultId ? ( - - Vault - - - - - - ) : null} - Skur has not been audited. Do not put real value behind it until an independent audit is complete. + + setEditing(false)} title="Edit profile"> + + + + + + + + + + ); } diff --git a/mobile/src/screens/Team.tsx b/mobile/src/screens/Team.tsx new file mode 100644 index 0000000..972a5e1 --- /dev/null +++ b/mobile/src/screens/Team.tsx @@ -0,0 +1,183 @@ +import { useState } from 'react'; +import { RefreshControl, Text, View } from 'react-native'; +import { Role, hasRole, short, tx as build } from '@skur/sdk'; +import { + Badge, + Button, + Card, + ErrorState, + Field, + IconButton, + Input, + Notice, + Row, + Screen, + SectionLabel, + Sheet, + Skeleton, + TopBar, + TxStatus, +} from '../components/ui'; +import { Identicon } from '../components/Identicon'; +import { ROLE_SPECS, roleSpec, titleForBits, type RoleId } from '../lib/roles'; +import { useTheme } from '../state/theme'; +import { F } from '../theme'; +import { PACKAGE_ID } from '../lib/config'; +import { useTx } from '../hooks/useTx'; +import { useVaultView } from '../hooks/useVault'; +import { useStore } from '../state/store'; + +const ADDRESS = /^0x[0-9a-fA-F]{64}$/; + +/** + * Screen 15 — the team. The roster is the chain's, not a local list, and an invitation is a + * governance proposal: it collects owner approvals like any other change to who can move money. + */ +export function Team({ onOpenRoles }: { onOpenRoles: () => void }) { + const C = useTheme(); + const { vaultId, address, profile } = useStore(); + const q = useVaultView(vaultId); + const tx = useTx(vaultId); + + const [inviting, setInviting] = useState(false); + const [invitee, setInvitee] = useState(''); + const [role, setRole] = useState('signer'); + + const myRoles = address ? (q.data?.members.find((m) => m.address === address)?.roles ?? 0) : 0; + const isOwner = hasRole(myRoles, Role.OWNER); + const trimmed = invitee.trim(); + const valid = ADDRESS.test(trimmed); + const already = q.data?.members.some((m) => m.address.toLowerCase() === trimmed.toLowerCase()) ?? false; + + if (q.isLoading) { + return ( + }> + + + ); + } + if (q.error || !q.data) { + return ( + }> + q.refetch()} /> + + ); + } + + const members = q.data.members; + + return ( + } + /> + } + refreshControl={ q.refetch()} tintColor={C.text2} />} + footer={ + isOwner ? ( + + + + + ) : null + } + > + + + {members.length} member{members.length === 1 ? '' : 's'} + + + {members.map((m, i) => { + const me = m.address === address; + const title = titleForBits(m.roles); + return ( + } + title={me && profile?.name ? `${profile.name} (You)` : me ? `${short(m.address)} (You)` : short(m.address)} + subtitle={me ? undefined : short(m.address) === m.address ? undefined : undefined} + trailing={ + {title} + } + last={i === members.length - 1} + /> + ); + })} + + + + + + + {!isOwner ? ( + + Changing the roster takes an owner. Membership is a governance action, approved like any + other change to who can move money. + + ) : ( + + An invitation opens a proposal. It executes once {q.data.vault.policy.governanceThreshold} owner + {q.data.vault.policy.governanceThreshold === 1 ? ' has' : 's have'} approved it. + + )} + + + setInviting(false)} title="Invite a member"> + + + + + + Role + + {ROLE_SPECS.filter((r) => r.id !== 'viewer').map((r) => ( + + ))} + + + {roleSpec(role).grants} + + + {already ? That address is already a member. : null} + + + + + ); +} diff --git a/mobile/src/screens/Transactions.tsx b/mobile/src/screens/Transactions.tsx index 1b032c0..fabd8d9 100644 --- a/mobile/src/screens/Transactions.tsx +++ b/mobile/src/screens/Transactions.tsx @@ -1,14 +1,18 @@ +import { useState } from 'react'; import { RefreshControl, Text, View } from 'react-native'; import { KIND_LABELS, Kind, Status, fmtAmount, fmtRelative, type Proposal } from '@skur/sdk'; import { + Address, Card, Empty, ErrorState, + Notice, Row, Screen, SectionLabel, Skeleton, StatusBadge, + Tabs, TierBadge, TopBar, } from '../components/ui'; @@ -19,91 +23,131 @@ import { F } from '../theme'; import { useVaultView } from '../hooks/useVault'; import { useStore } from '../state/store'; +type Filter = 'all' | 'sent' | 'received'; + +/** + * Screen 10 — the transaction list. "Sent" is every transfer that executed; "Received" is honest + * about what the chain does: deposits land directly on the vault object, not through proposals, + * so there is no per-deposit feed here — only where to send and what is accepted. + */ export function Transactions({ onOpen }: { onOpen: (id: bigint) => void }) { const C = useTheme(); const { vaultId } = useStore(); const q = useVaultView(vaultId); + const [filter, setFilter] = useState('all'); + + const all = q.data?.proposals ?? []; + const pending = all.filter((p) => p.status === Status.PENDING); + const settled = all.filter((p) => p.status !== Status.PENDING); + const sent = all.filter((p) => p.kind === Kind.TRANSFER && p.status === Status.EXECUTED); - const pending = (q.data?.proposals ?? []).filter((p) => p.status === Status.PENDING); - const settled = (q.data?.proposals ?? []).filter((p) => p.status !== Status.PENDING); + const line = (p: Proposal) => + p.kind === Kind.TRANSFER && p.asset + ? fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset)) + : KIND_LABELS[p.kind]; - const line = (p: Proposal) => { - if (p.kind === Kind.TRANSFER && p.asset) { - return `${fmtAmount(p.amount, coinDecimals(p.asset), coinSymbol(p.asset))}`; - } - return KIND_LABELS[p.kind]; - }; + const item = (p: Proposal, i: number, arr: Proposal[]) => ( + : + } + title={line(p)} + subtitle={ + p.status === Status.PENDING ? ( + `${p.memo || KIND_LABELS[p.kind]} · ${p.approvals.length}/${p.reqApprovals} approvals` + ) : ( + + {(p.memo ? `${p.memo} · ` : '') + fmtRelative(p.createdAt)} + + ) + } + trailing={ + p.status === Status.PENDING && p.kind === Kind.TRANSFER ? : + } + onPress={() => onOpen(p.id)} + chevron + last={i === arr.length - 1} + /> + ); return ( } + top={} refreshControl={ q.refetch()} tintColor={C.text2} /> } > - + + + {q.isLoading ? : null} {q.error ? q.refetch()} /> : null} - - Awaiting action - {pending.length === 0 ? ( - Nothing is waiting. - ) : ( - - {pending.map((p, i) => ( - - ) : ( - - ) - } - title={line(p)} - subtitle={`${p.memo || KIND_LABELS[p.kind]} · ${p.approvals.length}/${p.reqApprovals} approvals`} - trailing={p.kind === Kind.TRANSFER ? : } - onPress={() => onOpen(p.id)} - chevron - last={i === pending.length - 1} - /> - ))} - - )} - + {filter === 'all' ? ( + <> + + Awaiting action + {pending.length === 0 ? ( + Nothing is waiting. + ) : ( + {pending.map((p, i) => item(p, i, pending))} + )} + + + Settled + {settled.length === 0 ? ( + Nothing has settled yet. + ) : ( + {settled.map((p, i) => item(p, i, settled))} + )} + + + ) : null} - - Settled - {settled.length === 0 ? ( - Nothing has settled yet. + {filter === 'sent' ? ( + sent.length === 0 ? ( + No payment has executed yet. ) : ( - - {settled.map((p, i) => ( - - ) : ( - - ) - } - title={line(p)} - subtitle={ - - {fmtRelative(p.createdAt)} - - } - trailing={} - onPress={() => onOpen(p.id)} - chevron - last={i === settled.length - 1} - /> - ))} + {sent.map((p, i) => item(p, i, sent))} + ) + ) : null} + + {filter === 'received' ? ( + + + Deposits land directly on the vault — in any mode, from any address — so they do not + appear as proposals. Share the address below to receive. + + + Vault address +
      - )} - + {(q.data?.assets ?? []).filter((a) => a.limits.approved).length > 0 ? ( + + {q.data!.assets + .filter((a) => a.limits.approved) + .map((a, i, arr) => ( + } + title={coinSymbol(a.coinType)} + subtitle={`holding ${fmtAmount(a.balance, coinDecimals(a.coinType))}`} + last={i === arr.length - 1} + /> + ))} + + ) : null} + + ) : null} ); diff --git a/mobile/src/screens/TxDetail.tsx b/mobile/src/screens/TxDetail.tsx index 6b28c3f..88b82cc 100644 --- a/mobile/src/screens/TxDetail.tsx +++ b/mobile/src/screens/TxDetail.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { Text, View } from 'react-native'; import { KIND_LABELS, @@ -5,12 +6,15 @@ import { Role, Status, Tier, + Trust, describeReasons, fmtAmount, fmtDuration, + fmtRelative, fmtTimestamp, hasRole, policyReductions, + short, tx as build, } from '@skur/sdk'; import { @@ -26,17 +30,20 @@ import { TierBadge, TopBar, TxStatus, + Sheet, } from '../components/ui'; +import { CheckItem, Meter, TimelineStep } from '../components/kit'; import { coinDecimals, coinSymbol } from '../components/TokenMark'; import { useTheme } from '../state/theme'; import { F } from '../theme'; import { PACKAGE_ID } from '../lib/config'; import { useTx } from '../hooks/useTx'; -import { useVaultView } from '../hooks/useVault'; +import { useTransferPreview, useVaultView } from '../hooks/useVault'; import { useStore } from '../state/store'; /** - * One proposal, and the actions this device's key is actually allowed to take on it. + * Screens 12–14 in one place: the details of a proposal, its approval flow as a timeline, the + * review-before-signing checks, and the actions this device's key is actually allowed to take. * * Every button is gated on the role the contract requires, so a signer is never offered something * the vault would refuse. The requirements shown are the ones pinned when the proposal was opened; @@ -48,10 +55,22 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { const { vaultId, address } = useStore(); const q = useVaultView(vaultId); const tx = useTx(vaultId); + const [simulating, setSimulating] = useState(false); const p = q.data?.proposals.find((x) => x.id === id); const roles = address ? (q.data?.members.find((m) => m.address === address)?.roles ?? 0) : 0; + const isTransfer = p?.kind === Kind.TRANSFER; + // The simulation re-runs the vault's own preview for this exact payment, on demand. + const preview = useTransferPreview({ + vaultId, + coinType: p?.asset ?? '', + amount: p?.amount ?? 0n, + recipient: p?.recipient ?? '', + sender: address, + enabled: simulating && Boolean(isTransfer && p?.asset), + }); + if (!p || !q.data) { return ( } title="Proposal" />}> @@ -60,7 +79,6 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { ); } - const isTransfer = p.kind === Kind.TRANSFER; const voteRole = isTransfer ? Role.APPROVER : Role.OWNER; const canVote = hasRole(roles, voteRole); const canExecute = isTransfer ? hasRole(roles, Role.EXECUTOR) : roles !== 0; @@ -89,6 +107,14 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { const reasons = describeReasons(p.reasons); const reductions = p.newPolicy ? policyReductions(q.data.vault.policy, p.newPolicy) : []; + // Screen 14's checks, computed from chain state rather than asserted. + const recipientRecord = q.data.recipients.find((r) => r.address === p.recipient); + const trust = recipientRecord?.trust ?? Trust.UNKNOWN; + const asset = p.asset ? q.data.assets.find((a) => a.coinType === p.asset) : undefined; + const withinPerTx = !asset || asset.limits.perTxMax === 0n || p.amount <= asset.limits.perTxMax; + const recipientKnown = trust !== Trust.UNKNOWN && trust !== Trust.BLOCKED; + const noRedFlags = trust !== Trust.BLOCKED && p.reductionMask === 0; + const executeTx = () => { if (isTransfer && p.asset) return build.executeTransfer(PACKAGE_ID, { vaultId: vaultId!, coinType: p.asset, proposalId: id }); @@ -102,6 +128,46 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { throw new Error('nothing to execute for this kind'); }; + // Screen 13 — the approval flow, as it stands on chain right now. + const flow: { title: string; subtitle: string; state: 'done' | 'active' | 'todo' }[] = [ + { + title: 'Proposed', + subtitle: `by ${short(p.proposer)} · ${fmtRelative(p.createdAt)}`, + state: 'done', + }, + ...p.approvals.map((a) => ({ + title: 'Approved', + subtitle: short(a), + state: 'done' as const, + })), + ...Array.from({ length: Math.max(0, p.reqApprovals - liveApprovals) }).map((_, i) => ({ + title: 'Approval', + subtitle: i === 0 && canVote && !voted ? 'Yours, if you give it' : 'Awaiting a signer', + state: (i === 0 ? 'active' : 'todo') as 'active' | 'todo', + })), + ...(p.reqGuardians > 0 + ? [ + { + title: 'Guardian confirmation', + subtitle: `${liveConfirmations} of ${p.reqGuardians}`, + state: (liveConfirmations >= p.reqGuardians ? 'done' : 'todo') as 'done' | 'todo', + }, + ] + : []), + { + title: p.status === Status.EXECUTED ? 'Executed' : 'Execution', + subtitle: + p.status === Status.EXECUTED + ? 'Settled on chain' + : !timeMet + ? `Waits until ${fmtTimestamp(p.executableAt)}` + : ready + ? 'Ready now' + : 'After the approvals above', + state: p.status === Status.EXECUTED ? 'done' : ready && open ? 'active' : 'todo', + }, + ]; + return ( } title={`#${id} · ${KIND_LABELS[p.kind]}`} />} @@ -114,7 +180,7 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { + ) : null} ) : null} @@ -226,6 +308,63 @@ export function TxDetail({ id, onBack }: { id: bigint; onBack: () => void }) { ) : null} + {open && isTransfer && (canVote || canExecute || isGuardian) ? ( + + Review before signing + + + + + + + + ) : null} + + + Approval flow + + {flow.map((step, i) => ( + + ))} + + + What it needs void }) { ) : null} + + setSimulating(false)} title="Simulation"> + + + The vault's own preview, re-run against its state right now — the same code + execution will run. + + {preview.isLoading ? ( + Asking the vault… + ) : preview.data ? ( + + + It would demand + + + + + + + + ) : preview.error ? ( + + The vault refused the simulation: {preview.error instanceof Error ? preview.error.message : 'it would not execute as-is.'} + + ) : null} + + ); } diff --git a/mobile/src/screens/Welcome.tsx b/mobile/src/screens/Welcome.tsx deleted file mode 100644 index 4ddecb1..0000000 --- a/mobile/src/screens/Welcome.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { Text, View } from 'react-native'; -import { Button, Logo, Screen, Tape } from '../components/ui'; -import { useTheme } from '../state/theme'; -import { F } from '../theme'; -import { NETWORK } from '../lib/config'; - -const POINTS: [string, string][] = [ - ['Approvals that follow the risk', 'The amount, the destination, today’s outflow and the vault’s posture decide how much sign-off a payment needs.'], - ['A brake you can reach', 'Freeze the vault from anywhere. Any guardian can veto a critical payment before it settles.'], - ['Your key stays on the phone', 'Held in the secure element behind your face or fingerprint, and released for one action at a time.'], -]; - -export function Welcome({ onStart }: { onStart: () => void }) { - const C = useTheme(); - return ( - - Get started - - } - > - - - - - A valid signature is not a safe payment - - - Skur decides how much authorization a payment needs, and whether it may settle right - now — enforced in Move, in a shared object anyone can read. - - - - - {POINTS.map(([title, body]) => ( - - {title} - - {body} - - - ))} - - - Sui · {NETWORK} · not audited - - - - ); -} diff --git a/mobile/src/screens/onboarding/AddMembers.tsx b/mobile/src/screens/onboarding/AddMembers.tsx new file mode 100644 index 0000000..8391a52 --- /dev/null +++ b/mobile/src/screens/onboarding/AddMembers.tsx @@ -0,0 +1,161 @@ +import { useState } from 'react'; +import { Text, View } from 'react-native'; +import { + Badge, + BackButton, + Button, + Card, + Field, + IconButton, + Input, + Notice, + Row, + Screen, + SectionLabel, + Sheet, + TopBar, +} from '../../components/ui'; +import { Avatar } from '../../components/kit'; +import { Identicon } from '../../components/Identicon'; +import { short } from '@skur/sdk'; +import { ROLE_SPECS, roleSpec, type RoleId } from '../../lib/roles'; +import { useTheme } from '../../state/theme'; +import { F } from '../../theme'; +import { useStore } from '../../state/store'; + +export type MemberDraft = { address: string; role: RoleId }; + +const ADDRESS = /^0x[0-9a-fA-F]{64}$/; + +/** + * Screen 6 — the roster. You are the first owner; everyone else is an address and a role. The + * contract writes this at creation, so what is promised here is exactly what will hold. + */ +export function AddMembers({ + members, + onBack, + onDone, +}: { + members: MemberDraft[]; + onBack: () => void; + onDone: (members: MemberDraft[]) => void; +}) { + const C = useTheme(); + const { profile } = useStore(); + const [list, setList] = useState(members); + const [adding, setAdding] = useState(false); + const [address, setAddress] = useState(''); + const [role, setRole] = useState('signer'); + + const trimmed = address.trim(); + const valid = ADDRESS.test(trimmed); + const duplicate = list.some((m) => m.address.toLowerCase() === trimmed.toLowerCase()); + const guardians = list.filter((m) => m.role === 'guardian').length; + + const add = () => { + setList([...list, { address: trimmed, role }]); + setAddress(''); + setRole('signer'); + setAdding(false); + }; + + return ( + } title="Add Members" />} + footer={ + + } + > + + + Invite your team members and set their roles. + + + + } + title={`${profile?.name ?? 'You'} (You)`} + subtitle="Key created in the next step" + trailing={Owner} + last={list.length === 0} + /> + {list.map((m, i) => ( + } + title={short(m.address)} + subtitle={roleSpec(m.role).grants} + trailing={ + + {roleSpec(m.role).title} + setList(list.filter((x) => x.address !== m.address))} + /> + + } + last={i === list.length - 1} + /> + ))} + + + + + {guardians === 0 ? ( + + No guardian yet. A guardian is an independent key that can veto a theft in progress — + without one, the vault is only as safe as its signers. You can also add one later + through governance. + + ) : null} + + + Members are written on chain at creation. Viewers need no role — a vault is a shared + object anyone can read. + + + + setAdding(false)} title="Add a member"> + + + + + + Role + + {ROLE_SPECS.filter((r) => r.id !== 'viewer' && r.id !== 'owner').map((r) => ( + + ))} + + + {roleSpec(role).grants} + + + {duplicate ? That address is already on the roster. : null} + + + + + ); +} diff --git a/mobile/src/screens/onboarding/ConnectWallet.tsx b/mobile/src/screens/onboarding/ConnectWallet.tsx new file mode 100644 index 0000000..f026548 --- /dev/null +++ b/mobile/src/screens/onboarding/ConnectWallet.tsx @@ -0,0 +1,305 @@ +import { useEffect, useState } from 'react'; +import { Text, View } from 'react-native'; +import { usePreventScreenCapture } from 'expo-screen-capture'; +import { Role, templateById, tx as build } from '@skur/sdk'; +import { + Address, + BackButton, + Badge, + Button, + Card, + Field, + Input, + Notice, + Row, + Screen, + SectionLabel, + Sheet, + TopBar, + TxProgress, +} from '../../components/ui'; +import { CheckItem } from '../../components/kit'; +import { Icon } from '../../components/ui'; +import { useTheme } from '../../state/theme'; +import { F, R } from '../../theme'; +import { client } from '../../lib/client'; +import { NETWORK, PACKAGE_ID } from '../../lib/config'; +import { biometricSupport, createSigner, importSigner, unlockSigner, type BiometricSupport } from '../../lib/keystore'; +import { describeFailure } from '@skur/sdk'; +import { hapticError, hapticSuccess } from '../../lib/haptics'; +import { roleSpec } from '../../lib/roles'; +import { useStore } from '../../state/store'; +import type { OrgDraft } from './CreateOrg'; +import type { MemberDraft } from './AddMembers'; +import type { TxState } from '../../hooks/useTx'; + +/** + * Screen 7 — the signer. + * + * The real wallet on a phone is the phone: an Ed25519 key in the secure element, released one + * action at a time behind a biometric. The external wallets people know from the desktop are + * listed so the choice is visible, and marked honestly until wallet-to-wallet connections ship. + */ +const EXTERNAL_WALLETS = ['Slush', 'Suiet', 'Backpack', 'Ledger', 'Nightly', 'OKX Wallet'] as const; + +export function ConnectWallet({ + draft, + members, + onBack, + onDone, +}: { + /** Present when this run is creating an organisation; null when joining one. */ + draft: OrgDraft | null; + members: MemberDraft[]; + onBack: () => void; + onDone: () => void; +}) { + usePreventScreenCapture(); + const C = useTheme(); + const { address, refreshSigner, openVault, saveProfile, profile } = useStore(); + const [bio, setBio] = useState(null); + const [importing, setImporting] = useState(false); + const [secret, setSecret] = useState(''); + const [error, setError] = useState(null); + const [busy, setBusy] = useState(false); + const [state, setState] = useState({ phase: 'idle' }); + + useEffect(() => { + void biometricSupport().then(setBio); + }, []); + + const makeKey = async (how: 'create' | 'import') => { + setError(null); + setBusy(true); + try { + if (how === 'create') await createSigner(); + else await importSigner(secret); + await refreshSigner(); + setImporting(false); + setSecret(''); + } catch (e) { + setError(e instanceof Error ? e.message : String(e)); + } finally { + setBusy(false); + } + }; + + /** Build and execute the creation, and open the vault the chain hands back. */ + const createOrganisation = async () => { + if (!draft || !address) return; + setState({ phase: 'unlocking' }); + try { + const keypair = await unlockSigner(`Create ${draft.name} on Sui`); + setState({ phase: 'signing' }); + + const template = templateById('startup'); + const roster = [ + { address, roles: Role.OWNER | Role.APPROVER | Role.EXECUTOR }, + ...members + .filter((m) => roleSpec(m.role).bits !== 0) + .map((m) => ({ address: m.address, roles: roleSpec(m.role).bits })), + ]; + // The template assumes a team; the roster is what actually exists. Every threshold is + // clamped to the people who can meet it — the contract refuses anything else, rightly: a + // 2-of-1 vault is a locked box. Growing the team later raises these through governance. + const owners = roster.filter((m) => m.roles & Role.OWNER).length; + const approvers = roster.filter((m) => m.roles & Role.APPROVER).length; + const guardians = roster.filter((m) => m.roles & Role.GUARDIAN).length; + const policy = { + ...template.policy, + governanceThreshold: Math.min(template.policy.governanceThreshold, owners), + approvalsLow: Math.min(template.policy.approvalsLow, approvers), + approvalsHigh: Math.min(template.policy.approvalsHigh, approvers), + approvalsCritical: Math.min(template.policy.approvalsCritical, approvers), + guardianThreshold: Math.min(template.policy.guardianThreshold, Math.max(guardians, 1)), + guardianRequiredCritical: template.policy.guardianRequiredCritical && guardians > 0, + }; + const tx = build.createVault(PACKAGE_ID, { + name: draft.name, + policy, + members: roster, + assets: [{ coinType: '0x2::sui::SUI', limits: template.native }], + }); + + const result = await client.signAndExecuteTransaction({ + transaction: tx, + signer: keypair, + include: { effects: true }, + }); + if (result.FailedTransaction) { + throw new Error(result.FailedTransaction.status.error?.message ?? 'the network refused it'); + } + const digest = result.Transaction.digest; + setState({ phase: 'waiting', digest }); + await client.core.waitForTransaction({ digest }); + + const created = (result.Transaction.effects?.changedObjects ?? []).find( + (c) => c.outputOwner?.$kind === 'Shared' && c.idOperation === 'Created', + ); + const vaultId = created && 'objectId' in created ? (created as { objectId: string }).objectId : null; + if (!vaultId) throw new Error('the vault was created but its id could not be read — open it by id'); + + hapticSuccess(); + setState({ phase: 'done', digest }); + if (profile) saveProfile(profile); // keep as-is; descriptions stay local + openVault(vaultId); + onDone(); + } catch (e) { + const raw = e instanceof Error ? e.message : String(e); + if (raw === 'cancelled') { + setState({ phase: 'cancelled' }); + return; + } + hapticError(); + const funds = /gas|coin|balance|insufficient/i.test(raw); + setState({ + phase: 'error', + message: funds + ? `This device's address has no SUI to pay for creation on ${NETWORK}. Fund it and try again.` + : describeFailure(e), + }); + } + }; + + const creating = state.phase === 'unlocking' || state.phase === 'signing' || state.phase === 'waiting'; + + return ( + } title="Connect Wallet" />} + footer={ + address ? ( + + {state.phase !== 'idle' ? : null} + {draft ? ( + + ) : ( + + )} + + ) : undefined + } + > + + + Choose a wallet to connect to Skur. + + + {address ? ( + + + + This device + + Connected + + + Signs as +
      + + ) : ( + + + + + This device (recommended) + + + + A new Ed25519 key, generated here and written to the secure element. It never leaves + the phone and is released for one action at a time, behind{' '} + {bio?.enrolled ? bio.label : 'your screen lock'}. + + {bio && !bio.enrolled ? ( + + No {bio.available ? bio.label : 'screen lock'} is set up on this device. Set one up + first — without it the key would sit unprotected. + + ) : null} + + + + + {error ? {error} : null} + + )} + + + External wallets + + {EXTERNAL_WALLETS.map((w, i) => ( + + {w[0]} + + } + title={w} + trailing={Soon} + last={i === EXTERNAL_WALLETS.length - 1} + /> + ))} + + + Wallet-to-wallet connections are not wired up yet. The device key above is live today + and holds the same roles any wallet would. + + + + {!address ? ( + + + + ) : null} + + + setImporting(false)} title="Import a key"> + + + + + + {error ? {error} : null} + + + + ); +} diff --git a/mobile/src/screens/onboarding/CreateAccount.tsx b/mobile/src/screens/onboarding/CreateAccount.tsx new file mode 100644 index 0000000..f3aa125 --- /dev/null +++ b/mobile/src/screens/onboarding/CreateAccount.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react'; +import { Pressable, Text, View } from 'react-native'; +import { BackButton, Button, Field, Icon, Input, Notice, Screen, TopBar } from '../../components/ui'; +import { useTheme } from '../../state/theme'; +import { F, R } from '../../theme'; +import { useStore } from '../../state/store'; + +/** + * Screen 4 — who you are. + * + * There is deliberately no password and no federated login here. Skur's credential is the signing + * key in the phone's secure element, created on the next step and released by the OS behind a + * biometric — a password would be a second, weaker door into the same house. The name and email + * stay on this device: the chain identifies members by address, and the backend only ever sees + * what notification registration sends it. + */ +export function CreateAccount({ onBack, onDone }: { onBack: () => void; onDone: () => void }) { + const C = useTheme(); + const { profile, saveProfile } = useStore(); + const [name, setName] = useState(profile?.name ?? ''); + const [email, setEmail] = useState(profile?.email ?? ''); + const [agreed, setAgreed] = useState(false); + + const emailOk = email === '' || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); + const ready = name.trim().length > 0 && emailOk && agreed; + + return ( + } title="Create Account" />} + footer={ + + } + > + + + Enter your details to get started. + + + + + + + + + + {!emailOk ? That does not look like an email address. : null} + + setAgreed(!agreed)} + accessibilityRole="checkbox" + accessibilityState={{ checked: agreed }} + style={{ flexDirection: 'row', gap: 10, alignItems: 'center' }} + > + + {agreed ? : null} + + + I agree to the Terms of Service and Privacy Policy. + + + + + No password. Your signing key — created on the next step, held in this phone's + secure element — is the credential. + + + + ); +} diff --git a/mobile/src/screens/onboarding/CreateOrg.tsx b/mobile/src/screens/onboarding/CreateOrg.tsx new file mode 100644 index 0000000..2854766 --- /dev/null +++ b/mobile/src/screens/onboarding/CreateOrg.tsx @@ -0,0 +1,69 @@ +import { useState } from 'react'; +import { Text, View } from 'react-native'; +import { BackButton, Button, Card, Field, Input, KV, Screen, SectionLabel, TopBar } from '../../components/ui'; +import { useTheme } from '../../state/theme'; +import { F } from '../../theme'; +import { NETWORK } from '../../lib/config'; + +export type OrgDraft = { name: string; description: string }; + +/** + * Screen 5 — name the organisation. The blockchain row is fixed by the build: which Sui network + * this app points at is an environment decision, not something to mis-tap during setup. + */ +export function CreateOrg({ + draft, + onBack, + onDone, +}: { + draft: OrgDraft | null; + onBack: () => void; + onDone: (draft: OrgDraft) => void; +}) { + const C = useTheme(); + const [name, setName] = useState(draft?.name ?? ''); + const [description, setDescription] = useState(draft?.description ?? ''); + const ready = name.trim().length >= 2; + + return ( + } title="Create Organisation" />} + footer={ + + } + > + + + Set up your team or business on Skur. + + + + + + + + + + + + Blockchain + + + + + + + ); +} diff --git a/mobile/src/screens/onboarding/Launch.tsx b/mobile/src/screens/onboarding/Launch.tsx new file mode 100644 index 0000000..98f2489 --- /dev/null +++ b/mobile/src/screens/onboarding/Launch.tsx @@ -0,0 +1,45 @@ +import { Text, View } from 'react-native'; +import { Button, Logo, Screen } from '../../components/ui'; +import { useTheme } from '../../state/theme'; +import { F } from '../../theme'; +import { NETWORK } from '../../lib/config'; + +/** Screen 1 — the front door. */ +export function Launch({ onStart }: { onStart: () => void }) { + const C = useTheme(); + return ( + + Get started + + } + > + + + + Skur + + Secure. Shared. On Sui. + + + + The mobile treasury security layer for teams, DAOs and businesses building on Sui. + + + Sui · {NETWORK} · not audited + + + + ); +} diff --git a/mobile/src/screens/onboarding/Start.tsx b/mobile/src/screens/onboarding/Start.tsx new file mode 100644 index 0000000..5b13703 --- /dev/null +++ b/mobile/src/screens/onboarding/Start.tsx @@ -0,0 +1,47 @@ +import { Text, View } from 'react-native'; +import { Button, Logo, Screen } from '../../components/ui'; +import { useTheme } from '../../state/theme'; +import { F, R } from '../../theme'; + +/** Screen 3 — create a new organisation, or join one that already exists. */ +export function Start({ onCreate, onJoin }: { onCreate: () => void; onJoin: () => void }) { + const C = useTheme(); + return ( + + + + + } + > + + + Welcome to Skur! + + + Let's set up your secure organisation and get you started. + + + + + + + ); +} diff --git a/mobile/src/screens/onboarding/Tour.tsx b/mobile/src/screens/onboarding/Tour.tsx new file mode 100644 index 0000000..84a26b9 --- /dev/null +++ b/mobile/src/screens/onboarding/Tour.tsx @@ -0,0 +1,70 @@ +import { useState } from 'react'; +import { Text, View } from 'react-native'; +import { Button, Card, Screen } from '../../components/ui'; +import { CheckItem, Dots } from '../../components/kit'; +import { useTheme } from '../../state/theme'; +import { F } from '../../theme'; + +/** + * Screen 2 — what the product does, in four controls. One page of checks plus two pages of + * depth, so "Next" has somewhere to go and the dots are not decoration. + */ +const PAGES: { heading: string; sub: string; items: [string, string][] }[] = [ + { + heading: 'Your Treasury,\nUnder Control.', + sub: 'Four controls stand between a stolen key and your money.', + items: [ + ['Multi-Signature Security', 'Require multiple approvals'], + ['Spending Policies', 'Set limits and rules'], + ['Transaction Simulation', 'Check before you sign'], + ['Team Permissions', 'Manage roles and access'], + ], + }, + { + heading: 'Approvals that\nfollow the risk.', + sub: 'The amount, the destination and today’s outflow decide how much sign-off a payment needs.', + items: [ + ['Risk-tiered approvals', 'Routine, high and critical each demand their own quorum'], + ['Timelocks on big moves', 'Critical payments wait, so a theft can be vetoed'], + ['A loss envelope', 'A hard ceiling on what can leave in a day'], + ], + }, + { + heading: 'Enforced on chain,\nnot promised.', + sub: 'Every rule lives in a Move object anyone can read. The app cannot bend them, and neither can an attacker with one key.', + items: [ + ['Guardians', 'An independent brake that can veto or freeze'], + ['Key on your phone', 'In the secure element, behind your fingerprint or face'], + ['Recovery built in', 'Lose the phone, keep the treasury'], + ], + }, +]; + +export function Tour({ onDone }: { onDone: () => void }) { + const C = useTheme(); + const [page, setPage] = useState(0); + const p = PAGES[page]; + const last = page === PAGES.length - 1; + return ( + + + + + } + > + + {p.heading} + {p.sub} + + {p.items.map(([title, detail]) => ( + + ))} + + + + ); +} diff --git a/mobile/src/state/store.tsx b/mobile/src/state/store.tsx index 8126739..7022611 100644 --- a/mobile/src/state/store.tsx +++ b/mobile/src/state/store.tsx @@ -17,6 +17,9 @@ import { hasSigner, signerAddress } from '../lib/keystore'; */ export type Labelled = { address: string; label: string }; +/** Who is holding the phone, for the Settings header and notification registrations. Local only. */ +export type Profile = { name: string; email: string }; + type Store = { ready: boolean; /** Null until a key exists on the device. */ @@ -24,6 +27,8 @@ type Store = { vaultId: string | null; onboarded: boolean; book: Labelled[]; + profile: Profile | null; + saveProfile: (p: Profile) => void; openVault: (id: string) => void; closeVault: () => void; finishOnboarding: () => void; @@ -34,7 +39,12 @@ type Store = { }; const Ctx = createContext(null); -const K = { vault: 'skur.vault', onboarded: 'skur.onboarded', book: 'skur.book' } as const; +const K = { + vault: 'skur.vault', + onboarded: 'skur.onboarded', + book: 'skur.book', + profile: 'skur.profile', +} as const; /** * A normalised Sui object id: 0x and exactly 32 bytes of hex. Storage is validated on load @@ -50,6 +60,7 @@ export function StoreProvider({ children }: { children: ReactNode }) { const [vaultId, setVaultId] = useState(null); const [onboarded, setOnboarded] = useState(false); const [book, setBook] = useState([]); + const [profile, setProfile] = useState(null); const refreshSigner = useCallback(async () => { setAddress((await hasSigner()) ? await signerAddress() : null); @@ -57,11 +68,22 @@ export function StoreProvider({ children }: { children: ReactNode }) { useEffect(() => { void (async () => { - const [v, o, b] = await Promise.all([ + const [v, o, b, pr] = await Promise.all([ AsyncStorage.getItem(K.vault), AsyncStorage.getItem(K.onboarded), AsyncStorage.getItem(K.book), + AsyncStorage.getItem(K.profile), ]); + try { + if (pr) { + const parsed = JSON.parse(pr) as Profile; + if (parsed && typeof parsed.name === 'string' && typeof parsed.email === 'string') { + setProfile(parsed); + } + } + } catch { + // A corrupted profile is cosmetic; the key and the vault are what matter. + } if (v && SUI_ID.test(v)) { setVaultId(v); } else if (v) { @@ -90,6 +112,11 @@ export function StoreProvider({ children }: { children: ReactNode }) { void AsyncStorage.removeItem(K.vault); }, []); + const saveProfile = useCallback((p: Profile) => { + setProfile(p); + void AsyncStorage.setItem(K.profile, JSON.stringify(p)); + }, []); + const finishOnboarding = useCallback(() => { setOnboarded(true); void AsyncStorage.setItem(K.onboarded, '1'); @@ -121,6 +148,8 @@ export function StoreProvider({ children }: { children: ReactNode }) { vaultId, onboarded, book, + profile, + saveProfile, openVault, closeVault, finishOnboarding, @@ -128,7 +157,7 @@ export function StoreProvider({ children }: { children: ReactNode }) { unlabel, refreshSigner, }), - [ready, address, vaultId, onboarded, book, openVault, closeVault, finishOnboarding, label, unlabel, refreshSigner], + [ready, address, vaultId, onboarded, book, profile, saveProfile, openVault, closeVault, finishOnboarding, label, unlabel, refreshSigner], ); return {children}; diff --git a/mobile/test/design.test.tsx b/mobile/test/design.test.tsx new file mode 100644 index 0000000..56219a9 --- /dev/null +++ b/mobile/test/design.test.tsx @@ -0,0 +1,176 @@ +import { fireEvent } from '@testing-library/react-native'; +import { Role, Status } from '@skur/sdk'; +import { renderScreen } from './harness'; +import { ME, VAULT, proposal, view } from './fixtures'; + +/** + * The product screens from the design pass: onboarding, dashboard, team, policies, logs, help. + * Same contract as the other suites — what appears is what the chain would honour. + */ +const mockStore = jest.fn(); +const mockView = jest.fn(); +const mockRun = jest.fn(async () => 'digest'); + +jest.mock('../src/state/store', () => ({ useStore: () => mockStore() })); +jest.mock('../src/hooks/useVault', () => ({ + useVaultView: () => mockView(), + useTransferPreview: () => ({ data: undefined, isLoading: false, error: null }), +})); +jest.mock('../src/hooks/useTx', () => ({ + useTx: () => ({ run: mockRun, state: { phase: 'idle' }, reset: jest.fn(), busy: false }), +})); + +import { Launch } from '../src/screens/onboarding/Launch'; +import { Tour } from '../src/screens/onboarding/Tour'; +import { Start } from '../src/screens/onboarding/Start'; +import { AddMembers } from '../src/screens/onboarding/AddMembers'; +import { ActivityLog } from '../src/screens/ActivityLog'; +import { Dashboard } from '../src/screens/Dashboard'; +import { Help } from '../src/screens/Help'; +import { Policies } from '../src/screens/Policies'; +import { Roles } from '../src/screens/Roles'; +import { Team } from '../src/screens/Team'; + +function seed(roles: number, over = {}) { + mockStore.mockReturnValue({ + vaultId: VAULT, + address: ME, + book: [], + ready: true, + profile: { name: 'Olajumoke Emmanuel', email: 'tayo@company.com' }, + }); + mockView.mockReturnValue({ + data: view(roles, over), + isLoading: false, + error: null, + refetch: jest.fn(), + isRefetching: false, + }); +} + +afterEach(() => jest.clearAllMocks()); + +describe('the front door', () => { + it('names the product and where it runs', async () => { + seed(Role.OWNER); + const r = await renderScreen(); + expect(r.queryByText('Skur')).not.toBeNull(); + expect(r.queryByText('Secure. Shared. On Sui.')).not.toBeNull(); + }); + + it('walks the tour and only then continues', async () => { + const done = jest.fn(); + const r = await renderScreen(); + expect(r.queryByText('Multi-Signature Security')).not.toBeNull(); + expect(r.queryByText('Transaction Simulation')).not.toBeNull(); + await fireEvent.press(r.getByTestId('tour-next')); + expect(done).not.toHaveBeenCalled(); + await fireEvent.press(r.getByTestId('tour-next')); + await fireEvent.press(r.getByTestId('tour-next')); + expect(done).toHaveBeenCalledTimes(1); + }); + + it('offers create and join as different paths', async () => { + const create = jest.fn(); + const join = jest.fn(); + const r = await renderScreen(); + await fireEvent.press(r.getByTestId('create-org')); + await fireEvent.press(r.getByTestId('join-org')); + expect(create).toHaveBeenCalled(); + expect(join).toHaveBeenCalled(); + }); +}); + +describe('building the roster', () => { + it('warns when no guardian is on it', async () => { + seed(Role.OWNER); + const r = await renderScreen(); + expect(r.queryByText(/No guardian yet/)).not.toBeNull(); + }); + + it('lists you first, as the owner', async () => { + seed(Role.OWNER); + const r = await renderScreen(); + expect(r.queryByText(/Olajumoke Emmanuel \(You\)/)).not.toBeNull(); + expect(r.queryByText('Owner')).not.toBeNull(); + }); +}); + +describe('the dashboard', () => { + it('counts what is pending and who is on the vault', async () => { + seed(Role.APPROVER); + const r = await renderScreen( + , + ); + expect(r.queryByText('Pending approvals')).not.toBeNull(); + expect(r.queryByText('Active members')).not.toBeNull(); + expect(r.queryByText('Total treasury value')).not.toBeNull(); + }); + + it('never shows a fiat figure it cannot know', async () => { + seed(Role.APPROVER); + const r = await renderScreen( + , + ); + expect(r.queryAllByText(/\$/).length).toBe(0); + }); +}); + +describe('the team', () => { + it('offers Invite Member to an owner', async () => { + seed(Role.OWNER); + const r = await renderScreen(); + expect(r.queryByTestId('invite-member')).not.toBeNull(); + }); + + it('does not offer it to a signer, and says why', async () => { + seed(Role.APPROVER); + const r = await renderScreen(); + expect(r.queryByTestId('invite-member')).toBeNull(); + expect(r.queryByText(/takes an owner/)).not.toBeNull(); + }); + + it('marks the guardian as a separate plane in the role guide', async () => { + const r = await renderScreen(); + expect(r.queryByText('Guardian')).not.toBeNull(); + expect(r.queryByText(/refuses to combine/)).not.toBeNull(); + expect(r.queryByText('Viewer')).not.toBeNull(); + }); +}); + +describe('spending policies', () => { + it('shows the bands with the vault’s own numbers', async () => { + seed(Role.OWNER); + const r = await renderScreen(); + // Fixture policy: 1 / 2 / 3 approvals, unknown-recipient timelock. + expect(r.queryByText(/1 approval required, no wait/)).not.toBeNull(); + expect(r.queryByText('Unknown recipients')).not.toBeNull(); + }); + + it('offers editing only to an owner', async () => { + seed(Role.APPROVER); + const r = await renderScreen(); + expect(r.queryByTestId('edit-policies')).toBeNull(); + }); +}); + +describe('activity logs', () => { + it('derives entries from what actually happened', async () => { + seed(Role.APPROVER, { + proposals: [proposal({ approvals: [ME], status: Status.EXECUTED })], + }); + const r = await renderScreen(); + expect(r.queryByText(/Payment opened/)).not.toBeNull(); + expect(r.queryByText(/Approved by/)).not.toBeNull(); + expect(r.queryByText(/Payment executed/)).not.toBeNull(); + }); +}); + +describe('help', () => { + it('answers the lost-phone question without hiding the loss', async () => { + const r = await renderScreen(); + expect(r.queryByText('What happens if I lose my phone?')).not.toBeNull(); + expect(r.queryByText(/The key is gone with it/)).not.toBeNull(); + expect(r.queryByText('Chat with Support')).not.toBeNull(); + }); +}); diff --git a/mobile/test/roles.test.tsx b/mobile/test/roles.test.tsx index 90f6d25..5a32f17 100644 --- a/mobile/test/roles.test.tsx +++ b/mobile/test/roles.test.tsx @@ -30,7 +30,9 @@ async function show(roles: number, over = {}) { mockStore.mockReturnValue({ vaultId: VAULT, address: ME, book: [], ready: true }); mockView.mockReturnValue({ data: view(roles, over), isLoading: false, error: null, refetch: jest.fn() }); const r = await renderScreen(); - return Object.assign((label: string | RegExp) => r.queryByText(label) !== null, { + // queryAllByText: a fact may legitimately appear twice — once in the review-before-signing + // card and once in the what-it-needs card. The assertion is "the screen says it", not "once". + return Object.assign((label: string | RegExp) => r.queryAllByText(label).length > 0, { action: (id: string) => r.queryByTestId(`action-${id}`) !== null, enabled: (id: string) => { const node = r.queryByTestId(`action-${id}`); From df9617b448d5118a4f5c53bf6a9e42844a8681d3 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Wed, 7 Oct 2026 12:41:04 +0100 Subject: [PATCH 38/44] feat: the real Skur mark everywhere, and a design-fidelity pass on the mobile screens Brand: - The actual mark - two interlocked strokes, #FFD000 - extracted from the brand file with clean alpha and applied everywhere a logo appears: mobile app icon, Android adaptive + monochrome/notification icons, splash (yellow on black, as the brand presents itself), the in-app Logo component, and the web: both shells nav marks, public/mark.png, and Next icon.png/apple-icon.png so the favicon is the mark too. Design fidelity, from a second pass over the reference screens: - Sparse screens no longer hug the status bar: Screen gained a centered mode, and the launch and welcome screens sit in the middle of the viewport like a designed thing. - Treasury signature donut is real now (react-native-svg): segments by share, the total in the hole, legend beneath - no fiat figures invented. - Send / Request is the reference segmented pair of buttons, not an underline tab. - Spending Policies: each band is its own card with an icon chip, as drawn. - Security Center: shield hero up top, the checklist, and a posture meter card at the bottom in place of a made-up score. - Settings rows carry their leading icons; Create Organisation description is a proper textarea. Native rebuilds for the new assets and the svg module on both platforms; verified live on the Android emulator (fresh onboarding to a funded dashboard) and on the iOS simulator (same dashboard against the same chain). 59 tests, typecheck, both bundles, verify.sh 11/11. --- app/public/mark.png | Bin 0 -> 33815 bytes app/src/app/apple-icon.png | Bin 0 -> 9264 bytes app/src/app/globals.css | 6 +- app/src/app/icon.png | Bin 0 -> 54310 bytes app/src/components/Shell.tsx | 3 +- app/src/marketing/Shell.tsx | 3 +- app/src/marketing/styles.css | 4 +- mobile/app.json | 11 +- mobile/assets/android-icon-background.png | Bin 5236 -> 22117 bytes mobile/assets/android-icon-foreground.png | Bin 19781 -> 102485 bytes mobile/assets/android-icon-monochrome.png | Bin 19781 -> 77242 bytes mobile/assets/favicon.png | Bin 28809 -> 10721 bytes mobile/assets/icon.png | Bin 28809 -> 163432 bytes mobile/assets/mark.png | Bin 0 -> 108850 bytes mobile/assets/splash-icon.png | Bin 19781 -> 76092 bytes mobile/package-lock.json | 159 +++++++++++++++++++- mobile/package.json | 3 +- mobile/src/components/kit.tsx | 110 ++++++++++++++ mobile/src/components/ui.tsx | 13 +- mobile/src/screens/Home.tsx | 15 +- mobile/src/screens/Policies.tsx | 44 ++++-- mobile/src/screens/Security.tsx | 24 ++- mobile/src/screens/Send.tsx | 6 +- mobile/src/screens/Settings.tsx | 21 ++- mobile/src/screens/onboarding/CreateOrg.tsx | 3 + mobile/src/screens/onboarding/Launch.tsx | 5 +- mobile/src/screens/onboarding/Start.tsx | 5 +- 27 files changed, 381 insertions(+), 54 deletions(-) create mode 100644 app/public/mark.png create mode 100644 app/src/app/apple-icon.png create mode 100644 app/src/app/icon.png create mode 100644 mobile/assets/mark.png diff --git a/app/public/mark.png b/app/public/mark.png new file mode 100644 index 0000000000000000000000000000000000000000..3bc93028922ff4b9351e771a172558a3e5f0536b GIT binary patch literal 33815 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 literal 0 HcmV?d00001 diff --git a/app/src/app/apple-icon.png b/app/src/app/apple-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2cd06014b8e9e275a72f69ad667dc26fc25c8d GIT binary patch literal 9264 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

      - S + {/* eslint-disable-next-line @next/next/no-img-element */} + Skur {NETWORK} diff --git a/app/src/marketing/Shell.tsx b/app/src/marketing/Shell.tsx index 89ded91..2a18830 100644 --- a/app/src/marketing/Shell.tsx +++ b/app/src/marketing/Shell.tsx @@ -26,7 +26,8 @@ export function MarketingShell({
      - S + {/* eslint-disable-next-line @next/next/no-img-element */} + Skur
      @@ -481,8 +484,8 @@ export default function Landing() { What a guardian can do -
      - +
      +
      diff --git a/app/src/marketing/Mockup.tsx b/app/src/marketing/Mockup.tsx index f4ac71a..4b0646e 100644 --- a/app/src/marketing/Mockup.tsx +++ b/app/src/marketing/Mockup.tsx @@ -5,7 +5,8 @@ export function AppMockup({ variant = "overview" }: { variant?: "overview" | "qu return (
      -
      S  Home
      + {/* eslint-disable-next-line @next/next/no-img-element */} +
      Home
      + New transaction
      {["Overview", "Queue", "Pay", "Policy", "People", "Security"].map((n, i) => (
      {n}
      @@ -61,3 +62,61 @@ export function AppMockup({ variant = "overview" }: { variant?: "overview" | "qu
      ); } + + +/** + * The phone, drawn in CSS: the redesigned mobile app as the landing page's second piece of + * artwork. "home" is the dashboard with the donut; "security" is the guardian's brake. + */ +export function PhoneMockup({ variant = "home" }: { variant?: "home" | "security" }) { + return ( +
      +
      +
      9:41●●
      + {variant === "home" ? ( + <> +
      + {/* eslint-disable-next-line @next/next/no-img-element */} + + Lenzypay Treasury +
      +
      +
      TOTAL TREASURY VALUE Normal
      +
      800SUI total
      +
      +
      +
      0Pending approvals
      +
      3Active members
      +
      +
      +
      RECENT ACTIVITY
      +
      5 SUI · Contractor invoiceExecuted
      +
      Policy change1 of 2
      +
      + + ) : ( + <> +
      Security Center
      +
      +
      🛡
      + Your assets are protected +
      +
      6 of 7 controls hold
      +
      +
      ⚠ Raise to Elevated
      +
      🔒 Freeze the vault
      +
      +
      Veto a critical payment✓
      +
      Never touches a coin✓
      +
      + + )} +
      + {["Home", "Treasury", "Proposals", "Team", "More"].map((t, i) => ( + {t} + ))} +
      +
      +
      + ); +} diff --git a/app/src/marketing/styles.css b/app/src/marketing/styles.css index 6c173ef..d486d47 100644 --- a/app/src/marketing/styles.css +++ b/app/src/marketing/styles.css @@ -844,3 +844,40 @@ input:read-only { color: var(--text-2); } .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } .docs-body h1 { font-size: 34px; line-height: 38px; } } + +/* ================================================================== the phone: the mobile app as artwork */ +.mock-phone { width: 272px; border-radius: 42px; background: #0b0d0f; padding: 10px; border: 1px solid #343a40; box-shadow: 0 30px 60px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.3); } +.mock-phone .mp-screen { border-radius: 33px; overflow: hidden; background: #212529; color: #f8f9fa; font-size: 11px; padding: 10px 12px 0; display: flex; flex-direction: column; gap: 10px; min-height: 480px; } +.mp-status { display: flex; align-items: center; justify-content: space-between; color: #adb5bd; font-weight: 700; font-size: 10px; } +.mp-island { width: 64px; height: 16px; border-radius: 10px; background: #0b0d0f; } +.mp-head { display: flex; align-items: center; gap: 8px; font-size: 15px; letter-spacing: -0.01em; padding-top: 2px; } +.mp-card { background: #2b3035; border-radius: 14px; padding: 12px; display: flex; flex-direction: column; gap: 8px; } +.mp-label { color: #6c757d; font-size: 9px; letter-spacing: 1px; font-weight: 700; display: flex; justify-content: space-between; align-items: center; } +.mp-ok { color: #75b798; font-weight: 700; letter-spacing: 0; } +.mp-rv { color: #ffcd39; font-weight: 700; } +.mp-donut { width: 128px; height: 128px; border-radius: 50%; margin: 6px auto; background: conic-gradient(#ffd000 0 100%); display: grid; place-items: center; } +.mp-donut > div { width: 92px; height: 92px; border-radius: 50%; background: #2b3035; display: flex; flex-direction: column; align-items: center; justify-content: center; } +.mp-donut b { font-size: 22px; letter-spacing: -0.02em; } +.mp-donut span { color: #adb5bd; font-size: 10px; } +.mp-tiles { display: flex; gap: 8px; } +.mp-tile { flex: 1; background: #2b3035; border-radius: 12px; padding: 10px; display: flex; flex-direction: column; gap: 2px; } +.mp-tile b { font-size: 18px; } +.mp-tile span { color: #adb5bd; font-size: 10px; } +.mp-list .mp-row { display: flex; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid #343a40; } +.mp-list .mp-row:first-of-type { border-top: 0; } +.mp-shield { font-size: 30px; } +.mp-meter { height: 6px; border-radius: 3px; background: #343a40; overflow: hidden; margin-top: 4px; } +.mp-meter i { display: block; height: 6px; border-radius: 3px; background: #ffd000; } +.mp-btn { border-radius: 10px; padding: 10px; text-align: center; font-weight: 800; } +.mp-btn-soft { background: #343a40; color: #ffcd39; } +.mp-btn-danger { background: #4a1c22; color: #ea868f; } +.mp-tabs { margin-top: auto; display: flex; justify-content: space-between; gap: 2px; border-top: 1px solid #343a40; padding: 9px 2px 12px; color: #6c757d; font-size: 8.5px; font-weight: 700; } +.mp-tabs .on { color: #ffd000; } + +/* in the hero, the phone leans on the desktop mock */ +.mockwrap { position: relative; } +.float-phone { position: absolute; right: -18px; bottom: -34px; transform: rotate(4deg); z-index: 3; } +@media (max-width: 1100px) { .float-phone { display: none; } } +/* in the audience cards, it stands alone */ +.art-phone { display: flex; justify-content: center; padding: 18px 0 6px; } +.art-phone .mock-phone { transform: rotate(-2deg); } From 75f2eddd070eabccf800b6ec39e01eec65661703 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:16:00 +0100 Subject: [PATCH 41/44] fix(web): scope the marketing stylesheet, and finish the brand sweep The two design languages were fighting after all: Next bundles both route groups' stylesheets, so marketing's generic selectors (.shell { display: flex }, .pill, .btn) leaked into /app and shattered its entry page - tabs wrapping vertically, the no-package notice breaking one word per line, the hero laid sideways. Every marketing rule is now scoped under the .land root the marketing shell renders (theme attributes stay on , so [data-theme] guards wrap .land rather than replacing it), and the dapp's own sheet is the only one that reaches /app. Also: the risk-engine diagram carries the mark instead of a letter S; the hero becomes a proper triptych (phone left, desktop centre, risk ticker right - nothing overlaps); the phone's tab bar gets five equal cells so no label clips. Typecheck clean; 23 pages build. --- app/src/app/(marketing)/page.tsx | 3 +- app/src/marketing/styles.css | 1422 +++++++++++++++--------------- 2 files changed, 713 insertions(+), 712 deletions(-) diff --git a/app/src/app/(marketing)/page.tsx b/app/src/app/(marketing)/page.tsx index f638db7..2bfe5fa 100644 --- a/app/src/app/(marketing)/page.tsx +++ b/app/src/app/(marketing)/page.tsx @@ -247,7 +247,8 @@ export default function Landing() { animation: 'float 4s ease-in-out infinite', }} > - S + {/* eslint-disable-next-line @next/next/no-img-element */} +
      diff --git a/app/src/marketing/styles.css b/app/src/marketing/styles.css index d486d47..77fce1d 100644 --- a/app/src/marketing/styles.css +++ b/app/src/marketing/styles.css @@ -46,7 +46,7 @@ --shadow-1: 0 1px 2px rgba(33, 37, 41, 0.06), 0 0 0 1px rgba(33, 37, 41, 0.04); --shadow-2: 0 12px 32px rgba(33, 37, 41, 0.12); } -[data-theme="dark"] { +[data-theme="dark"] .land { --text: #f8f9fa; --text-2: #adb5bd; --text-3: #6c757d; @@ -85,30 +85,30 @@ --shadow-2: 0 12px 32px rgba(0, 0, 0, 0.4); } -* { box-sizing: border-box; } -html, body { margin: 0; } -html { scroll-behavior: smooth; } -body { font-family: "DM Sans", system-ui, sans-serif; font-size: 14px; line-height: 20px; color: var(--text); background: var(--canvas); -webkit-font-smoothing: antialiased; transition: background 0.25s var(--ease), color 0.25s var(--ease); } -h1, h2, h3, h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; } -h1 { font-size: 32px; line-height: 36px; } -h2 { font-size: 27px; line-height: 34px; } -h3 { font-size: 20px; line-height: 26px; } -h4 { font-size: 16px; line-height: 22px; } -p { margin: 0; } -a { color: inherit; text-decoration: none; } -code, .mono { font-family: "DM Mono", ui-monospace, Menlo, monospace; font-size: 12.5px; } -button, input, select, textarea { font-family: inherit; } -h1, h2, h3, .display, .balance-card .amount, .scorecard .v, .stats .v { font-family: "Space Grotesk", "DM Sans", system-ui, sans-serif; } -.muted { color: var(--text-2); } -.faint { color: var(--text-3); } -.small { font-size: 12px; line-height: 16px; } -.caption { font-size: 12px; line-height: 16px; color: var(--text-2); } -.overline { font-size: 11px; line-height: 14px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--text-2); } -.strong { font-weight: 700; } -.num { font-variant-numeric: tabular-nums; } -.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.accent { color: var(--text); background: var(--accent); padding: 0 4px; } -[data-theme="dark"] .accent { color: var(--accent); background: none; padding: 0; } +.land, .land * { box-sizing: border-box; } +.land, .land { margin: 0; } +.land { scroll-behavior: smooth; } +.land { font-family: "DM Sans", system-ui, sans-serif; font-size: 14px; line-height: 20px; color: var(--text); background: var(--canvas); -webkit-font-smoothing: antialiased; transition: background 0.25s var(--ease), color 0.25s var(--ease); } +.land h1, .land h2, .land h3, .land h4 { margin: 0; font-weight: 700; letter-spacing: -0.01em; } +.land h1 { font-size: 32px; line-height: 36px; } +.land h2 { font-size: 27px; line-height: 34px; } +.land h3 { font-size: 20px; line-height: 26px; } +.land h4 { font-size: 16px; line-height: 22px; } +.land p { margin: 0; } +.land a { color: inherit; text-decoration: none; } +.land code, .land .mono { font-family: "DM Mono", ui-monospace, Menlo, monospace; font-size: 12.5px; } +.land button, .land input, .land select, .land textarea { font-family: inherit; } +.land h1, .land h2, .land h3, .land .display, .land .balance-card .amount, .land .scorecard .v, .land .stats .v { font-family: "Space Grotesk", "DM Sans", system-ui, sans-serif; } +.land .muted { color: var(--text-2); } +.land .faint { color: var(--text-3); } +.land .small { font-size: 12px; line-height: 16px; } +.land .caption { font-size: 12px; line-height: 16px; color: var(--text-2); } +.land .overline { font-size: 11px; line-height: 14px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--text-2); } +.land .strong { font-weight: 700; } +.land .num { font-variant-numeric: tabular-nums; } +.land .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.land .accent { color: var(--text); background: var(--accent); padding: 0 4px; } +[data-theme="dark"] .land .accent { color: var(--accent); background: none; padding: 0; } /* ================================================================== motion */ @keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } } @@ -122,432 +122,432 @@ h1, h2, h3, .display, .balance-card .amount, .scorecard .v, .stats .v { font-fam @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } @keyframes grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } -.reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); } -.reveal.in { opacity: 1; transform: none; } -.reveal-stagger > * { opacity: 0; transform: translateY(16px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); } -.reveal-stagger.in > * { opacity: 1; transform: none; } -.reveal-stagger.in > *:nth-child(1) { transition-delay: 0.05s; } -.reveal-stagger.in > *:nth-child(2) { transition-delay: 0.12s; } -.reveal-stagger.in > *:nth-child(3) { transition-delay: 0.19s; } -.reveal-stagger.in > *:nth-child(4) { transition-delay: 0.26s; } -.reveal-stagger.in > *:nth-child(5) { transition-delay: 0.33s; } -.reveal-stagger.in > *:nth-child(6) { transition-delay: 0.40s; } -.reveal-stagger.in > *:nth-child(n+7) { transition-delay: 0.47s; } -.enter { animation: rise 0.5s var(--ease) both; } -.enter-2 { animation: rise 0.5s var(--ease) 0.08s both; } -.enter-3 { animation: rise 0.5s var(--ease) 0.16s both; } -.enter-4 { animation: rise 0.5s var(--ease) 0.24s both; } -.page-enter { animation: fade 0.35s var(--ease) both; } -.page-enter > * { animation: rise 0.45s var(--ease) both; } -.page-enter > *:nth-child(2) { animation-delay: 0.06s; } -.page-enter > *:nth-child(3) { animation-delay: 0.12s; } -.page-enter > *:nth-child(4) { animation-delay: 0.18s; } -.lift { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); } -.lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); } -.skeleton { position: relative; overflow: hidden; background: var(--panel-2); border-radius: 6px; color: transparent !important; } -.skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent); background-size: 600px 100%; animation: shimmer 1.4s linear infinite; } -[data-theme="dark"] .skeleton::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent); background-size: 600px 100%; } -.spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--border-2); border-top-color: var(--brand); animation: spin 0.8s linear infinite; display: inline-block; vertical-align: middle; } +.land .reveal { opacity: 0; transform: translateY(24px); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); } +.land .reveal.in { opacity: 1; transform: none; } +.land .reveal-stagger > * { opacity: 0; transform: translateY(16px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); } +.land .reveal-stagger.in > * { opacity: 1; transform: none; } +.land .reveal-stagger.in > *:nth-child(1) { transition-delay: 0.05s; } +.land .reveal-stagger.in > *:nth-child(2) { transition-delay: 0.12s; } +.land .reveal-stagger.in > *:nth-child(3) { transition-delay: 0.19s; } +.land .reveal-stagger.in > *:nth-child(4) { transition-delay: 0.26s; } +.land .reveal-stagger.in > *:nth-child(5) { transition-delay: 0.33s; } +.land .reveal-stagger.in > *:nth-child(6) { transition-delay: 0.40s; } +.land .reveal-stagger.in > *:nth-child(n+7) { transition-delay: 0.47s; } +.land .enter { animation: rise 0.5s var(--ease) both; } +.land .enter-2 { animation: rise 0.5s var(--ease) 0.08s both; } +.land .enter-3 { animation: rise 0.5s var(--ease) 0.16s both; } +.land .enter-4 { animation: rise 0.5s var(--ease) 0.24s both; } +.land .page-enter { animation: fade 0.35s var(--ease) both; } +.land .page-enter > * { animation: rise 0.45s var(--ease) both; } +.land .page-enter > *:nth-child(2) { animation-delay: 0.06s; } +.land .page-enter > *:nth-child(3) { animation-delay: 0.12s; } +.land .page-enter > *:nth-child(4) { animation-delay: 0.18s; } +.land .lift { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); } +.land .lift:hover { transform: translateY(-3px); box-shadow: var(--shadow-2); } +.land .skeleton { position: relative; overflow: hidden; background: var(--panel-2); border-radius: 6px; color: transparent !important; } +.land .skeleton::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent); background-size: 600px 100%; animation: shimmer 1.4s linear infinite; } +[data-theme="dark"] .land .skeleton::after { background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent); background-size: 600px 100%; } +.land .spinner { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--border-2); border-top-color: var(--brand); animation: spin 0.8s linear infinite; display: inline-block; vertical-align: middle; } @media (prefers-reduced-motion: reduce) { - *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } - .reveal, .reveal-stagger > * { opacity: 1; transform: none; } + .land, .land *, .land *::before, .land *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; scroll-behavior: auto !important; } + .land .reveal, .land .reveal-stagger > * { opacity: 1; transform: none; } } /* ================================================================== buttons */ -.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 20px; border-radius: var(--radius-sm); border: 1px solid transparent; font-size: 14px; font-weight: 700; cursor: pointer; white-space: nowrap; transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease), box-shadow 0.15s var(--ease); } -.btn:active:not(:disabled) { transform: scale(0.98); } -.btn:disabled { opacity: 0.4; cursor: not-allowed; } -.btn-primary { background: var(--brand); color: var(--brand-contrast); } -.btn-primary:hover:not(:disabled) { background: var(--brand-hover); box-shadow: var(--shadow-2); } -.btn-secondary { background: transparent; color: var(--text); border-color: var(--border-2); } -.btn-secondary:hover:not(:disabled) { background: var(--panel-2); } -.btn-dark { background: var(--panel-2); color: var(--text); } -.btn-dark:hover:not(:disabled) { background: var(--brand-bg-2); } -.btn-danger { background: transparent; color: var(--error); border-color: var(--error); } -.btn-danger:hover:not(:disabled) { background: var(--error-bg); } -.btn-ghost { background: transparent; color: var(--text); } -.btn-ghost:hover:not(:disabled) { background: var(--panel-2); } -.btn-accent { background: var(--accent); color: var(--accent-contrast); } -.btn-accent:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 10px 28px rgba(255,208,0,0.35); } -.btn-white { background: #fff; color: #212529; border-color: #dee2e6; } -.btn-white:hover:not(:disabled) { background: #f1f3f5; } -.btn-black { background: #212529; color: #fff; } -.btn-black:hover:not(:disabled) { background: #343a40; } -.btn-sm { height: 32px; padding: 0 12px; font-size: 13px; } -.btn-lg { height: 52px; padding: 0 28px; font-size: 16px; } -.btn-block { width: 100%; } -.icon-btn { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 999px; border: 0; background: var(--panel-2); color: var(--text-2); cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.15s; } -.icon-btn:hover { color: var(--text); background: var(--brand-bg-2); } -.icon-btn:active { transform: scale(0.94); } -.icon-btn.small { width: 28px; height: 28px; background: transparent; } -.icon-btn.small:hover { background: var(--panel-2); } +.land .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 40px; padding: 0 20px; border-radius: var(--radius-sm); border: 1px solid transparent; font-size: 14px; font-weight: 700; cursor: pointer; white-space: nowrap; transition: background 0.15s var(--ease), border-color 0.15s var(--ease), transform 0.15s var(--ease), box-shadow 0.15s var(--ease); } +.land .btn:active:not(:disabled) { transform: scale(0.98); } +.land .btn:disabled { opacity: 0.4; cursor: not-allowed; } +.land .btn-primary { background: var(--brand); color: var(--brand-contrast); } +.land .btn-primary:hover:not(:disabled) { background: var(--brand-hover); box-shadow: var(--shadow-2); } +.land .btn-secondary { background: transparent; color: var(--text); border-color: var(--border-2); } +.land .btn-secondary:hover:not(:disabled) { background: var(--panel-2); } +.land .btn-dark { background: var(--panel-2); color: var(--text); } +.land .btn-dark:hover:not(:disabled) { background: var(--brand-bg-2); } +.land .btn-danger { background: transparent; color: var(--error); border-color: var(--error); } +.land .btn-danger:hover:not(:disabled) { background: var(--error-bg); } +.land .btn-ghost { background: transparent; color: var(--text); } +.land .btn-ghost:hover:not(:disabled) { background: var(--panel-2); } +.land .btn-accent { background: var(--accent); color: var(--accent-contrast); } +.land .btn-accent:hover:not(:disabled) { background: var(--accent-hover); box-shadow: 0 10px 28px rgba(255,208,0,0.35); } +.land .btn-white { background: #fff; color: #212529; border-color: #dee2e6; } +.land .btn-white:hover:not(:disabled) { background: #f1f3f5; } +.land .btn-black { background: #212529; color: #fff; } +.land .btn-black:hover:not(:disabled) { background: #343a40; } +.land .btn-sm { height: 32px; padding: 0 12px; font-size: 13px; } +.land .btn-lg { height: 52px; padding: 0 28px; font-size: 16px; } +.land .btn-block { width: 100%; } +.land .icon-btn { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 999px; border: 0; background: var(--panel-2); color: var(--text-2); cursor: pointer; transition: background 0.15s, color 0.15s, transform 0.15s; } +.land .icon-btn:hover { color: var(--text); background: var(--brand-bg-2); } +.land .icon-btn:active { transform: scale(0.94); } +.land .icon-btn.small { width: 28px; height: 28px; background: transparent; } +.land .icon-btn.small:hover { background: var(--panel-2); } /* ================================================================== app shell */ -.shell { display: flex; min-height: 100vh; } -.shell.collapsed { --sidebar: 68px; } -.shell.collapsed .sidebar { padding: 12px 8px 16px; } -.shell.collapsed .lbl, .shell.collapsed .nav-group, .shell.collapsed .promo, .shell.collapsed .nav .count, .shell.collapsed .tag-new { display: none; } -.shell.collapsed .home-pill { padding: 0 8px; } -.shell.collapsed .sidebar-top { flex-direction: column; gap: 6px; } -.shell.collapsed .nav button { justify-content: center; padding: 0; } -.shell.collapsed .nav button.active::before { left: -6px; } -.shell.collapsed .newtx .btn { font-size: 0; gap: 0; padding: 0; } -.shell.collapsed .newtx .btn svg { width: 16px; height: 16px; } -.sidebar { transition: width 0.25s var(--ease), padding 0.25s var(--ease); } -.sidebar { width: var(--sidebar); flex: none; background: var(--panel); border-right: 1px solid var(--border); padding: 12px 10px 16px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; overflow-y: auto; } -.home-pill { display: inline-flex; align-items: center; gap: 10px; height: 40px; padding: 0 14px 0 8px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; background: var(--accent-bg); color: var(--text); font-weight: 700; cursor: pointer; border: 0; align-self: flex-start; transition: background 0.15s; } -.home-pill:hover { background: var(--accent-bg-2); } -.home-pill .mark { width: 24px; height: 24px; border-radius: 4px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 13px; } -.sidebar-top { display: flex; align-items: center; justify-content: space-between; padding: 4px 4px 8px; } -.newtx { margin: 4px 0 16px; } -.newtx .btn { width: 100%; justify-content: center; border-color: var(--border-2); background: transparent; color: var(--text-2); font-weight: 500; } -.newtx .btn:not(:disabled) { color: var(--text); border-color: var(--accent); } -.newtx .btn:hover:not(:disabled) { background: var(--accent); color: var(--accent-contrast); } -.nav { display: flex; flex-direction: column; gap: 2px; position: relative; } -.nav button { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; height: 38px; padding: 0 12px; border-radius: var(--radius-sm); border: 0; background: transparent; color: var(--text); font-size: 14px; font-weight: 500; cursor: pointer; position: relative; transition: background 0.15s, color 0.15s; } -.nav button:hover { background: var(--panel-2); } -.nav button.active { background: var(--accent-bg); font-weight: 700; } -.nav button.active::before { content: ""; position: absolute; left: -10px; top: 8px; bottom: 8px; width: 3px; border-radius: 2px; background: var(--accent); animation: grow 0.3s var(--ease); transform-origin: center; } -.nav button .ico { width: 18px; height: 18px; color: var(--text-2); display: inline-grid; place-items: center; transition: color 0.15s, transform 0.2s var(--ease); } -.nav button:hover .ico { transform: translateX(2px); } -.nav button.active .ico { color: var(--text); } -[data-theme="dark"] .nav button.active .ico { color: var(--accent); } -.nav .count { margin-left: auto; font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; background: var(--review-bg); color: var(--review); } -.nav-group { font-size: 12px; color: var(--text-2); padding: 14px 12px 6px; } -.sidebar-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 2px; } -.promo { border-radius: 10px; padding: 16px; background: linear-gradient(180deg, var(--brand-bg) 0%, var(--panel) 100%); margin: 0 4px 12px; animation: pop 0.4s var(--ease); } -.promo .tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); margin-bottom: 8px; } -.promo h4 { font-size: 14px; margin-bottom: 4px; } -.promo p { font-size: 12px; color: var(--text-2); margin-bottom: 10px; } -.tag-new { display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); font-size: 11px; font-weight: 700; } +.land .shell { display: flex; min-height: 100vh; } +.land .shell.collapsed { --sidebar: 68px; } +.land .shell.collapsed .sidebar { padding: 12px 8px 16px; } +.land .shell.collapsed .lbl, .land .shell.collapsed .nav-group, .land .shell.collapsed .promo, .land .shell.collapsed .nav .count, .land .shell.collapsed .tag-new { display: none; } +.land .shell.collapsed .home-pill { padding: 0 8px; } +.land .shell.collapsed .sidebar-top { flex-direction: column; gap: 6px; } +.land .shell.collapsed .nav button { justify-content: center; padding: 0; } +.land .shell.collapsed .nav button.active::before { left: -6px; } +.land .shell.collapsed .newtx .btn { font-size: 0; gap: 0; padding: 0; } +.land .shell.collapsed .newtx .btn svg { width: 16px; height: 16px; } +.land .sidebar { transition: width 0.25s var(--ease), padding 0.25s var(--ease); } +.land .sidebar { width: var(--sidebar); flex: none; background: var(--panel); border-right: 1px solid var(--border); padding: 12px 10px 16px; display: flex; flex-direction: column; gap: 4px; position: sticky; top: 0; height: 100vh; overflow-y: auto; } +.land .home-pill { display: inline-flex; align-items: center; gap: 10px; height: 40px; padding: 0 14px 0 8px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; background: var(--accent-bg); color: var(--text); font-weight: 700; cursor: pointer; border: 0; align-self: flex-start; transition: background 0.15s; } +.land .home-pill:hover { background: var(--accent-bg-2); } +.land .home-pill .mark { width: 24px; height: 24px; border-radius: 4px; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 13px; } +.land .sidebar-top { display: flex; align-items: center; justify-content: space-between; padding: 4px 4px 8px; } +.land .newtx { margin: 4px 0 16px; } +.land .newtx .btn { width: 100%; justify-content: center; border-color: var(--border-2); background: transparent; color: var(--text-2); font-weight: 500; } +.land .newtx .btn:not(:disabled) { color: var(--text); border-color: var(--accent); } +.land .newtx .btn:hover:not(:disabled) { background: var(--accent); color: var(--accent-contrast); } +.land .nav { display: flex; flex-direction: column; gap: 2px; position: relative; } +.land .nav button { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; height: 38px; padding: 0 12px; border-radius: var(--radius-sm); border: 0; background: transparent; color: var(--text); font-size: 14px; font-weight: 500; cursor: pointer; position: relative; transition: background 0.15s, color 0.15s; } +.land .nav button:hover { background: var(--panel-2); } +.land .nav button.active { background: var(--accent-bg); font-weight: 700; } +.land .nav button.active::before { content: ""; position: absolute; left: -10px; top: 8px; bottom: 8px; width: 3px; border-radius: 2px; background: var(--accent); animation: grow 0.3s var(--ease); transform-origin: center; } +.land .nav button .ico { width: 18px; height: 18px; color: var(--text-2); display: inline-grid; place-items: center; transition: color 0.15s, transform 0.2s var(--ease); } +.land .nav button:hover .ico { transform: translateX(2px); } +.land .nav button.active .ico { color: var(--text); } +[data-theme="dark"] .land .nav button.active .ico { color: var(--accent); } +.land .nav .count { margin-left: auto; font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; background: var(--review-bg); color: var(--review); } +.land .nav-group { font-size: 12px; color: var(--text-2); padding: 14px 12px 6px; } +.land .sidebar-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 2px; } +.land .promo { border-radius: 10px; padding: 16px; background: linear-gradient(180deg, var(--brand-bg) 0%, var(--panel) 100%); margin: 0 4px 12px; animation: pop 0.4s var(--ease); } +.land .promo .tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); margin-bottom: 8px; } +.land .promo h4 { font-size: 14px; margin-bottom: 4px; } +.land .promo p { font-size: 12px; color: var(--text-2); margin-bottom: 10px; } +.land .tag-new { display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px; background: var(--accent); color: var(--accent-contrast); font-size: 11px; font-weight: 700; } -.main { flex: 1; min-width: 0; padding: 20px 24px 48px; } -.main-inner { max-width: 1160px; } -.header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; animation: fade 0.4s var(--ease); } -.acct-pill { display: inline-flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px 0 8px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); cursor: pointer; border: 0; color: var(--text); text-align: left; max-width: 100%; transition: box-shadow 0.2s; } -.acct-pill:hover { box-shadow: var(--shadow-2); } -.acct-pill .name { font-size: 14px; font-weight: 700; } -.acct-pill .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 11.5px; color: var(--text-2); } -.acct-pill .addr b { color: var(--text); font-weight: 600; } -.acct-pill .meta { display: inline-flex; align-items: center; gap: 12px; margin-left: 8px; padding-left: 12px; border-left: 1px solid var(--border); font-size: 14px; } -.acct-pill .meta .chip-s { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 6px; background: var(--panel-2); font-size: 12px; color: var(--text-2); } -.tools-pill { display: inline-flex; align-items: center; gap: 6px; height: 56px; padding: 0 10px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); } -.tools-pill .btn { height: 36px; border-radius: 6px; } -.tools-pill .btn-secondary { border-color: var(--border-2); color: var(--text-2); } -.tools-pill .btn-secondary.on { color: var(--text); } +.land .main { flex: 1; min-width: 0; padding: 20px 24px 48px; } +.land .main-inner { max-width: 1160px; } +.land .header-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 24px; flex-wrap: wrap; animation: fade 0.4s var(--ease); } +.land .acct-pill { display: inline-flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px 0 8px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); cursor: pointer; border: 0; color: var(--text); text-align: left; max-width: 100%; transition: box-shadow 0.2s; } +.land .acct-pill:hover { box-shadow: var(--shadow-2); } +.land .acct-pill .name { font-size: 14px; font-weight: 700; } +.land .acct-pill .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 11.5px; color: var(--text-2); } +.land .acct-pill .addr b { color: var(--text); font-weight: 600; } +.land .acct-pill .meta { display: inline-flex; align-items: center; gap: 12px; margin-left: 8px; padding-left: 12px; border-left: 1px solid var(--border); font-size: 14px; } +.land .acct-pill .meta .chip-s { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: 6px; background: var(--panel-2); font-size: 12px; color: var(--text-2); } +.land .tools-pill { display: inline-flex; align-items: center; gap: 6px; height: 56px; padding: 0 10px; border-radius: 10px; background: var(--panel); box-shadow: var(--shadow-1); } +.land .tools-pill .btn { height: 36px; border-radius: 6px; } +.land .tools-pill .btn-secondary { border-color: var(--border-2); color: var(--text-2); } +.land .tools-pill .btn-secondary.on { color: var(--text); } /* ================================================================== cards, lists, tables */ -.card { background: var(--panel); border-radius: 10px; padding: 24px; margin-bottom: 24px; box-shadow: var(--shadow-1); } -.card.flush { padding: 0; overflow: hidden; } -.card.flush .card-head { padding: 20px 24px 8px; } -.card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } -.card-head h4 { font-size: 16px; } -.card-head .sub { color: var(--text-2); font-size: 14px; margin-top: 4px; } -.card-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } -.link { color: var(--text); font-weight: 500; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; display: inline-flex; align-items: center; gap: 4px; } -.link:hover { text-decoration: underline; } -.link.accent { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } -[data-theme="dark"] .link.accent { color: var(--accent); box-shadow: none; } -.grid { display: grid; gap: 24px; } -.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } -.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } -.overview-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 24px; align-items: start; } -@media (max-width: 1000px) { .overview-grid { grid-template-columns: 1fr; } } +.land .card { background: var(--panel); border-radius: 10px; padding: 24px; margin-bottom: 24px; box-shadow: var(--shadow-1); } +.land .card.flush { padding: 0; overflow: hidden; } +.land .card.flush .card-head { padding: 20px 24px 8px; } +.land .card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; } +.land .card-head h4 { font-size: 16px; } +.land .card-head .sub { color: var(--text-2); font-size: 14px; margin-top: 4px; } +.land .card-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; } +.land .link { color: var(--text); font-weight: 500; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; display: inline-flex; align-items: center; gap: 4px; } +.land .link:hover { text-decoration: underline; } +.land .link.accent { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } +[data-theme="dark"] .land .link.accent { color: var(--accent); box-shadow: none; } +.land .grid { display: grid; gap: 24px; } +.land .grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); } +.land .grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); } +.land .overview-grid { display: grid; grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr); gap: 24px; align-items: start; } +@media (max-width: 1000px) { .land .overview-grid { grid-template-columns: 1fr; } } -.balance-card .label { font-size: 15px; font-weight: 500; margin-bottom: 4px; color: var(--text-2); } -.balance-card .amount { font-size: 42px; line-height: 46px; font-weight: 800; letter-spacing: -0.03em; } -.balance-card .amount .dec { color: var(--text-3); font-weight: 600; } -.balance-card .actions { display: flex; gap: 8px; flex-wrap: wrap; } -.balance-card .actions .btn { background: var(--panel-2); color: var(--text); border: 0; height: 38px; font-weight: 600; } -.balance-card .actions .btn.hi { background: var(--brand); color: var(--brand-contrast); } -.balance-card .actions .btn:hover:not(:disabled) { background: var(--brand-bg-2); } -.balance-card .actions .btn.hi:hover:not(:disabled) { background: var(--brand-hover); } -.balance-row { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; } +.land .balance-card .label { font-size: 15px; font-weight: 500; margin-bottom: 4px; color: var(--text-2); } +.land .balance-card .amount { font-size: 42px; line-height: 46px; font-weight: 800; letter-spacing: -0.03em; } +.land .balance-card .amount .dec { color: var(--text-3); font-weight: 600; } +.land .balance-card .actions { display: flex; gap: 8px; flex-wrap: wrap; } +.land .balance-card .actions .btn { background: var(--panel-2); color: var(--text); border: 0; height: 38px; font-weight: 600; } +.land .balance-card .actions .btn.hi { background: var(--brand); color: var(--brand-contrast); } +.land .balance-card .actions .btn:hover:not(:disabled) { background: var(--brand-bg-2); } +.land .balance-card .actions .btn.hi:hover:not(:disabled) { background: var(--brand-hover); } +.land .balance-row { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; flex-wrap: wrap; } -.banner { border-radius: 10px; padding: 20px 24px; display: flex; gap: 20px; align-items: center; margin-bottom: 24px; background: linear-gradient(90deg, #dee2e6 0%, #e9ecef 60%, #f1f3f5 100%); color: #212529; position: relative; overflow: hidden; } -[data-theme="dark"] .banner { background: linear-gradient(90deg, #343a40 0%, #2b3035 70%); color: #f8f9fa; } -.banner .glyph { width: 52px; height: 52px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; flex: none; animation: pulse-ring 2.4s ease-out infinite; } -.banner h4 { font-size: 18px; margin-bottom: 4px; } -.banner p { color: var(--text-2); margin-bottom: 8px; } -.banner .cta { font-weight: 700; color: var(--text); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; } -.banner .cta svg { transition: transform 0.2s var(--ease); } -.banner .cta:hover svg { transform: translateX(4px); } -.banner.warn { background: linear-gradient(90deg, #ffe5b4 0%, #fff3cd 70%); color: #212529; } -[data-theme="dark"] .banner.warn { background: linear-gradient(90deg, #4d3a05 0%, #2b3035 70%); color: #f8f9fa; } -.banner.warn .glyph { background: var(--warning); color: #212529; } -.banner .close { margin-left: auto; align-self: flex-start; background: none; border: 0; cursor: pointer; color: inherit; opacity: 0.6; } -.banner .close:hover { opacity: 1; } +.land .banner { border-radius: 10px; padding: 20px 24px; display: flex; gap: 20px; align-items: center; margin-bottom: 24px; background: linear-gradient(90deg, #dee2e6 0%, #e9ecef 60%, #f1f3f5 100%); color: #212529; position: relative; overflow: hidden; } +[data-theme="dark"] .land .banner { background: linear-gradient(90deg, #343a40 0%, #2b3035 70%); color: #f8f9fa; } +.land .banner .glyph { width: 52px; height: 52px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; flex: none; animation: pulse-ring 2.4s ease-out infinite; } +.land .banner h4 { font-size: 18px; margin-bottom: 4px; } +.land .banner p { color: var(--text-2); margin-bottom: 8px; } +.land .banner .cta { font-weight: 700; color: var(--text); display: inline-flex; align-items: center; gap: 6px; cursor: pointer; background: none; border: 0; padding: 0; font-size: 14px; } +.land .banner .cta svg { transition: transform 0.2s var(--ease); } +.land .banner .cta:hover svg { transform: translateX(4px); } +.land .banner.warn { background: linear-gradient(90deg, #ffe5b4 0%, #fff3cd 70%); color: #212529; } +[data-theme="dark"] .land .banner.warn { background: linear-gradient(90deg, #4d3a05 0%, #2b3035 70%); color: #f8f9fa; } +.land .banner.warn .glyph { background: var(--warning); color: #212529; } +.land .banner .close { margin-left: auto; align-self: flex-start; background: none; border: 0; cursor: pointer; color: inherit; opacity: 0.6; } +.land .banner .close:hover { opacity: 1; } -.list { list-style: none; margin: 0; padding: 0; } -.list > li { display: flex; align-items: center; gap: 14px; padding: 14px 24px; border-top: 1px solid var(--border); transition: background 0.15s; } -.list > li:hover { background: var(--panel-3); } -.list > li:first-child { border-top: 0; } -.list .grow { flex: 1; min-width: 0; } -.list .title { font-weight: 700; } -.list .sub { font-size: 12px; color: var(--text-2); } -.list .right { text-align: right; } +.land .list { list-style: none; margin: 0; padding: 0; } +.land .list > li { display: flex; align-items: center; gap: 14px; padding: 14px 24px; border-top: 1px solid var(--border); transition: background 0.15s; } +.land .list > li:hover { background: var(--panel-3); } +.land .list > li:first-child { border-top: 0; } +.land .list .grow { flex: 1; min-width: 0; } +.land .list .title { font-weight: 700; } +.land .list .sub { font-size: 12px; color: var(--text-2); } +.land .list .right { text-align: right; } /* Colour and glyph come from lib/tokens.ts, so both interfaces draw an asset the same way. */ -.token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; line-height: 1; } -table { width: 100%; border-collapse: collapse; } -th, td { text-align: left; padding: 14px 24px; border-top: 1px solid var(--border); vertical-align: middle; } -thead th { border-top: 0; color: var(--text-2); font-weight: 500; font-size: 13px; } -tbody tr { transition: background 0.15s; } -tbody tr:hover { background: var(--panel-3); } -td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; } -.card:not(.flush) table th, .card:not(.flush) table td { padding-left: 0; padding-right: 0; } -.explore { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; } -.explore button { border: 1px solid var(--border); border-radius: 10px; background: var(--panel-3); color: var(--text); padding: 20px 16px; text-align: left; font-weight: 700; font-size: 15px; cursor: pointer; display: flex; flex-direction: column; gap: 20px; transition: transform 0.25s var(--ease), border-color 0.25s, box-shadow 0.25s; } -.explore button:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow-2); } -.explore .ico { width: 56px; height: 56px; color: var(--text); transition: transform 0.3s var(--ease); } -[data-theme="dark"] .explore .ico { color: var(--accent); } -.explore button { position: relative; overflow: hidden; } -.explore button::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 0.3s var(--ease); } -.explore button:hover::after { transform: scaleX(1); } -.explore button:hover .ico { transform: scale(1.08) rotate(-4deg); } +.land .token-ico { width: 32px; height: 32px; border-radius: 50%; display: inline-grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; line-height: 1; } +.land table { width: 100%; border-collapse: collapse; } +.land th, .land td { text-align: left; padding: 14px 24px; border-top: 1px solid var(--border); vertical-align: middle; } +.land thead th { border-top: 0; color: var(--text-2); font-weight: 500; font-size: 13px; } +.land tbody tr { transition: background 0.15s; } +.land tbody tr:hover { background: var(--panel-3); } +.land td.num, .land th.num { text-align: right; font-variant-numeric: tabular-nums; } +.land .card:not(.flush) table th, .land .card:not(.flush) table td { padding-left: 0; padding-right: 0; } +.land .explore { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; } +.land .explore button { border: 1px solid var(--border); border-radius: 10px; background: var(--panel-3); color: var(--text); padding: 20px 16px; text-align: left; font-weight: 700; font-size: 15px; cursor: pointer; display: flex; flex-direction: column; gap: 20px; transition: transform 0.25s var(--ease), border-color 0.25s, box-shadow 0.25s; } +.land .explore button:hover { border-color: var(--accent); transform: translateY(-3px); box-shadow: var(--shadow-2); } +.land .explore .ico { width: 56px; height: 56px; color: var(--text); transition: transform 0.3s var(--ease); } +[data-theme="dark"] .land .explore .ico { color: var(--accent); } +.land .explore button { position: relative; overflow: hidden; } +.land .explore button::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 0.3s var(--ease); } +.land .explore button:hover::after { transform: scaleX(1); } +.land .explore button:hover .ico { transform: scale(1.08) rotate(-4deg); } /* ================================================================== pills */ -.pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 6px; font-size: 12px; font-weight: 700; white-space: nowrap; } -.pill-neutral { background: var(--panel-2); color: var(--text-2); } -.pill-ok { background: var(--success-bg); color: var(--success-text); } -.pill-warn { background: var(--warning-bg); color: var(--warning-text); } -.pill-bad { background: var(--error-bg); color: var(--error-text); } -.pill-info { background: var(--info-bg); color: var(--info-text); } -.pill-review { background: var(--review-bg); color: var(--review); } -[data-theme="light"] .pill-review, :root:not([data-theme="dark"]) .pill-review { color: #7a5c00; } -.pill-brand { background: var(--accent); color: var(--accent-contrast); } -.pill svg { width: 12px; height: 12px; } +.land .pill { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 10px; border-radius: 6px; font-size: 12px; font-weight: 700; white-space: nowrap; } +.land .pill-neutral { background: var(--panel-2); color: var(--text-2); } +.land .pill-ok { background: var(--success-bg); color: var(--success-text); } +.land .pill-warn { background: var(--warning-bg); color: var(--warning-text); } +.land .pill-bad { background: var(--error-bg); color: var(--error-text); } +.land .pill-info { background: var(--info-bg); color: var(--info-text); } +.land .pill-review { background: var(--review-bg); color: var(--review); } +[data-theme="light"] .land .pill-review, .land:not([data-theme="dark"]) .pill-review { color: #7a5c00; } +.land .pill-brand { background: var(--accent); color: var(--accent-contrast); } +.land .pill svg { width: 12px; height: 12px; } /* ================================================================== tabs */ -.tabs { display: flex; gap: 8px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; } -.tabs button { background: none; border: 0; padding: 10px 16px; font-size: 14px; font-weight: 700; cursor: pointer; color: var(--text-2); border-bottom: 2px solid transparent; margin-bottom: -1px; display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; transition: color 0.15s, border-color 0.15s; } -.tabs button:hover { color: var(--text); } -.tabs button.active { color: var(--text); border-bottom-color: var(--accent); } -.tabs-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; border-bottom: 1px solid var(--border); margin-bottom: 20px; } -.tabs-row .tabs { margin-bottom: 0; border-bottom: 0; } +.land .tabs { display: flex; gap: 8px; border-bottom: 1px solid var(--border); margin-bottom: 20px; overflow-x: auto; } +.land .tabs button { background: none; border: 0; padding: 10px 16px; font-size: 14px; font-weight: 700; cursor: pointer; color: var(--text-2); border-bottom: 2px solid transparent; margin-bottom: -1px; display: inline-flex; gap: 8px; align-items: center; white-space: nowrap; transition: color 0.15s, border-color 0.15s; } +.land .tabs button:hover { color: var(--text); } +.land .tabs button.active { color: var(--text); border-bottom-color: var(--accent); } +.land .tabs-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; border-bottom: 1px solid var(--border); margin-bottom: 20px; } +.land .tabs-row .tabs { margin-bottom: 0; border-bottom: 0; } /* ================================================================== transactions */ -.date-label { font-size: 12px; font-weight: 500; color: var(--text-2); letter-spacing: 0.06em; text-transform: uppercase; margin: 20px 0 10px; } -.txcard { background: var(--panel); border-radius: 10px; margin-bottom: 8px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) both; } -.txcard .row { display: grid; grid-template-columns: 24px minmax(120px, 1fr) minmax(0, 1.4fr) 110px auto 24px; align-items: center; gap: 16px; padding: 18px 20px; cursor: pointer; border-radius: 10px; transition: background 0.15s; } -.txcard .row:hover { background: var(--panel-3); } -.txcard .kind { font-weight: 600; } -.txcard .amt { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; } -.txcard .when { color: var(--text-2); font-size: 13px; } -.txcard .status { text-align: right; font-weight: 700; } -.status-success { color: var(--success); } -.status-cancel { color: var(--text-2); } -.status-veto { color: var(--error); } -.txcard .detail { padding: 8px 20px 20px 60px; border-top: 1px solid var(--border); display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr); gap: 24px; animation: rise 0.3s var(--ease); } -@media (max-width: 900px) { .txcard .row { grid-template-columns: 24px 1fr auto 24px; } .txcard .hide-sm { display: none; } .txcard .detail { grid-template-columns: 1fr; padding-left: 20px; } } -.chev { transition: transform 0.2s var(--ease); color: var(--text-2); } -.chev.open { transform: rotate(180deg); } -.timeline { list-style: none; margin: 0; padding: 0; } -.timeline li { position: relative; padding: 0 0 16px 24px; } -.timeline li::before { content: ""; position: absolute; left: 4px; top: 5px; width: 10px; height: 10px; border-radius: 50%; background: var(--border-2); transition: background 0.3s; } -.timeline li.done::before { background: var(--accent); } -.timeline li.active::before { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-bg); animation: pulse-ring 2s ease-out infinite; } -.timeline li:not(:last-child)::after { content: ""; position: absolute; left: 8px; top: 16px; bottom: 0; width: 2px; background: var(--border); } -.timeline .t-title { font-weight: 700; } -.timeline .t-sub { font-size: 12px; color: var(--text-2); } -.timeline .signers { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; font-size: 12px; } -.tx-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; } -.empty-illus { padding: 64px 24px; text-align: center; color: var(--text-2); animation: fade 0.5s var(--ease); } -.empty-illus .glyph { width: 96px; height: 96px; border-radius: 50%; background: var(--panel-2); display: grid; place-items: center; margin: 0 auto 16px; color: var(--accent); animation: float 4s ease-in-out infinite; } +.land .date-label { font-size: 12px; font-weight: 500; color: var(--text-2); letter-spacing: 0.06em; text-transform: uppercase; margin: 20px 0 10px; } +.land .txcard { background: var(--panel); border-radius: 10px; margin-bottom: 8px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) both; } +.land .txcard .row { display: grid; grid-template-columns: 24px minmax(120px, 1fr) minmax(0, 1.4fr) 110px auto 24px; align-items: center; gap: 16px; padding: 18px 20px; cursor: pointer; border-radius: 10px; transition: background 0.15s; } +.land .txcard .row:hover { background: var(--panel-3); } +.land .txcard .kind { font-weight: 600; } +.land .txcard .amt { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; } +.land .txcard .when { color: var(--text-2); font-size: 13px; } +.land .txcard .status { text-align: right; font-weight: 700; } +.land .status-success { color: var(--success); } +.land .status-cancel { color: var(--text-2); } +.land .status-veto { color: var(--error); } +.land .txcard .detail { padding: 8px 20px 20px 60px; border-top: 1px solid var(--border); display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr); gap: 24px; animation: rise 0.3s var(--ease); } +@media (max-width: 900px) { .land .txcard .row { grid-template-columns: 24px 1fr auto 24px; } .land .txcard .hide-sm { display: none; } .land .txcard .detail { grid-template-columns: 1fr; padding-left: 20px; } } +.land .chev { transition: transform 0.2s var(--ease); color: var(--text-2); } +.land .chev.open { transform: rotate(180deg); } +.land .timeline { list-style: none; margin: 0; padding: 0; } +.land .timeline li { position: relative; padding: 0 0 16px 24px; } +.land .timeline li::before { content: ""; position: absolute; left: 4px; top: 5px; width: 10px; height: 10px; border-radius: 50%; background: var(--border-2); transition: background 0.3s; } +.land .timeline li.done::before { background: var(--accent); } +.land .timeline li.active::before { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-bg); animation: pulse-ring 2s ease-out infinite; } +.land .timeline li:not(:last-child)::after { content: ""; position: absolute; left: 8px; top: 16px; bottom: 0; width: 2px; background: var(--border); } +.land .timeline .t-title { font-weight: 700; } +.land .timeline .t-sub { font-size: 12px; color: var(--text-2); } +.land .timeline .signers { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; font-size: 12px; } +.land .tx-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 16px; } +.land .empty-illus { padding: 64px 24px; text-align: center; color: var(--text-2); animation: fade 0.5s var(--ease); } +.land .empty-illus .glyph { width: 96px; height: 96px; border-radius: 50%; background: var(--panel-2); display: grid; place-items: center; margin: 0 auto 16px; color: var(--accent); animation: float 4s ease-in-out infinite; } /* ================================================================== sections (settings-style) */ -.section { background: var(--panel); border-radius: 10px; padding: 28px 32px; margin-bottom: 20px; display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 24px; box-shadow: var(--shadow-1); } -.section > h3 { font-size: 20px; } -.section > h3 small { display: block; font-size: 13px; font-weight: 400; color: var(--text-2); margin-top: 6px; line-height: 18px; } -.section .body { min-width: 0; } -.section .body h4 { margin-bottom: 8px; } -.section .body p.desc { color: var(--text-2); margin-bottom: 16px; font-size: 15px; } -@media (max-width: 860px) { .section { grid-template-columns: 1fr; } } -.member-row { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-top: 1px solid var(--border); } -.member-row:first-of-type { border-top: 0; } -.member-row .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 13px; } -.member-row .addr b { font-family: "DM Sans", sans-serif; font-weight: 700; } -.member-row .roles { display: flex; gap: 6px; flex-wrap: wrap; } -.member-row .tools { margin-left: auto; display: flex; gap: 4px; } -.kv { display: grid; grid-template-columns: 1fr; margin: 0; } -.kv div { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px; } -.kv div:first-child { border-top: 0; } -.kv dt { color: var(--text-2); } -.kv dd { margin: 0; text-align: right; font-weight: 500; } -.addr { display: inline-flex; align-items: center; gap: 6px; color: var(--text); } -.addr code { font-size: 12.5px; } -.addr:hover code { text-decoration: underline; } +.land .section { background: var(--panel); border-radius: 10px; padding: 28px 32px; margin-bottom: 20px; display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 24px; box-shadow: var(--shadow-1); } +.land .section > h3 { font-size: 20px; } +.land .section > h3 small { display: block; font-size: 13px; font-weight: 400; color: var(--text-2); margin-top: 6px; line-height: 18px; } +.land .section .body { min-width: 0; } +.land .section .body h4 { margin-bottom: 8px; } +.land .section .body p.desc { color: var(--text-2); margin-bottom: 16px; font-size: 15px; } +@media (max-width: 860px) { .land .section { grid-template-columns: 1fr; } } +.land .member-row { display: flex; align-items: center; gap: 14px; padding: 12px 0; border-top: 1px solid var(--border); } +.land .member-row:first-of-type { border-top: 0; } +.land .member-row .addr { font-family: "DM Mono", ui-monospace, monospace; font-size: 13px; } +.land .member-row .addr b { font-family: "DM Sans", sans-serif; font-weight: 700; } +.land .member-row .roles { display: flex; gap: 6px; flex-wrap: wrap; } +.land .member-row .tools { margin-left: auto; display: flex; gap: 4px; } +.land .kv { display: grid; grid-template-columns: 1fr; margin: 0; } +.land .kv div { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); font-size: 14px; } +.land .kv div:first-child { border-top: 0; } +.land .kv dt { color: var(--text-2); } +.land .kv dd { margin: 0; text-align: right; font-weight: 500; } +.land .addr { display: inline-flex; align-items: center; gap: 6px; color: var(--text); } +.land .addr code { font-size: 12.5px; } +.land .addr:hover code { text-decoration: underline; } /* policy editor controls */ -.pfield { display: grid; grid-template-columns: minmax(0, 1fr) 160px; gap: 16px; align-items: center; padding: 14px 0; border-top: 1px solid var(--border); } -.pfield:first-child { border-top: 0; } -.pfield .lbl { font-weight: 600; } -.pfield .hint { font-size: 12px; color: var(--text-2); margin-top: 2px; } -.pfield input, .pfield select { height: 40px; } -.pfield .unit { display: flex; align-items: center; gap: 8px; } -.pfield .unit span { color: var(--text-2); font-size: 12px; white-space: nowrap; } -.pfield.changed .lbl::after { content: " •"; color: var(--warning); } -.stepper { display: inline-flex; align-items: center; border: 1px solid var(--border-2); border-radius: 8px; overflow: hidden; height: 40px; } -.stepper button { width: 36px; height: 100%; border: 0; background: var(--panel-2); color: var(--text); cursor: pointer; font-size: 16px; } -.stepper button:hover { background: var(--brand-bg-2); } -.stepper input { border: 0; width: 64px; text-align: center; height: 100%; border-radius: 0; } -.mode-hero { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } -.mode-hero > div { border: 1px solid var(--border); border-radius: 10px; padding: 18px; position: relative; transition: border-color 0.25s, transform 0.25s var(--ease); } -.mode-hero > div.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); transform: translateY(-2px); } -.mode-hero .m { font-size: 18px; font-weight: 800; margin-bottom: 4px; } -.mode-hero .d { color: var(--text-2); font-size: 13px; } -.mode-hero .cur { position: absolute; top: 12px; right: 12px; } -@media (max-width: 860px) { .mode-hero { grid-template-columns: 1fr; } } -.gauge { display: flex; align-items: center; gap: 16px; } -.gauge .ring { width: 72px; height: 72px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 18px; background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--panel-2) 0); position: relative; } -.gauge .ring::after { content: ""; position: absolute; inset: 8px; border-radius: 50%; background: var(--panel); } -.gauge .ring span { position: relative; z-index: 1; font-size: 15px; } -.scorecard { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; } -.scorecard > div { background: var(--panel); border-radius: 10px; padding: 16px 18px; box-shadow: var(--shadow-1); } -.scorecard .v { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } -.scorecard .l { font-size: 12px; color: var(--text-2); } +.land .pfield { display: grid; grid-template-columns: minmax(0, 1fr) 160px; gap: 16px; align-items: center; padding: 14px 0; border-top: 1px solid var(--border); } +.land .pfield:first-child { border-top: 0; } +.land .pfield .lbl { font-weight: 600; } +.land .pfield .hint { font-size: 12px; color: var(--text-2); margin-top: 2px; } +.land .pfield input, .land .pfield select { height: 40px; } +.land .pfield .unit { display: flex; align-items: center; gap: 8px; } +.land .pfield .unit span { color: var(--text-2); font-size: 12px; white-space: nowrap; } +.land .pfield.changed .lbl::after { content: " •"; color: var(--warning); } +.land .stepper { display: inline-flex; align-items: center; border: 1px solid var(--border-2); border-radius: 8px; overflow: hidden; height: 40px; } +.land .stepper button { width: 36px; height: 100%; border: 0; background: var(--panel-2); color: var(--text); cursor: pointer; font-size: 16px; } +.land .stepper button:hover { background: var(--brand-bg-2); } +.land .stepper input { border: 0; width: 64px; text-align: center; height: 100%; border-radius: 0; } +.land .mode-hero { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; } +.land .mode-hero > div { border: 1px solid var(--border); border-radius: 10px; padding: 18px; position: relative; transition: border-color 0.25s, transform 0.25s var(--ease); } +.land .mode-hero > div.on { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); transform: translateY(-2px); } +.land .mode-hero .m { font-size: 18px; font-weight: 800; margin-bottom: 4px; } +.land .mode-hero .d { color: var(--text-2); font-size: 13px; } +.land .mode-hero .cur { position: absolute; top: 12px; right: 12px; } +@media (max-width: 860px) { .land .mode-hero { grid-template-columns: 1fr; } } +.land .gauge { display: flex; align-items: center; gap: 16px; } +.land .gauge .ring { width: 72px; height: 72px; border-radius: 50%; display: grid; place-items: center; font-weight: 800; font-size: 18px; background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--panel-2) 0); position: relative; } +.land .gauge .ring::after { content: ""; position: absolute; inset: 8px; border-radius: 50%; background: var(--panel); } +.land .gauge .ring span { position: relative; z-index: 1; font-size: 15px; } +.land .scorecard { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; } +.land .scorecard > div { background: var(--panel); border-radius: 10px; padding: 16px 18px; box-shadow: var(--shadow-1); } +.land .scorecard .v { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } +.land .scorecard .l { font-size: 12px; color: var(--text-2); } /* ================================================================== forms */ -.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } -.field-label { font-size: 14px; font-weight: 700; } -.field-hint { font-size: 12px; color: var(--text-2); } -input, select, textarea { height: 48px; padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--panel); color: var(--text); width: 100%; font-size: 14px; transition: border-color 0.15s, box-shadow 0.15s; } -select option { background: var(--panel); color: var(--text); } -input[type="checkbox"] { height: auto; width: auto; accent-color: var(--accent); } -input[type="range"] { height: auto; padding: 0; border: 0; accent-color: var(--accent); } -input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } -input:read-only { color: var(--text-2); } -.row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; } -.row > .field { flex: 1; min-width: 180px; } -.inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } -.stack { display: flex; flex-direction: column; gap: 8px; } -.notice { padding: 14px 16px; border-radius: var(--radius-sm); margin: 12px 0; font-size: 14px; display: flex; gap: 10px; align-items: flex-start; animation: rise 0.3s var(--ease); } -.notice-ok { background: var(--success-bg); color: var(--success-text); } -.notice-bad { background: var(--error-bg); color: var(--error-text); } -.notice-warn { background: var(--warning-bg); color: var(--warning-text); } -.notice-info { background: var(--info-bg); color: var(--info-text); } -.empty { padding: 40px 24px; text-align: center; color: var(--text-2); } -.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; } -.switch .track { width: 40px; height: 22px; border-radius: 999px; background: var(--border-2); position: relative; transition: background 0.2s; } -.switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform 0.2s var(--ease); } -.switch.on .track { background: var(--accent); } -.switch.on .track::after { transform: translateX(18px); } -.segmented { display: inline-flex; padding: 4px; border-radius: 999px; background: var(--panel); gap: 4px; box-shadow: var(--shadow-1); } -.segmented button { border: 0; background: transparent; color: var(--text-2); font-weight: 700; padding: 10px 28px; border-radius: 999px; cursor: pointer; transition: background 0.2s, color 0.2s; } -.segmented button.active { background: var(--brand); color: var(--brand-contrast); } -.review { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel-3); padding: 4px 16px; } -.review-line { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); } -.review-line:first-child { border-top: 0; } -.review-line > span:first-child { color: var(--text-2); flex: none; } -.review-line > *:last-child { text-align: right; } -.reasons { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } -.bar { height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden; margin-top: 8px; } -.bar > i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: grow 0.8s var(--ease); } -.bar.warn > i { background: var(--warning); } -.bar.bad > i { background: var(--error); } -.templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; } -.template { border: 1px solid var(--border); border-radius: 10px; padding: 16px; cursor: pointer; background: var(--panel-3); text-align: left; color: var(--text); transition: border-color 0.2s, transform 0.2s var(--ease), box-shadow 0.2s; } -.template:hover { border-color: var(--border-2); transform: translateY(-2px); } -.template.active { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 3px var(--accent-soft); } -.template strong { display: block; margin-bottom: 4px; } -.scenario { border-radius: 10px; padding: 20px 24px; margin-bottom: 12px; background: var(--panel); border-left: 4px solid var(--border-2); box-shadow: var(--shadow-1); transition: transform 0.25s var(--ease), box-shadow 0.25s; } -.scenario:hover { transform: translateX(4px); box-shadow: var(--shadow-2); } -.scenario.blocked, .scenario.impossible { border-left-color: var(--success); } -.scenario.delayed { border-left-color: var(--info); } -.scenario.escalated { border-left-color: var(--warning); } -.scenario.allowed { border-left-color: var(--error); } -.scenario ul { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } -.posture { list-style: none; margin: 0; padding: 0; } -.posture li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; } -.posture .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-3); } -.posture .dot.ok { background: var(--success); } -.posture .dot.warn { background: var(--warning); } -.posture .dot.bad { background: var(--error); } -.assumptions { font-size: 12px; color: var(--text-2); margin: 12px 0 0; padding-left: 18px; } +.land .field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } +.land .field-label { font-size: 14px; font-weight: 700; } +.land .field-hint { font-size: 12px; color: var(--text-2); } +.land input, .land select, .land textarea { height: 48px; padding: 0 14px; border: 1px solid var(--border-2); border-radius: var(--radius-sm); background: var(--panel); color: var(--text); width: 100%; font-size: 14px; transition: border-color 0.15s, box-shadow 0.15s; } +.land select option { background: var(--panel); color: var(--text); } +.land input[type="checkbox"] { height: auto; width: auto; accent-color: var(--accent); } +.land input[type="range"] { height: auto; padding: 0; border: 0; accent-color: var(--accent); } +.land input:focus, .land select:focus, .land textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); } +.land input:read-only { color: var(--text-2); } +.land .row { display: flex; gap: 16px; flex-wrap: wrap; align-items: flex-end; } +.land .row > .field { flex: 1; min-width: 180px; } +.land .inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } +.land .stack { display: flex; flex-direction: column; gap: 8px; } +.land .notice { padding: 14px 16px; border-radius: var(--radius-sm); margin: 12px 0; font-size: 14px; display: flex; gap: 10px; align-items: flex-start; animation: rise 0.3s var(--ease); } +.land .notice-ok { background: var(--success-bg); color: var(--success-text); } +.land .notice-bad { background: var(--error-bg); color: var(--error-text); } +.land .notice-warn { background: var(--warning-bg); color: var(--warning-text); } +.land .notice-info { background: var(--info-bg); color: var(--info-text); } +.land .empty { padding: 40px 24px; text-align: center; color: var(--text-2); } +.land .switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; } +.land .switch .track { width: 40px; height: 22px; border-radius: 999px; background: var(--border-2); position: relative; transition: background 0.2s; } +.land .switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; transition: transform 0.2s var(--ease); } +.land .switch.on .track { background: var(--accent); } +.land .switch.on .track::after { transform: translateX(18px); } +.land .segmented { display: inline-flex; padding: 4px; border-radius: 999px; background: var(--panel); gap: 4px; box-shadow: var(--shadow-1); } +.land .segmented button { border: 0; background: transparent; color: var(--text-2); font-weight: 700; padding: 10px 28px; border-radius: 999px; cursor: pointer; transition: background 0.2s, color 0.2s; } +.land .segmented button.active { background: var(--brand); color: var(--brand-contrast); } +.land .review { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel-3); padding: 4px 16px; } +.land .review-line { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-top: 1px solid var(--border); } +.land .review-line:first-child { border-top: 0; } +.land .review-line > span:first-child { color: var(--text-2); flex: none; } +.land .review-line > *:last-child { text-align: right; } +.land .reasons { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } +.land .bar { height: 6px; background: var(--panel-2); border-radius: 3px; overflow: hidden; margin-top: 8px; } +.land .bar > i { display: block; height: 100%; background: var(--accent); transform-origin: left; animation: grow 0.8s var(--ease); } +.land .bar.warn > i { background: var(--warning); } +.land .bar.bad > i { background: var(--error); } +.land .templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px; } +.land .template { border: 1px solid var(--border); border-radius: 10px; padding: 16px; cursor: pointer; background: var(--panel-3); text-align: left; color: var(--text); transition: border-color 0.2s, transform 0.2s var(--ease), box-shadow 0.2s; } +.land .template:hover { border-color: var(--border-2); transform: translateY(-2px); } +.land .template.active { border-color: var(--accent); background: var(--accent-bg); box-shadow: 0 0 0 3px var(--accent-soft); } +.land .template strong { display: block; margin-bottom: 4px; } +.land .scenario { border-radius: 10px; padding: 20px 24px; margin-bottom: 12px; background: var(--panel); border-left: 4px solid var(--border-2); box-shadow: var(--shadow-1); transition: transform 0.25s var(--ease), box-shadow 0.25s; } +.land .scenario:hover { transform: translateX(4px); box-shadow: var(--shadow-2); } +.land .scenario.blocked, .land .scenario.impossible { border-left-color: var(--success); } +.land .scenario.delayed { border-left-color: var(--info); } +.land .scenario.escalated { border-left-color: var(--warning); } +.land .scenario.allowed { border-left-color: var(--error); } +.land .scenario ul { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); } +.land .posture { list-style: none; margin: 0; padding: 0; } +.land .posture li { display: flex; gap: 10px; align-items: baseline; padding: 6px 0; } +.land .posture .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--text-3); } +.land .posture .dot.ok { background: var(--success); } +.land .posture .dot.warn { background: var(--warning); } +.land .posture .dot.bad { background: var(--error); } +.land .assumptions { font-size: 12px; color: var(--text-2); margin: 12px 0 0; padding-left: 18px; } /* modal */ -.modal-backdrop { position: fixed; inset: 0; background: rgba(33, 37, 41, 0.55); backdrop-filter: blur(4px); z-index: 50; display: flex; align-items: flex-start; justify-content: center; padding: 48px 16px; overflow-y: auto; animation: fade 0.2s var(--ease); } -.modal { width: 100%; max-width: 640px; background: var(--panel); border-radius: 14px; box-shadow: 0 24px 64px rgba(0,0,0,0.35); animation: pop 0.3s var(--ease); } -.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px; border-bottom: 1px solid var(--border); } -.modal-body { padding: 24px; } -.modal-foot { display: flex; justify-content: space-between; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--border); } -.steps { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--text-2); } -.steps .step { display: inline-flex; align-items: center; gap: 6px; } -.steps .n { width: 20px; height: 20px; border-radius: 50%; display: inline-grid; place-items: center; background: var(--panel-2); font-weight: 700; font-size: 11px; transition: background 0.2s, color 0.2s; } -.steps .step.on .n { background: var(--accent); color: var(--accent-contrast); } -.steps .step.on { color: var(--text); font-weight: 700; } +.land .modal-backdrop { position: fixed; inset: 0; background: rgba(33, 37, 41, 0.55); backdrop-filter: blur(4px); z-index: 50; display: flex; align-items: flex-start; justify-content: center; padding: 48px 16px; overflow-y: auto; animation: fade 0.2s var(--ease); } +.land .modal { width: 100%; max-width: 640px; background: var(--panel); border-radius: 14px; box-shadow: 0 24px 64px rgba(0,0,0,0.35); animation: pop 0.3s var(--ease); } +.land .modal-head { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px; border-bottom: 1px solid var(--border); } +.land .modal-body { padding: 24px; } +.land .modal-foot { display: flex; justify-content: space-between; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--border); } +.land .steps { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--text-2); } +.land .steps .step { display: inline-flex; align-items: center; gap: 6px; } +.land .steps .n { width: 20px; height: 20px; border-radius: 50%; display: inline-grid; place-items: center; background: var(--panel-2); font-weight: 700; font-size: 11px; transition: background 0.2s, color 0.2s; } +.land .steps .step.on .n { background: var(--accent); color: var(--accent-contrast); } +.land .steps .step.on { color: var(--text); font-weight: 700; } /* ================================================================== welcome / create */ -.entry { min-height: 100vh; background: radial-gradient(60% 40% at 50% 28%, var(--panel-2) 0%, var(--canvas) 60%); display: flex; flex-direction: column; } -.entry-top { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; animation: fade 0.4s var(--ease); } -.entry-top .logo { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 18px; } -.entry-top .logo .mark { width: 28px; height: 28px; display: block; } -.entry-center { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 40px 16px; gap: 16px; } -.entry-card { width: 100%; max-width: 440px; background: var(--panel); border-radius: 16px; padding: 32px; text-align: center; box-shadow: var(--shadow-2); animation: pop 0.45s var(--ease) both; } -.entry-card h2 { font-size: 24px; margin: 12px 0 8px; } -.entry-card p { color: var(--text-2); margin-bottom: 20px; } -.entry-card .or { display: flex; align-items: center; gap: 12px; color: var(--text-2); font-size: 12px; margin: 16px 0; } -.entry-card .or::before, .entry-card .or::after { content: ""; flex: 1; height: 1px; background: var(--border-2); } -.entry-note { max-width: 440px; width: 100%; background: var(--panel); border-radius: 10px; padding: 10px 16px; display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 14px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) 0.1s both; } -.entry-foot { display: flex; gap: 16px; justify-content: center; padding: 24px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; } -.entry-foot a { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } -[data-theme="dark"] .entry-foot a { color: var(--accent); box-shadow: none; } -.wordmark-lg { font-size: 28px; font-weight: 800; letter-spacing: -0.02em; display: inline-flex; align-items: center; gap: 10px; justify-content: center; } -.wordmark-lg .brace { color: var(--text-2); font-weight: 500; } -.create { max-width: 1160px; margin: 0 auto; padding: 24px; } -.create-grid { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 24px; align-items: start; } -@media (max-width: 960px) { .create-grid { grid-template-columns: 1fr; } } -.stepcard { background: var(--panel); border-radius: 10px; overflow: hidden; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease); } -.stepcard .progress { height: 4px; background: var(--border); } -.stepcard .progress i { display: block; height: 100%; background: var(--accent); transition: width 0.5s var(--ease); } -.stepcard .step-head { display: flex; gap: 16px; align-items: flex-start; padding: 24px 28px; border-bottom: 1px solid var(--border); } -.stepcard .step-head .n { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 12px; flex: none; margin-top: 2px; } -.stepcard .step-head h3 { font-size: 20px; } -.stepcard .step-head p { color: var(--text-2); margin-top: 2px; } -.stepcard .step-body { padding: 28px; animation: fade 0.3s var(--ease); } -.stepcard .step-foot { display: flex; justify-content: space-between; padding: 20px 28px; border-top: 1px solid var(--border); } -.preview { background: var(--panel); border-radius: 10px; padding: 24px; text-align: center; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease) 0.1s both; position: sticky; top: 24px; } -.preview h4 { font-size: 18px; margin: 8px 0 16px; } -.preview .kv div { text-align: left; } +.land .entry { min-height: 100vh; background: radial-gradient(60% 40% at 50% 28%, var(--panel-2) 0%, var(--canvas) 60%); display: flex; flex-direction: column; } +.land .entry-top { display: flex; justify-content: space-between; align-items: center; padding: 16px 24px; animation: fade 0.4s var(--ease); } +.land .entry-top .logo { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 18px; } +.land .entry-top .logo .mark { width: 28px; height: 28px; display: block; } +.land .entry-center { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 40px 16px; gap: 16px; } +.land .entry-card { width: 100%; max-width: 440px; background: var(--panel); border-radius: 16px; padding: 32px; text-align: center; box-shadow: var(--shadow-2); animation: pop 0.45s var(--ease) both; } +.land .entry-card h2 { font-size: 24px; margin: 12px 0 8px; } +.land .entry-card p { color: var(--text-2); margin-bottom: 20px; } +.land .entry-card .or { display: flex; align-items: center; gap: 12px; color: var(--text-2); font-size: 12px; margin: 16px 0; } +.land .entry-card .or::before, .land .entry-card .or::after { content: ""; flex: 1; height: 1px; background: var(--border-2); } +.land .entry-note { max-width: 440px; width: 100%; background: var(--panel); border-radius: 10px; padding: 10px 16px; display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 14px; box-shadow: var(--shadow-1); animation: rise 0.4s var(--ease) 0.1s both; } +.land .entry-foot { display: flex; gap: 16px; justify-content: center; padding: 24px; color: var(--text-2); font-size: 13px; flex-wrap: wrap; } +.land .entry-foot a { color: var(--text); font-weight: 700; box-shadow: inset 0 -6px 0 var(--accent); } +[data-theme="dark"] .land .entry-foot a { color: var(--accent); box-shadow: none; } +.land .wordmark-lg { font-size: 28px; font-weight: 800; letter-spacing: -0.02em; display: inline-flex; align-items: center; gap: 10px; justify-content: center; } +.land .wordmark-lg .brace { color: var(--text-2); font-weight: 500; } +.land .create { max-width: 1160px; margin: 0 auto; padding: 24px; } +.land .create-grid { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 24px; align-items: start; } +@media (max-width: 960px) { .land .create-grid { grid-template-columns: 1fr; } } +.land .stepcard { background: var(--panel); border-radius: 10px; overflow: hidden; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease); } +.land .stepcard .progress { height: 4px; background: var(--border); } +.land .stepcard .progress i { display: block; height: 100%; background: var(--accent); transition: width 0.5s var(--ease); } +.land .stepcard .step-head { display: flex; gap: 16px; align-items: flex-start; padding: 24px 28px; border-bottom: 1px solid var(--border); } +.land .stepcard .step-head .n { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); color: var(--accent-contrast); display: grid; place-items: center; font-weight: 800; font-size: 12px; flex: none; margin-top: 2px; } +.land .stepcard .step-head h3 { font-size: 20px; } +.land .stepcard .step-head p { color: var(--text-2); margin-top: 2px; } +.land .stepcard .step-body { padding: 28px; animation: fade 0.3s var(--ease); } +.land .stepcard .step-foot { display: flex; justify-content: space-between; padding: 20px 28px; border-top: 1px solid var(--border); } +.land .preview { background: var(--panel); border-radius: 10px; padding: 24px; text-align: center; box-shadow: var(--shadow-1); animation: rise 0.45s var(--ease) 0.1s both; position: sticky; top: 24px; } +.land .preview h4 { font-size: 18px; margin: 8px 0 16px; } +.land .preview .kv div { text-align: left; } /* ================================================================== marketing site (safe.global) */ .land { --lt: #212529; --ls: #6c757d; font-size: 16px; line-height: 24px; color: #212529; background: #fff; overflow-x: hidden; } .land .wrap { max-width: 1216px; margin: 0 auto; padding: 0 24px; } -.land-nav { position: sticky; top: 0; z-index: 30; background: rgba(255,255,255,0.85); backdrop-filter: blur(12px); border-bottom: 1px solid transparent; transition: border-color 0.2s, box-shadow 0.2s; } -.land-nav.scrolled { border-bottom-color: #e9ecef; box-shadow: 0 4px 24px rgba(33,37,41,0.06); } -.land-nav .nav-right { display: flex; align-items: center; gap: 14px; } -.netchip { display: inline-flex; align-items: center; gap: 8px; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #6c757d; border: 1px solid #dee2e6; padding: 7px 10px; border-radius: 4px; } -.netchip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #ffd000; box-shadow: 0 0 0 3px rgba(255,208,0,0.25); } -.land-nav .wrap { height: 72px; display: flex; align-items: center; justify-content: space-between; gap: 24px; } -.land-nav .logo { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 22px; letter-spacing: -0.02em; font-family: "Space Grotesk", sans-serif; } -.land-nav .logo .mark { width: 28px; height: 28px; display: block; } -.land-nav .logo .brace { color: #6c757d; font-weight: 500; } -.land-nav nav { display: flex; gap: 32px; } -.land-nav nav a { color: #6c757d; font-weight: 500; position: relative; z-index: 0; transition: color 0.15s; } -.land-nav nav a::after { content: ""; position: absolute; left: -4px; right: -4px; bottom: 1px; height: 9px; z-index: -1; background: #ffd000; transform: scaleX(0); transform-origin: left; transition: transform 0.25s var(--ease); } -.land-nav nav a:hover, .land-nav nav a.on { color: #212529; } -.land-nav nav a:hover::after, .land-nav nav a.on::after { transform: scaleX(1); } +.land .land-nav { position: sticky; top: 0; z-index: 30; background: rgba(255,255,255,0.85); backdrop-filter: blur(12px); border-bottom: 1px solid transparent; transition: border-color 0.2s, box-shadow 0.2s; } +.land .land-nav.scrolled { border-bottom-color: #e9ecef; box-shadow: 0 4px 24px rgba(33,37,41,0.06); } +.land .land-nav .nav-right { display: flex; align-items: center; gap: 14px; } +.land .netchip { display: inline-flex; align-items: center; gap: 8px; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #6c757d; border: 1px solid #dee2e6; padding: 7px 10px; border-radius: 4px; } +.land .netchip::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #ffd000; box-shadow: 0 0 0 3px rgba(255,208,0,0.25); } +.land .land-nav .wrap { height: 72px; display: flex; align-items: center; justify-content: space-between; gap: 24px; } +.land .land-nav .logo { display: inline-flex; align-items: center; gap: 10px; font-weight: 700; font-size: 22px; letter-spacing: -0.02em; font-family: "Space Grotesk", sans-serif; } +.land .land-nav .logo .mark { width: 28px; height: 28px; display: block; } +.land .land-nav .logo .brace { color: #6c757d; font-weight: 500; } +.land .land-nav nav { display: flex; gap: 32px; } +.land .land-nav nav a { color: #6c757d; font-weight: 500; position: relative; z-index: 0; transition: color 0.15s; } +.land .land-nav nav a::after { content: ""; position: absolute; left: -4px; right: -4px; bottom: 1px; height: 9px; z-index: -1; background: #ffd000; transform: scaleX(0); transform-origin: left; transition: transform 0.25s var(--ease); } +.land .land-nav nav a:hover, .land .land-nav nav a.on { color: #212529; } +.land .land-nav nav a:hover::after, .land .land-nav nav a.on::after { transform: scaleX(1); } .land .announce { background: #212529; color: #fff; text-align: center; padding: 12px 24px; font-size: 14px; } .land .announce a { font-weight: 500; } .land .announce a span { color: #ffd000; } .land .announce a span { display: inline-block; transition: transform 0.2s var(--ease); } .land .announce a:hover span { transform: translateX(4px); } -.hero { position: relative; overflow: hidden; background: #f8f9fa; padding: 104px 0 0; text-align: center; } -.hero.sub-hero { padding: 88px 0 72px; } -.hero .grid-bg { position: absolute; inset: 0; background-image: linear-gradient(#e9ecef 1px, transparent 1px), linear-gradient(90deg, #e9ecef 1px, transparent 1px); background-size: 131px 131px; } -.hero .cell { position: absolute; width: 130px; height: 130px; background: linear-gradient(180deg, rgba(255,208,0,0) 0%, rgba(255,208,0,0.55) 100%); animation: cell 6s ease-in-out infinite; } -.hero .wrap { position: relative; } -.hero .eyebrow { font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 24px; animation: rise 0.6s var(--ease) both; display: flex; align-items: center; justify-content: center; gap: 12px; } -.hero .eyebrow b { background: #ffd000; color: #212529; padding: 3px 7px; font-weight: 500; } -.hero h1 { font-size: 84px; line-height: 84px; letter-spacing: -0.035em; font-weight: 700; max-width: 960px; margin: 0 auto 24px; animation: rise 0.7s var(--ease) 0.08s both; } -.hero h1 .w { display: inline-block; } -.hero .sub { font-size: 19px; line-height: 28px; color: #6c757d; max-width: 600px; margin: 0 auto 32px; animation: rise 0.7s var(--ease) 0.18s both; } -.hero .cta-row { animation: rise 0.7s var(--ease) 0.26s both; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } -.hero .mockwrap { position: relative; max-width: 960px; margin: 72px auto 0; text-align: left; animation: rise 0.9s var(--ease) 0.35s both; } -.hero .mock { border-radius: 8px 8px 0 0; box-shadow: 0 -8px 60px rgba(33,37,41,0.18); overflow: hidden; border: 1px solid #dee2e6; border-bottom: 0; } -.hero .float { position: absolute; right: -56px; bottom: 36px; width: 400px; animation: rise 0.9s var(--ease) 0.7s both; } -.hero .float .ticker { box-shadow: 0 30px 80px rgba(33,37,41,0.35), 0 0 0 1px rgba(255,255,255,0.06); } -@media (max-width: 1120px) { .hero .float { position: static; width: auto; margin: 24px 0 0; } .hero .mock { border-bottom: 1px solid #dee2e6; border-radius: 8px; } } -@media (max-width: 900px) { .hero h1 { font-size: 48px; line-height: 50px; } } +.land .hero { position: relative; overflow: hidden; background: #f8f9fa; padding: 104px 0 0; text-align: center; } +.land .hero.sub-hero { padding: 88px 0 72px; } +.land .hero .grid-bg { position: absolute; inset: 0; background-image: linear-gradient(#e9ecef 1px, transparent 1px), linear-gradient(90deg, #e9ecef 1px, transparent 1px); background-size: 131px 131px; } +.land .hero .cell { position: absolute; width: 130px; height: 130px; background: linear-gradient(180deg, rgba(255,208,0,0) 0%, rgba(255,208,0,0.55) 100%); animation: cell 6s ease-in-out infinite; } +.land .hero .wrap { position: relative; } +.land .hero .eyebrow { font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 24px; animation: rise 0.6s var(--ease) both; display: flex; align-items: center; justify-content: center; gap: 12px; } +.land .hero .eyebrow b { background: #ffd000; color: #212529; padding: 3px 7px; font-weight: 500; } +.land .hero h1 { font-size: 84px; line-height: 84px; letter-spacing: -0.035em; font-weight: 700; max-width: 960px; margin: 0 auto 24px; animation: rise 0.7s var(--ease) 0.08s both; } +.land .hero h1 .w { display: inline-block; } +.land .hero .sub { font-size: 19px; line-height: 28px; color: #6c757d; max-width: 600px; margin: 0 auto 32px; animation: rise 0.7s var(--ease) 0.18s both; } +.land .hero .cta-row { animation: rise 0.7s var(--ease) 0.26s both; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; } +.land .hero .mockwrap { position: relative; max-width: 960px; margin: 72px auto 0; text-align: left; animation: rise 0.9s var(--ease) 0.35s both; } +.land .hero .mock { border-radius: 8px 8px 0 0; box-shadow: 0 -8px 60px rgba(33,37,41,0.18); overflow: hidden; border: 1px solid #dee2e6; border-bottom: 0; } +.land .hero .float { position: absolute; right: -56px; bottom: 36px; width: 400px; animation: rise 0.9s var(--ease) 0.7s both; } +.land .hero .float .ticker { box-shadow: 0 30px 80px rgba(33,37,41,0.35), 0 0 0 1px rgba(255,255,255,0.06); } +@media (max-width: 1120px) { .land .hero .float { position: static; width: auto; margin: 24px 0 0; } .land .hero .mock { border-bottom: 1px solid #dee2e6; border-radius: 8px; } } +@media (max-width: 900px) { .land .hero h1 { font-size: 48px; line-height: 50px; } } .land .light { background: #f8f9fa; padding: 96px 0; } .land .white { background: #fff; padding: 96px 0; } .land .dark { background: #212529; color: #fff; padding: 96px 0; } @@ -555,329 +555,329 @@ input:read-only { color: var(--text-2); } .land .lead { text-align: left; color: #adb5bd; font-size: 17px; max-width: 640px; margin: 0 0 56px; } .land .center h2, .land .center .lead { text-align: center; margin-left: auto; margin-right: auto; } .land .light .lead, .land .white .lead { color: #6c757d; } -.marquee { overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); } -.marquee .track { display: flex; gap: 12px; width: max-content; animation: marquee 28s linear infinite; } -.marquee .track:hover { animation-play-state: paused; } -.marquee .chip-l { padding: 12px 22px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; border: 1px solid #dee2e6; background: #fff; font-weight: 600; white-space: nowrap; color: #212529; } -.bento { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } -.bento .big { grid-column: 1 / -1; } -.bcard { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 32px; min-height: 340px; background-image: radial-gradient(60% 40% at 50% 0%, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 100%); transition: transform 0.35s var(--ease), border-color 0.35s, box-shadow 0.35s; } -.bcard:hover { transform: translateY(-4px); border-color: #ffd000; box-shadow: 0 24px 60px rgba(0,0,0,0.35); } -.bcard h3 { font-size: 24px; margin-bottom: 8px; } -.bcard p { color: #adb5bd; margin-bottom: 24px; } -.bcard.center { text-align: center; } -.bcard .art { margin-top: 8px; } -@media (max-width: 860px) { .bento { grid-template-columns: 1fr; } } -.dashed { display: grid; grid-template-columns: 1fr 1fr; max-width: 900px; margin: 0 auto; } -.dashed > div { padding: 40px 32px 40px 48px; border-left: 1px dashed #495057; border-top: 1px dashed #495057; } -.dashed > div:nth-child(-n+2) { border-top: 0; } -.dashed > div:nth-child(odd) { border-left: 0; } -.dashed h4 { font-size: 18px; margin-bottom: 8px; } -.dashed p { color: #adb5bd; } -.badges { display: flex; gap: 40px; justify-content: center; align-items: center; flex-wrap: wrap; padding: 40px 0; border-top: 1px solid #343a40; color: #adb5bd; font-weight: 700; font-size: 18px; } -.badges .lbl { font-weight: 400; font-size: 14px; } -.shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; } -.shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; } -.shield p { color: #adb5bd; margin-bottom: 32px; max-width: 320px; } -.shield ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; font-size: 20px; font-weight: 700; } -.shield ul li { display: flex; gap: 12px; align-items: center; } -.shield ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 26px; height: 26px; } -.shield .tilt { transform: perspective(1200px) rotateY(-12deg) rotateX(4deg) rotate(6deg) scale(1.05); transform-origin: left center; border-radius: 10px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,0.5); transition: transform 0.6s var(--ease); } -.shield:hover .tilt { transform: perspective(1200px) rotateY(-6deg) rotateX(2deg) rotate(3deg) scale(1.03); } -@media (max-width: 900px) { .shield { grid-template-columns: 1fr; } .shield .tilt { transform: none; } } -.compare { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 12px; max-width: 1000px; margin: 0 auto; overflow-x: auto; } -.compare table { border-collapse: separate; border-spacing: 8px 0; } -.compare th, .compare td { border: 0; padding: 20px 20px; vertical-align: top; background: #343a40; border-radius: 0; font-size: 15px; color: #adb5bd; } -.compare th { font-weight: 500; font-size: 16px; } -.compare td:first-child { color: #fff; font-weight: 500; } -.compare .hl { background: #ffd000; color: #212529 !important; font-weight: 700; } -.compare th.hl { border-radius: 8px 8px 0 0; } -.compare tr:last-child td.hl { border-radius: 0 0 8px 8px; } -.quote { text-align: center; max-width: 960px; margin: 0 auto; } -.quote blockquote { font-size: 36px; line-height: 44px; font-style: italic; color: #dee2e6; margin: 0 0 32px; font-weight: 400; letter-spacing: -0.01em; } -.quote cite { font-style: normal; font-weight: 700; font-size: 20px; } -.stats { display: flex; gap: 96px; justify-content: center; flex-wrap: wrap; margin-top: 56px; } -.stats .v { font-size: 64px; line-height: 68px; color: #ffd000; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; } -.stats .l { color: #adb5bd; margin-top: 8px; font-size: 14px; } -.audiences { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; } -.acard { background: #212529; color: #fff; border-radius: 8px; padding: 28px; min-height: 420px; transition: transform 0.35s var(--ease), box-shadow 0.35s; } -.acard:hover { transform: translateY(-4px); box-shadow: 0 24px 60px rgba(33,37,41,0.3); } -.acard h3 { font-size: 22px; margin-bottom: 8px; } -.acard p { color: #adb5bd; margin-bottom: 20px; max-width: 320px; } -.acard a, .acard .link { color: #ffd000; font-weight: 700; } -.acard .art { margin-top: 24px; } -@media (max-width: 860px) { .audiences { grid-template-columns: 1fr; } } -.steps4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } -.steps4 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } -.steps4 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } -.steps4 .n { width: 32px; height: 32px; border-radius: 4px; background: #ffd000; color: #212529; font-family: "DM Mono", monospace; display: grid; place-items: center; font-weight: 800; margin-bottom: 20px; } -.steps4 h4 { font-size: 18px; margin-bottom: 8px; } -.steps4 p { color: #6c757d; } -@media (max-width: 900px) { .steps4 { grid-template-columns: 1fr 1fr; } } -.feat6 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } -.feat6 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } -.feat6 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } -.feat6 .ico { width: 44px; height: 44px; border-radius: 10px; background: #212529; color: #fff; display: grid; place-items: center; margin-bottom: 20px; } -.feat6 h4 { font-size: 18px; margin-bottom: 8px; } -.feat6 p { color: #6c757d; } -.dark .feat6 > div { background: #2b3035; border-color: #343a40; } -.dark .feat6 .ico { background: #ffd000; color: #212529; } -.dark .feat6 p { color: #adb5bd; } -@media (max-width: 900px) { .feat6 { grid-template-columns: 1fr; } } -.faq { max-width: 770px; margin: 0 auto; } -.faq details { border-bottom: 1px solid #e9ecef; } -.faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 20px 0; font-weight: 700; font-size: 17px; } -.faq summary::-webkit-details-marker { display: none; } -.faq summary .plus { width: 24px; height: 24px; border-radius: 4px; border: 1.5px solid #6c757d; display: grid; place-items: center; color: #6c757d; font-weight: 400; transition: transform 0.3s var(--ease), background 0.2s, color 0.2s; } -.faq details[open] summary .plus { transform: rotate(45deg); background: #ffd000; color: #212529; border-color: #ffd000; } -.faq .ans { padding: 0 0 20px; color: #6c757d; max-width: 680px; animation: rise 0.3s var(--ease); } -.cta { position: relative; overflow: hidden; background: #fff; background-image: radial-gradient(#d9dde2 1.2px, transparent 1.2px); background-size: 26px 26px; padding: 120px 0; text-align: center; } -.cta h2 { font-size: 56px; line-height: 60px; text-align: center; margin: 0 auto 12px; } -.cta h2 span { color: #6c757d; } -.cta .sub { color: #6c757d; font-size: 18px; margin: 20px 0 32px; } -.land-footer { background: #212529; color: #fff; padding: 72px 0 0; overflow: hidden; } -.land-footer .cols { display: grid; grid-template-columns: 2fr repeat(5, 1fr); gap: 24px; padding-bottom: 56px; border-bottom: 1px solid #343a40; } -.land-footer h5 { margin: 0 0 16px; font-size: 14px; color: #adb5bd; font-weight: 700; } -.land-footer ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; font-size: 15px; } -.land-footer ul a { transition: color 0.15s; } -.land-footer ul a:hover { color: #adb5bd; } -.land-footer .legal { display: flex; justify-content: space-between; padding: 32px 0; color: #6c757d; font-size: 14px; } -.land-footer .giant { font-size: 30vw; line-height: 0.8; font-weight: 800; letter-spacing: -0.05em; color: transparent; -webkit-text-stroke: 1.5px #ffd000; text-align: left; margin-top: 24px; user-select: none; } -@media (max-width: 900px) { .land-footer .cols { grid-template-columns: 1fr 1fr; } .land-nav nav { display: none; } } +.land .marquee { overflow: hidden; mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent); } +.land .marquee .track { display: flex; gap: 12px; width: max-content; animation: marquee 28s linear infinite; } +.land .marquee .track:hover { animation-play-state: paused; } +.land .marquee .chip-l { padding: 12px 22px; border-radius: 6px; font-family: "Space Grotesk", sans-serif; border: 1px solid #dee2e6; background: #fff; font-weight: 600; white-space: nowrap; color: #212529; } +.land .bento { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; } +.land .bento .big { grid-column: 1 / -1; } +.land .bcard { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 32px; min-height: 340px; background-image: radial-gradient(60% 40% at 50% 0%, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0) 100%); transition: transform 0.35s var(--ease), border-color 0.35s, box-shadow 0.35s; } +.land .bcard:hover { transform: translateY(-4px); border-color: #ffd000; box-shadow: 0 24px 60px rgba(0,0,0,0.35); } +.land .bcard h3 { font-size: 24px; margin-bottom: 8px; } +.land .bcard p { color: #adb5bd; margin-bottom: 24px; } +.land .bcard.center { text-align: center; } +.land .bcard .art { margin-top: 8px; } +@media (max-width: 860px) { .land .bento { grid-template-columns: 1fr; } } +.land .dashed { display: grid; grid-template-columns: 1fr 1fr; max-width: 900px; margin: 0 auto; } +.land .dashed > div { padding: 40px 32px 40px 48px; border-left: 1px dashed #495057; border-top: 1px dashed #495057; } +.land .dashed > div:nth-child(-n+2) { border-top: 0; } +.land .dashed > div:nth-child(odd) { border-left: 0; } +.land .dashed h4 { font-size: 18px; margin-bottom: 8px; } +.land .dashed p { color: #adb5bd; } +.land .badges { display: flex; gap: 40px; justify-content: center; align-items: center; flex-wrap: wrap; padding: 40px 0; border-top: 1px solid #343a40; color: #adb5bd; font-weight: 700; font-size: 18px; } +.land .badges .lbl { font-weight: 400; font-size: 14px; } +.land .shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; } +.land .shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; } +.land .shield p { color: #adb5bd; margin-bottom: 32px; max-width: 320px; } +.land .shield ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; font-size: 20px; font-weight: 700; } +.land .shield ul li { display: flex; gap: 12px; align-items: center; } +.land .shield ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 26px; height: 26px; } +.land .shield .tilt { transform: perspective(1200px) rotateY(-12deg) rotateX(4deg) rotate(6deg) scale(1.05); transform-origin: left center; border-radius: 10px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,0.5); transition: transform 0.6s var(--ease); } +.land .shield:hover .tilt { transform: perspective(1200px) rotateY(-6deg) rotateX(2deg) rotate(3deg) scale(1.03); } +@media (max-width: 900px) { .land .shield { grid-template-columns: 1fr; } .land .shield .tilt { transform: none; } } +.land .compare { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 12px; max-width: 1000px; margin: 0 auto; overflow-x: auto; } +.land .compare table { border-collapse: separate; border-spacing: 8px 0; } +.land .compare th, .land .compare td { border: 0; padding: 20px 20px; vertical-align: top; background: #343a40; border-radius: 0; font-size: 15px; color: #adb5bd; } +.land .compare th { font-weight: 500; font-size: 16px; } +.land .compare td:first-child { color: #fff; font-weight: 500; } +.land .compare .hl { background: #ffd000; color: #212529 !important; font-weight: 700; } +.land .compare th.hl { border-radius: 8px 8px 0 0; } +.land .compare tr:last-child td.hl { border-radius: 0 0 8px 8px; } +.land .quote { text-align: center; max-width: 960px; margin: 0 auto; } +.land .quote blockquote { font-size: 36px; line-height: 44px; font-style: italic; color: #dee2e6; margin: 0 0 32px; font-weight: 400; letter-spacing: -0.01em; } +.land .quote cite { font-style: normal; font-weight: 700; font-size: 20px; } +.land .stats { display: flex; gap: 96px; justify-content: center; flex-wrap: wrap; margin-top: 56px; } +.land .stats .v { font-size: 64px; line-height: 68px; color: #ffd000; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; } +.land .stats .l { color: #adb5bd; margin-top: 8px; font-size: 14px; } +.land .audiences { display: grid; grid-template-columns: 1fr 2fr; gap: 20px; } +.land .acard { background: #212529; color: #fff; border-radius: 8px; padding: 28px; min-height: 420px; transition: transform 0.35s var(--ease), box-shadow 0.35s; } +.land .acard:hover { transform: translateY(-4px); box-shadow: 0 24px 60px rgba(33,37,41,0.3); } +.land .acard h3 { font-size: 22px; margin-bottom: 8px; } +.land .acard p { color: #adb5bd; margin-bottom: 20px; max-width: 320px; } +.land .acard a, .land .acard .link { color: #ffd000; font-weight: 700; } +.land .acard .art { margin-top: 24px; } +@media (max-width: 860px) { .land .audiences { grid-template-columns: 1fr; } } +.land .steps4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; } +.land .steps4 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } +.land .steps4 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } +.land .steps4 .n { width: 32px; height: 32px; border-radius: 4px; background: #ffd000; color: #212529; font-family: "DM Mono", monospace; display: grid; place-items: center; font-weight: 800; margin-bottom: 20px; } +.land .steps4 h4 { font-size: 18px; margin-bottom: 8px; } +.land .steps4 p { color: #6c757d; } +@media (max-width: 900px) { .land .steps4 { grid-template-columns: 1fr 1fr; } } +.land .feat6 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } +.land .feat6 > div { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 28px; transition: transform 0.3s var(--ease), box-shadow 0.3s; } +.land .feat6 > div:hover { transform: translateY(-4px); box-shadow: 0 16px 40px rgba(33,37,41,0.1); } +.land .feat6 .ico { width: 44px; height: 44px; border-radius: 10px; background: #212529; color: #fff; display: grid; place-items: center; margin-bottom: 20px; } +.land .feat6 h4 { font-size: 18px; margin-bottom: 8px; } +.land .feat6 p { color: #6c757d; } +.land .dark .feat6 > div { background: #2b3035; border-color: #343a40; } +.land .dark .feat6 .ico { background: #ffd000; color: #212529; } +.land .dark .feat6 p { color: #adb5bd; } +@media (max-width: 900px) { .land .feat6 { grid-template-columns: 1fr; } } +.land .faq { max-width: 770px; margin: 0 auto; } +.land .faq details { border-bottom: 1px solid #e9ecef; } +.land .faq summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; padding: 20px 0; font-weight: 700; font-size: 17px; } +.land .faq summary::-webkit-details-marker { display: none; } +.land .faq summary .plus { width: 24px; height: 24px; border-radius: 4px; border: 1.5px solid #6c757d; display: grid; place-items: center; color: #6c757d; font-weight: 400; transition: transform 0.3s var(--ease), background 0.2s, color 0.2s; } +.land .faq details[open] summary .plus { transform: rotate(45deg); background: #ffd000; color: #212529; border-color: #ffd000; } +.land .faq .ans { padding: 0 0 20px; color: #6c757d; max-width: 680px; animation: rise 0.3s var(--ease); } +.land .cta { position: relative; overflow: hidden; background: #fff; background-image: radial-gradient(#d9dde2 1.2px, transparent 1.2px); background-size: 26px 26px; padding: 120px 0; text-align: center; } +.land .cta h2 { font-size: 56px; line-height: 60px; text-align: center; margin: 0 auto 12px; } +.land .cta h2 span { color: #6c757d; } +.land .cta .sub { color: #6c757d; font-size: 18px; margin: 20px 0 32px; } +.land .land-footer { background: #212529; color: #fff; padding: 72px 0 0; overflow: hidden; } +.land .land-footer .cols { display: grid; grid-template-columns: 2fr repeat(5, 1fr); gap: 24px; padding-bottom: 56px; border-bottom: 1px solid #343a40; } +.land .land-footer h5 { margin: 0 0 16px; font-size: 14px; color: #adb5bd; font-weight: 700; } +.land .land-footer ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 12px; font-size: 15px; } +.land .land-footer ul a { transition: color 0.15s; } +.land .land-footer ul a:hover { color: #adb5bd; } +.land .land-footer .legal { display: flex; justify-content: space-between; padding: 32px 0; color: #6c757d; font-size: 14px; } +.land .land-footer .giant { font-size: 30vw; line-height: 0.8; font-weight: 800; letter-spacing: -0.05em; color: transparent; -webkit-text-stroke: 1.5px #ffd000; text-align: left; margin-top: 24px; user-select: none; } +@media (max-width: 900px) { .land .land-footer .cols { grid-template-columns: 1fr 1fr; } .land .land-nav nav { display: none; } } /* mini app mockup used on the marketing pages */ -.mock-app { background: #212529; color: #fff; font-size: 12px; display: grid; grid-template-columns: 180px 1fr; min-height: 420px; } -.mock-app .sb { background: #2b3035; padding: 12px; border-right: 1px solid #343a40; } -.mock-app .sb .pill { height: 26px; border-radius: 4px; background: #3d3400; padding: 0 10px; font-weight: 700; margin-bottom: 8px; } -.mock-app .sb .ntx { border: 1px solid #6c757d; border-radius: 6px; padding: 6px; color: #adb5bd; text-align: center; margin-bottom: 12px; } -.mock-app .sb .it { padding: 6px 8px; color: #fff; border-radius: 6px; } -.mock-app .sb .it.on { background: #3d3400; font-weight: 700; } -.mock-app .ct { padding: 14px; display: grid; gap: 12px; grid-template-columns: 1.7fr 1fr; align-items: start; } -.mock-app .acct { grid-column: 1 / -1; background: #2b3035; border-radius: 10px; padding: 8px 12px; display: flex; align-items: center; gap: 10px; } -.mock-app .pn { background: #2b3035; border-radius: 10px; padding: 14px; } -.mock-app .big { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } -.mock-app .big span { color: #6c757d; } -.mock-app .mb { display: inline-block; background: #343a40; border-radius: 6px; padding: 4px 10px; margin-right: 6px; margin-top: 8px; } -.mock-app .li { display: flex; justify-content: space-between; padding: 8px 0; border-top: 1px solid #343a40; } -.mock-app .ok { color: #75b798; font-weight: 700; } -.mock-app .rv { color: #ffcd39; font-weight: 700; } -.mock-app .ident { width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(#ffd000, #6c757d, #adb5bd, #ffd000); } +.land .mock-app { background: #212529; color: #fff; font-size: 12px; display: grid; grid-template-columns: 180px 1fr; min-height: 420px; } +.land .mock-app .sb { background: #2b3035; padding: 12px; border-right: 1px solid #343a40; } +.land .mock-app .sb .pill { height: 26px; border-radius: 4px; background: #3d3400; padding: 0 10px; font-weight: 700; margin-bottom: 8px; } +.land .mock-app .sb .ntx { border: 1px solid #6c757d; border-radius: 6px; padding: 6px; color: #adb5bd; text-align: center; margin-bottom: 12px; } +.land .mock-app .sb .it { padding: 6px 8px; color: #fff; border-radius: 6px; } +.land .mock-app .sb .it.on { background: #3d3400; font-weight: 700; } +.land .mock-app .ct { padding: 14px; display: grid; gap: 12px; grid-template-columns: 1.7fr 1fr; align-items: start; } +.land .mock-app .acct { grid-column: 1 / -1; background: #2b3035; border-radius: 10px; padding: 8px 12px; display: flex; align-items: center; gap: 10px; } +.land .mock-app .pn { background: #2b3035; border-radius: 10px; padding: 14px; } +.land .mock-app .big { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; } +.land .mock-app .big span { color: #6c757d; } +.land .mock-app .mb { display: inline-block; background: #343a40; border-radius: 6px; padding: 4px 10px; margin-right: 6px; margin-top: 8px; } +.land .mock-app .li { display: flex; justify-content: space-between; padding: 8px 0; border-top: 1px solid #343a40; } +.land .mock-app .ok { color: #75b798; font-weight: 700; } +.land .mock-app .rv { color: #ffcd39; font-weight: 700; } +.land .mock-app .ident { width: 24px; height: 24px; border-radius: 50%; background: conic-gradient(#ffd000, #6c757d, #adb5bd, #ffd000); } @media (max-width: 860px) { - .shell { flex-direction: column; } - .sidebar { width: auto; height: auto; position: static; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px 12px; } - .newtx { margin: 0; flex: 1 1 100%; } - .nav { flex-direction: row; flex-wrap: wrap; } - .nav button.active::before { display: none; } - .nav-group, .sidebar-bottom { display: none; } - .main { padding: 16px; } + .land .shell { flex-direction: column; } + .land .sidebar { width: auto; height: auto; position: static; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 6px; padding: 10px 12px; } + .land .newtx { margin: 0; flex: 1 1 100%; } + .land .nav { flex-direction: row; flex-wrap: wrap; } + .land .nav button.active::before { display: none; } + .land .nav-group, .land .sidebar-bottom { display: none; } + .land .main { padding: 16px; } } /* ================================================================== identity: tape, section index, marker, live scorer, mode strip */ -.tape { height: 10px; background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } -.tape.thin { height: 6px; } -.tape.run { animation: tape 0.9s linear infinite; } +.land .tape { height: 10px; background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } +.land .tape.thin { height: 6px; } +.land .tape.run { animation: tape 0.9s linear infinite; } @keyframes tape { to { background-position: 45.25px 0; } } -.secno { display: flex; align-items: center; gap: 12px; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 18px; } -.secno::before { content: ""; width: 28px; height: 3px; background: #ffd000; flex: none; } -.dark .secno { color: #adb5bd; } -.mark-hl { background-image: linear-gradient(180deg, transparent 60%, #ffd000 60%, #ffd000 92%, transparent 92%); background-repeat: no-repeat; background-size: 0% 100%; -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: hlin 0.8s var(--ease) 0.7s forwards; } +.land .secno { display: flex; align-items: center; gap: 12px; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.14em; text-transform: uppercase; color: #6c757d; margin-bottom: 18px; } +.land .secno::before { content: ""; width: 28px; height: 3px; background: #ffd000; flex: none; } +.land .dark .secno { color: #adb5bd; } +.land .mark-hl { background-image: linear-gradient(180deg, transparent 60%, #ffd000 60%, #ffd000 92%, transparent 92%); background-repeat: no-repeat; background-size: 0% 100%; -webkit-box-decoration-break: clone; box-decoration-break: clone; animation: hlin 0.8s var(--ease) 0.7s forwards; } @keyframes hlin { to { background-size: 100% 100%; } } -.hero-meta { margin-top: 32px; display: flex; gap: 24px; flex-wrap: wrap; justify-content: center; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: #6c757d; animation: rise 0.7s var(--ease) 0.4s both; } -.hero-meta span { display: inline-flex; align-items: center; gap: 8px; } -.hero-meta span::before { content: ""; width: 8px; height: 3px; background: #ffd000; } +.land .hero-meta { margin-top: 32px; display: flex; gap: 24px; flex-wrap: wrap; justify-content: center; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: #6c757d; animation: rise 0.7s var(--ease) 0.4s both; } +.land .hero-meta span { display: inline-flex; align-items: center; gap: 8px; } +.land .hero-meta span::before { content: ""; width: 8px; height: 3px; background: #ffd000; } -.ticker { background: #212529; color: #fff; border-radius: 8px; box-shadow: 0 30px 80px rgba(33,37,41,0.28); overflow: hidden; font-size: 14px; } -.ticker .head { display: flex; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #343a40; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #adb5bd; } -.ticker .head b { color: #ffd000; font-weight: 500; } -.ticker .body { padding: 20px 18px 16px; display: grid; gap: 14px; } -.ticker .row { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; } -.ticker .row > span:first-child { color: #adb5bd; font-size: 13px; } -.ticker .amt { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.02em; } -.ticker .to { font-family: "DM Mono", monospace; font-size: 12.5px; color: #dee2e6; } -.ticker .prog { height: 6px; background: #343a40; border-radius: 3px; overflow: hidden; } -.ticker .prog i { display: block; height: 100%; background: #ffd000; width: 0; } -.ticker .prog.on i { animation: growx 1.1s var(--ease) both; } -.ticker .prog.done i { width: 100%; } +.land .ticker { background: #212529; color: #fff; border-radius: 8px; box-shadow: 0 30px 80px rgba(33,37,41,0.28); overflow: hidden; font-size: 14px; } +.land .ticker .head { display: flex; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid #343a40; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #adb5bd; } +.land .ticker .head b { color: #ffd000; font-weight: 500; } +.land .ticker .body { padding: 20px 18px 16px; display: grid; gap: 14px; } +.land .ticker .row { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; } +.land .ticker .row > span:first-child { color: #adb5bd; font-size: 13px; } +.land .ticker .amt { font-family: "Space Grotesk", sans-serif; font-size: 30px; font-weight: 700; letter-spacing: -0.02em; } +.land .ticker .to { font-family: "DM Mono", monospace; font-size: 12.5px; color: #dee2e6; } +.land .ticker .prog { height: 6px; background: #343a40; border-radius: 3px; overflow: hidden; } +.land .ticker .prog i { display: block; height: 100%; background: #ffd000; width: 0; } +.land .ticker .prog.on i { animation: growx 1.1s var(--ease) both; } +.land .ticker .prog.done i { width: 100%; } @keyframes growx { from { width: 0; } to { width: 100%; } } -.ticker .verdict { display: flex; align-items: center; gap: 10px; min-height: 34px; flex-wrap: wrap; } -.ticker .tier { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; padding: 7px 10px; border-radius: 4px; font-weight: 500; color: #212529; animation: pop 0.3s var(--ease) both; } -.ticker .tier.low { background: #ffd000; } -.ticker .tier.high { background: #ffa94d; } -.ticker .tier.critical { background: #ea868f; } -.ticker .tier.blocked { background: #fff; } -.ticker .scoring { color: #adb5bd; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; } -.ticker .why { list-style: none; padding: 0; margin: 0; display: grid; gap: 7px; color: #dee2e6; font-size: 13px; min-height: 66px; } -.ticker .why li { animation: rise 0.4s var(--ease) both; padding-left: 18px; position: relative; } -.ticker .why li::before { content: ""; position: absolute; left: 0; top: 8px; width: 9px; height: 3px; background: #ffd000; } -.ticker .foot { padding: 12px 18px; border-top: 1px solid #343a40; font-size: 12px; color: #adb5bd; display: flex; justify-content: space-between; gap: 12px; } -.ticker .dots { display: flex; gap: 6px; } -.ticker .dots i { width: 18px; height: 3px; background: #495057; } -.ticker .dots i.on { background: #ffd000; } -.mode-strip { height: 6px; margin: -20px -24px 16px; background: transparent; transition: background 0.3s; } -.mode-strip.elevated { background: #ffd000; } -.mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } -@media (prefers-reduced-motion: reduce) { .tape.run, .mark-hl, .ticker .prog.on i, .ticker .why li, .ticker .tier { animation: none; } .mark-hl { background-size: 100% 100%; } .ticker .prog.on i { width: 100%; } } +.land .ticker .verdict { display: flex; align-items: center; gap: 10px; min-height: 34px; flex-wrap: wrap; } +.land .ticker .tier { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; padding: 7px 10px; border-radius: 4px; font-weight: 500; color: #212529; animation: pop 0.3s var(--ease) both; } +.land .ticker .tier.low { background: #ffd000; } +.land .ticker .tier.high { background: #ffa94d; } +.land .ticker .tier.critical { background: #ea868f; } +.land .ticker .tier.blocked { background: #fff; } +.land .ticker .scoring { color: #adb5bd; font-family: "DM Mono", monospace; font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; } +.land .ticker .why { list-style: none; padding: 0; margin: 0; display: grid; gap: 7px; color: #dee2e6; font-size: 13px; min-height: 66px; } +.land .ticker .why li { animation: rise 0.4s var(--ease) both; padding-left: 18px; position: relative; } +.land .ticker .why li::before { content: ""; position: absolute; left: 0; top: 8px; width: 9px; height: 3px; background: #ffd000; } +.land .ticker .foot { padding: 12px 18px; border-top: 1px solid #343a40; font-size: 12px; color: #adb5bd; display: flex; justify-content: space-between; gap: 12px; } +.land .ticker .dots { display: flex; gap: 6px; } +.land .ticker .dots i { width: 18px; height: 3px; background: #495057; } +.land .ticker .dots i.on { background: #ffd000; } +.land .mode-strip { height: 6px; margin: -20px -24px 16px; background: transparent; transition: background 0.3s; } +.land .mode-strip.elevated { background: #ffd000; } +.land .mode-strip.tape { background: repeating-linear-gradient(-45deg, #ffd000 0 16px, #212529 16px 32px); background-size: 45.25px 100%; } +@media (prefers-reduced-motion: reduce) { .land .tape.run, .land .mark-hl, .land .ticker .prog.on i, .land .ticker .why li, .land .ticker .tier { animation: none; } .land .mark-hl { background-size: 100% 100%; } .land .ticker .prog.on i { width: 100%; } } /* ================================================================== phone mockups (marketing) Authored at true device scale (393 x 852 points) and scaled as a unit, so the app's own type sizes and spacing survive. --pwn is unitless: calc() dividing two lengths yields a length, which scale() would reject. */ -.phone { --pwn: 268; --scale: calc(var(--pwn) / 417); position: relative; width: calc(var(--pwn) * 1px); height: calc(876px * var(--scale)); flex: none; } -.phone-device { position: absolute; top: 0; left: 0; width: 417px; height: 876px; transform: scale(var(--scale)); transform-origin: top left; background: #0b0d10; border-radius: 58px; padding: 12px; box-shadow: 0 40px 90px rgba(16,20,24,0.3), 0 0 0 1px rgba(255,255,255,0.08) inset; } -.ph-island { position: absolute; top: 24px; left: 50%; transform: translateX(-50%); width: 122px; height: 35px; background: #0b0d10; border-radius: 20px; z-index: 3; } -.phone-screen { position: relative; width: 100%; height: 100%; border-radius: 46px; background: #fff; overflow: hidden; display: flex; flex-direction: column; color: #101418; font-size: 15px; } -.ph-home-ind { position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%); width: 140px; height: 5px; border-radius: 3px; background: #101418; opacity: 0.85; } -.ph-status { height: 56px; padding: 16px 30px 0; display: flex; align-items: center; justify-content: space-between; font-size: 16px; } -.ph-status b { font-family: "DM Sans", sans-serif; font-weight: 700; letter-spacing: -0.2px; } -.ph-status-icons { display: flex; align-items: center; gap: 6px; fill: #101418; color: #101418; } -.ph-body { flex: 1; padding: 6px 16px 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; } +.land .phone { --pwn: 268; --scale: calc(var(--pwn) / 417); position: relative; width: calc(var(--pwn) * 1px); height: calc(876px * var(--scale)); flex: none; } +.land .phone-device { position: absolute; top: 0; left: 0; width: 417px; height: 876px; transform: scale(var(--scale)); transform-origin: top left; background: #0b0d10; border-radius: 58px; padding: 12px; box-shadow: 0 40px 90px rgba(16,20,24,0.3), 0 0 0 1px rgba(255,255,255,0.08) inset; } +.land .ph-island { position: absolute; top: 24px; left: 50%; transform: translateX(-50%); width: 122px; height: 35px; background: #0b0d10; border-radius: 20px; z-index: 3; } +.land .phone-screen { position: relative; width: 100%; height: 100%; border-radius: 46px; background: #fff; overflow: hidden; display: flex; flex-direction: column; color: #101418; font-size: 15px; } +.land .ph-home-ind { position: absolute; bottom: 9px; left: 50%; transform: translateX(-50%); width: 140px; height: 5px; border-radius: 3px; background: #101418; opacity: 0.85; } +.land .ph-status { height: 56px; padding: 16px 30px 0; display: flex; align-items: center; justify-content: space-between; font-size: 16px; } +.land .ph-status b { font-family: "DM Sans", sans-serif; font-weight: 700; letter-spacing: -0.2px; } +.land .ph-status-icons { display: flex; align-items: center; gap: 6px; fill: #101418; color: #101418; } +.land .ph-body { flex: 1; padding: 6px 16px 0; display: flex; flex-direction: column; gap: 10px; overflow: hidden; } -.ph-top { display: flex; align-items: center; gap: 10px; height: 44px; } -.ph-top > b { font-size: 17px; font-weight: 700; } -.ph-ident { position: relative; width: 36px; height: 36px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #7dd3fc, #2ec27e); flex: none; } -.ph-ident i { position: absolute; top: -6px; left: 16px; background: #ffd000; color: #101418; font-style: normal; font-size: 10px; font-weight: 800; border-radius: 8px; padding: 1px 5px; border: 2px solid #fff; } -.ph-caret { color: #98a2b3; font-size: 13px; } -.ph-caret.r { margin-left: auto; } -.ph-top-btns { margin-left: auto; display: flex; gap: 8px; } -.ph-top-btns i { width: 40px; height: 40px; border-radius: 50%; background: #f6f7f9; display: block; position: relative; } -.ph-top-btns i::before { content: ""; position: absolute; inset: 13px; border: 2px solid #101418; border-radius: 3px; -webkit-mask: linear-gradient(#000 0 0) top/100% 4px no-repeat, linear-gradient(#000 0 0) bottom/100% 4px no-repeat, linear-gradient(#000 0 0) left/4px 100% no-repeat, linear-gradient(#000 0 0) right/4px 100% no-repeat; } -.ph-top-btns i.bell::before { inset: 11px 13px 12px; border: 0; background: #101418; -webkit-mask: none; border-radius: 7px 7px 2px 2px; } -.ph-top-btns i.bell::after { content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px; border-radius: 50%; background: #ffd000; } -.ph-pending { display: flex; align-items: center; gap: 10px; background: #fff6cc; color: #8a6d00; border-radius: 14px; padding: 0 14px; height: 48px; font-weight: 700; font-size: 15px; } -.ph-pending .n { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 12px; } -.ph-chain { display: flex; align-items: center; gap: 8px; font-size: 14px; } -.ph-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-size: 13px; } -.ph-ark { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 11px; font-weight: 800; } -.ph-balance { font-family: "Space Grotesk", sans-serif; font-size: 44px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } -.ph-balance small { font-size: 20px; color: #667085; margin-left: 8px; letter-spacing: -0.02em; } -.ph-actions { display: flex; gap: 10px; } -.ph-actions span { flex: 1; height: 48px; display: grid; place-items: center; border-radius: 14px; background: #f6f7f9; font-weight: 700; font-size: 15px; } -.ph-actions .go { background: #ffd000; } -.ph-label { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 4px; } -.ph-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #eceef2; } -.ph-row.last, .ph-card .ph-row:last-child { border-bottom: 0; } -.ph-card { background: #f6f7f9; border-radius: 16px; padding: 0 14px; } -.ph-card.pad { padding: 4px 14px; } -.ph-mark, .ph-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } -.ph-circle { width: 40px; height: 40px; background: #eceef2; font-size: 16px; } -.ph-circle.sm { width: 34px; height: 34px; font-size: 15px; } -.ph-name { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } -.ph-name b { font-size: 15px; font-weight: 700; } -.ph-name small { font-size: 13px; color: #667085; } -.ph-amt { font-size: 15px; font-weight: 700; } -.ph-badge { background: #eceef2; color: #667085; border-radius: 99px; padding: 4px 9px; font-weight: 700; font-size: 12px; } -.ph-badge.warn { background: #fff3d6; color: #a86a00; } -.ph-title { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 700; display: flex; align-items: center; gap: 10px; height: 44px; } -.ph-title.back { font-size: 18px; } -.ph-title .ph-plus { margin-left: auto; width: 40px; height: 40px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 20px; } -.ph-tabsline { display: flex; gap: 22px; border-bottom: 1px solid #eceef2; font-size: 15px; } -.ph-tabsline b { border-bottom: 2px solid #ffd000; padding-bottom: 9px; } -.ph-tabsline span { color: #98a2b3; padding-bottom: 9px; } -.ph-chips { display: flex; gap: 8px; } -.ph-chips b, .ph-chips span { border-radius: 99px; padding: 6px 12px; font-size: 12px; font-weight: 700; background: #f6f7f9; color: #667085; } -.ph-chips b { background: #ffd000; color: #101418; } -.ph-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0 4px; } -.ph-hero-mark { position: relative; } -.ph-hero-mark i { position: absolute; right: -4px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #b42318; color: #fff; font-style: normal; font-size: 12px; display: grid; place-items: center; border: 3px solid #fff; } -.ph-hero b { font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -0.03em; } -.ph-hero small { color: #667085; font-size: 14px; } -.ph-kv { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eceef2; font-size: 14px; } -.ph-kv.last { border-bottom: 0; } -.ph-kv span { color: #667085; } -.ph-sign { margin-top: auto; margin-bottom: 12px; background: #ffd000; border-radius: 16px; height: 56px; padding: 0 18px; display: flex; align-items: center; gap: 10px; font-size: 16px; } -.ph-sign b { font-weight: 700; } -.ph-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 5px 10px; font-family: "DM Mono", monospace; font-size: 12px; } -.ph-tabs { height: 84px; border-top: 1px solid #eceef2; display: flex; align-items: flex-start; padding-top: 14px; } -.ph-tabs span { flex: 1; text-align: center; font-size: 24px; color: #98a2b3; position: relative; } -.ph-tabs span.on { color: #ffd000; } -.ph-tab-badge { position: absolute; top: -4px; left: 55%; background: #ffd000; color: #101418; font-style: normal; font-size: 11px; font-weight: 800; border-radius: 99px; padding: 1px 6px; } -.phones { display: flex; gap: 30px; justify-content: center; align-items: flex-start; flex-wrap: wrap; } -.phones .phone:nth-child(2) { margin-top: -26px; } -@media (max-width: 900px) { .phones .phone:nth-child(2) { margin-top: 0; } .phone { --pwn: 240; } } +.land .ph-top { display: flex; align-items: center; gap: 10px; height: 44px; } +.land .ph-top > b { font-size: 17px; font-weight: 700; } +.land .ph-ident { position: relative; width: 36px; height: 36px; border-radius: 50%; background: conic-gradient(#2ec27e, #d8b4fe, #7dd3fc, #2ec27e); flex: none; } +.land .ph-ident i { position: absolute; top: -6px; left: 16px; background: #ffd000; color: #101418; font-style: normal; font-size: 10px; font-weight: 800; border-radius: 8px; padding: 1px 5px; border: 2px solid #fff; } +.land .ph-caret { color: #98a2b3; font-size: 13px; } +.land .ph-caret.r { margin-left: auto; } +.land .ph-top-btns { margin-left: auto; display: flex; gap: 8px; } +.land .ph-top-btns i { width: 40px; height: 40px; border-radius: 50%; background: #f6f7f9; display: block; position: relative; } +.land .ph-top-btns i::before { content: ""; position: absolute; inset: 13px; border: 2px solid #101418; border-radius: 3px; -webkit-mask: linear-gradient(#000 0 0) top/100% 4px no-repeat, linear-gradient(#000 0 0) bottom/100% 4px no-repeat, linear-gradient(#000 0 0) left/4px 100% no-repeat, linear-gradient(#000 0 0) right/4px 100% no-repeat; } +.land .ph-top-btns i.bell::before { inset: 11px 13px 12px; border: 0; background: #101418; -webkit-mask: none; border-radius: 7px 7px 2px 2px; } +.land .ph-top-btns i.bell::after { content: ""; position: absolute; top: 8px; right: 8px; width: 8px; height: 8px; border-radius: 50%; background: #ffd000; } +.land .ph-pending { display: flex; align-items: center; gap: 10px; background: #fff6cc; color: #8a6d00; border-radius: 14px; padding: 0 14px; height: 48px; font-weight: 700; font-size: 15px; } +.land .ph-pending .n { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 12px; } +.land .ph-chain { display: flex; align-items: center; gap: 8px; font-size: 14px; } +.land .ph-chain small { color: #98a2b3; font-family: "DM Mono", monospace; font-size: 13px; } +.land .ph-ark { width: 22px; height: 22px; border-radius: 50%; background: #ffd000; color: #101418; display: grid; place-items: center; font-size: 11px; font-weight: 800; } +.land .ph-balance { font-family: "Space Grotesk", sans-serif; font-size: 44px; font-weight: 700; letter-spacing: -0.04em; line-height: 1; } +.land .ph-balance small { font-size: 20px; color: #667085; margin-left: 8px; letter-spacing: -0.02em; } +.land .ph-actions { display: flex; gap: 10px; } +.land .ph-actions span { flex: 1; height: 48px; display: grid; place-items: center; border-radius: 14px; background: #f6f7f9; font-weight: 700; font-size: 15px; } +.land .ph-actions .go { background: #ffd000; } +.land .ph-label { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #98a2b3; margin-top: 4px; } +.land .ph-row { display: flex; align-items: center; gap: 12px; padding: 11px 0; border-bottom: 1px solid #eceef2; } +.land .ph-row.last, .land .ph-card .ph-row:last-child { border-bottom: 0; } +.land .ph-card { background: #f6f7f9; border-radius: 16px; padding: 0 14px; } +.land .ph-card.pad { padding: 4px 14px; } +.land .ph-mark, .land .ph-circle { border-radius: 50%; display: grid; place-items: center; flex: none; font-family: "Space Grotesk", sans-serif; font-weight: 700; } +.land .ph-circle { width: 40px; height: 40px; background: #eceef2; font-size: 16px; } +.land .ph-circle.sm { width: 34px; height: 34px; font-size: 15px; } +.land .ph-name { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } +.land .ph-name b { font-size: 15px; font-weight: 700; } +.land .ph-name small { font-size: 13px; color: #667085; } +.land .ph-amt { font-size: 15px; font-weight: 700; } +.land .ph-badge { background: #eceef2; color: #667085; border-radius: 99px; padding: 4px 9px; font-weight: 700; font-size: 12px; } +.land .ph-badge.warn { background: #fff3d6; color: #a86a00; } +.land .ph-title { font-family: "Space Grotesk", sans-serif; font-size: 22px; font-weight: 700; display: flex; align-items: center; gap: 10px; height: 44px; } +.land .ph-title.back { font-size: 18px; } +.land .ph-title .ph-plus { margin-left: auto; width: 40px; height: 40px; border-radius: 50%; background: #ffd000; display: grid; place-items: center; font-size: 20px; } +.land .ph-tabsline { display: flex; gap: 22px; border-bottom: 1px solid #eceef2; font-size: 15px; } +.land .ph-tabsline b { border-bottom: 2px solid #ffd000; padding-bottom: 9px; } +.land .ph-tabsline span { color: #98a2b3; padding-bottom: 9px; } +.land .ph-chips { display: flex; gap: 8px; } +.land .ph-chips b, .land .ph-chips span { border-radius: 99px; padding: 6px 12px; font-size: 12px; font-weight: 700; background: #f6f7f9; color: #667085; } +.land .ph-chips b { background: #ffd000; color: #101418; } +.land .ph-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 8px 0 4px; } +.land .ph-hero-mark { position: relative; } +.land .ph-hero-mark i { position: absolute; right: -4px; top: -4px; width: 24px; height: 24px; border-radius: 50%; background: #b42318; color: #fff; font-style: normal; font-size: 12px; display: grid; place-items: center; border: 3px solid #fff; } +.land .ph-hero b { font-family: "Space Grotesk", sans-serif; font-size: 30px; letter-spacing: -0.03em; } +.land .ph-hero small { color: #667085; font-size: 14px; } +.land .ph-kv { display: flex; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid #eceef2; font-size: 14px; } +.land .ph-kv.last { border-bottom: 0; } +.land .ph-kv span { color: #667085; } +.land .ph-sign { margin-top: auto; margin-bottom: 12px; background: #ffd000; border-radius: 16px; height: 56px; padding: 0 18px; display: flex; align-items: center; gap: 10px; font-size: 16px; } +.land .ph-sign b { font-weight: 700; } +.land .ph-sign .who { margin-left: auto; background: rgba(16,20,24,0.12); border-radius: 99px; padding: 5px 10px; font-family: "DM Mono", monospace; font-size: 12px; } +.land .ph-tabs { height: 84px; border-top: 1px solid #eceef2; display: flex; align-items: flex-start; padding-top: 14px; } +.land .ph-tabs span { flex: 1; text-align: center; font-size: 24px; color: #98a2b3; position: relative; } +.land .ph-tabs span.on { color: #ffd000; } +.land .ph-tab-badge { position: absolute; top: -4px; left: 55%; background: #ffd000; color: #101418; font-style: normal; font-size: 11px; font-weight: 800; border-radius: 99px; padding: 1px 6px; } +.land .phones { display: flex; gap: 30px; justify-content: center; align-items: flex-start; flex-wrap: wrap; } +.land .phones .phone:nth-child(2) { margin-top: -26px; } +@media (max-width: 900px) { .land .phones .phone:nth-child(2) { margin-top: 0; } .land .phone { --pwn: 240; } } /* The landing's mobile strip: copy on the left, two phones on the right, the card sized by both. */ -.mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } -.mstrip h2 { text-align: left; margin-bottom: 16px; } -.mstrip p { color: #6c757d; max-width: 380px; margin-bottom: 26px; } -.mstrip ul { list-style: none; padding: 0; margin: 0 0 26px; display: flex; flex-direction: column; gap: 14px; font-size: 17px; font-weight: 700; color: #212529; } -.mstrip ul li { display: flex; gap: 12px; align-items: center; } -.mstrip ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 24px; height: 24px; flex: none; } -.phones.two { display: flex; gap: 16px; align-items: flex-start; } -.phones.two .phone { --pwn: 196; } -.phones.two .phone:nth-child(2) { margin-top: 30px; } -@media (max-width: 980px) { .mstrip { grid-template-columns: 1fr; } .phones.two { justify-content: center; } .phones.two .phone:nth-child(2) { display: none; } } +.land .mstrip { background: #fff; border: 1px solid #e9ecef; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr auto; gap: 40px; align-items: center; } +.land .mstrip h2 { text-align: left; margin-bottom: 16px; } +.land .mstrip p { color: #6c757d; max-width: 380px; margin-bottom: 26px; } +.land .mstrip ul { list-style: none; padding: 0; margin: 0 0 26px; display: flex; flex-direction: column; gap: 14px; font-size: 17px; font-weight: 700; color: #212529; } +.land .mstrip ul li { display: flex; gap: 12px; align-items: center; } +.land .mstrip ul li svg { color: #212529; background: #ffd000; border-radius: 4px; padding: 3px; width: 24px; height: 24px; flex: none; } +.land .phones.two { display: flex; gap: 16px; align-items: flex-start; } +.land .phones.two .phone { --pwn: 196; } +.land .phones.two .phone:nth-child(2) { margin-top: 30px; } +@media (max-width: 980px) { .land .mstrip { grid-template-columns: 1fr; } .land .phones.two { justify-content: center; } .land .phones.two .phone:nth-child(2) { display: none; } } /* ================================================================== documentation */ -.docs { max-width: 1216px; margin: 0 auto; padding: 0 24px; display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; align-items: start; } -.docs-nav { position: sticky; top: 96px; padding: 40px 0 60px; display: flex; flex-direction: column; gap: 22px; } -.docs-group { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 8px; } -.docs-nav button { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 7px 12px; margin-left: -12px; border-radius: 8px; font: inherit; font-size: 15px; color: #6c757d; cursor: pointer; } -.docs-nav button:hover { background: #f1f3f5; color: #212529; } -.docs-nav button.on { background: #fff6cc; color: #212529; font-weight: 700; } -.docs-body { padding: 40px 0 96px; min-width: 0; } -.docs-crumb { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 12px; } -.docs-body h1 { font-family: "Space Grotesk", sans-serif; font-size: 44px; line-height: 48px; letter-spacing: -0.03em; margin-bottom: 20px; } -.docs-body h3 { font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -0.02em; margin: 40px 0 10px; scroll-margin-top: 96px; } -.docs-body p { font-size: 17px; line-height: 27px; color: #495057; margin-bottom: 16px; max-width: 70ch; } -.docs-body .doc-lead { font-size: 20px; line-height: 30px; color: #212529; margin-bottom: 24px; } -.docs-body ul, .docs-body ol { margin: 0 0 20px 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 26px; color: #495057; max-width: 70ch; } -.docs-body li b { color: #212529; } -.docs-body ol.doc-inv { counter-reset: inv; list-style: none; margin-left: 0; } -.docs-body ol.doc-inv li { counter-increment: inv; padding-left: 40px; position: relative; color: #212529; font-weight: 500; } -.docs-body ol.doc-inv li::before { content: counter(inv); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; border-radius: 6px; background: #ffd000; color: #212529; display: grid; place-items: center; font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; } -.doc-note { border-left: 3px solid #ffd000; background: #fffdf2; padding: 14px 18px; border-radius: 0 8px 8px 0; font-size: 16px; line-height: 25px; color: #495057; margin: 22px 0; max-width: 70ch; } -.doc-table { overflow-x: auto; margin: 0 0 24px; } -.doc-table table { border-collapse: collapse; width: 100%; font-size: 15px; } -.doc-table th { text-align: left; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #98a2b3; font-weight: 400; padding: 0 16px 10px 0; border-bottom: 1px solid #e9ecef; } -.doc-table td { padding: 12px 16px 12px 0; border-bottom: 1px solid #f1f3f5; color: #495057; vertical-align: top; line-height: 23px; } -.doc-table td:first-child { color: #212529; font-weight: 700; white-space: nowrap; } -.doc-table code { font-family: "DM Mono", monospace; font-size: 13px; background: #f1f3f5; padding: 2px 6px; border-radius: 4px; color: #212529; } -.docs-paging { display: flex; justify-content: space-between; gap: 16px; margin-top: 56px; padding-top: 24px; border-top: 1px solid #e9ecef; } -.docs-paging button { background: none; border: 0; font: inherit; font-weight: 700; color: #212529; cursor: pointer; padding: 8px 0; } -.docs-paging button:hover { color: #6c757d; } +.land .docs { max-width: 1216px; margin: 0 auto; padding: 0 24px; display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 56px; align-items: start; } +.land .docs-nav { position: sticky; top: 96px; padding: 40px 0 60px; display: flex; flex-direction: column; gap: 22px; } +.land .docs-group { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 8px; } +.land .docs-nav button { display: block; width: 100%; text-align: left; background: none; border: 0; padding: 7px 12px; margin-left: -12px; border-radius: 8px; font: inherit; font-size: 15px; color: #6c757d; cursor: pointer; } +.land .docs-nav button:hover { background: #f1f3f5; color: #212529; } +.land .docs-nav button.on { background: #fff6cc; color: #212529; font-weight: 700; } +.land .docs-body { padding: 40px 0 96px; min-width: 0; } +.land .docs-crumb { font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: #98a2b3; margin-bottom: 12px; } +.land .docs-body h1 { font-family: "Space Grotesk", sans-serif; font-size: 44px; line-height: 48px; letter-spacing: -0.03em; margin-bottom: 20px; } +.land .docs-body h3 { font-family: "Space Grotesk", sans-serif; font-size: 22px; letter-spacing: -0.02em; margin: 40px 0 10px; scroll-margin-top: 96px; } +.land .docs-body p { font-size: 17px; line-height: 27px; color: #495057; margin-bottom: 16px; max-width: 70ch; } +.land .docs-body .doc-lead { font-size: 20px; line-height: 30px; color: #212529; margin-bottom: 24px; } +.land .docs-body ul, .land .docs-body ol { margin: 0 0 20px 22px; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 17px; line-height: 26px; color: #495057; max-width: 70ch; } +.land .docs-body li b { color: #212529; } +.land .docs-body ol.doc-inv { counter-reset: inv; list-style: none; margin-left: 0; } +.land .docs-body ol.doc-inv li { counter-increment: inv; padding-left: 40px; position: relative; color: #212529; font-weight: 500; } +.land .docs-body ol.doc-inv li::before { content: counter(inv); position: absolute; left: 0; top: 1px; width: 26px; height: 26px; border-radius: 6px; background: #ffd000; color: #212529; display: grid; place-items: center; font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; } +.land .doc-note { border-left: 3px solid #ffd000; background: #fffdf2; padding: 14px 18px; border-radius: 0 8px 8px 0; font-size: 16px; line-height: 25px; color: #495057; margin: 22px 0; max-width: 70ch; } +.land .doc-table { overflow-x: auto; margin: 0 0 24px; } +.land .doc-table table { border-collapse: collapse; width: 100%; font-size: 15px; } +.land .doc-table th { text-align: left; font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: #98a2b3; font-weight: 400; padding: 0 16px 10px 0; border-bottom: 1px solid #e9ecef; } +.land .doc-table td { padding: 12px 16px 12px 0; border-bottom: 1px solid #f1f3f5; color: #495057; vertical-align: top; line-height: 23px; } +.land .doc-table td:first-child { color: #212529; font-weight: 700; white-space: nowrap; } +.land .doc-table code { font-family: "DM Mono", monospace; font-size: 13px; background: #f1f3f5; padding: 2px 6px; border-radius: 4px; color: #212529; } +.land .docs-paging { display: flex; justify-content: space-between; gap: 16px; margin-top: 56px; padding-top: 24px; border-top: 1px solid #e9ecef; } +.land .docs-paging button { background: none; border: 0; font: inherit; font-weight: 700; color: #212529; cursor: pointer; padding: 8px 0; } +.land .docs-paging button:hover { color: #6c757d; } @media (max-width: 900px) { - .docs { grid-template-columns: 1fr; gap: 0; } - .docs-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 24px 0 0; } - .docs-nav > div { display: contents; } - .docs-group { display: none; } - .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } - .docs-body h1 { font-size: 34px; line-height: 38px; } + .land .docs { grid-template-columns: 1fr; gap: 0; } + .land .docs-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; padding: 24px 0 0; } + .land .docs-nav > div { display: contents; } + .land .docs-group { display: none; } + .land .docs-nav button { width: auto; margin: 0; border: 1px solid #e9ecef; font-size: 14px; } + .land .docs-body h1 { font-size: 34px; line-height: 38px; } } /* ================================================================== the phone: the mobile app as artwork */ -.mock-phone { width: 272px; border-radius: 42px; background: #0b0d0f; padding: 10px; border: 1px solid #343a40; box-shadow: 0 30px 60px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.3); } -.mock-phone .mp-screen { border-radius: 33px; overflow: hidden; background: #212529; color: #f8f9fa; font-size: 11px; padding: 10px 12px 0; display: flex; flex-direction: column; gap: 10px; min-height: 480px; } -.mp-status { display: flex; align-items: center; justify-content: space-between; color: #adb5bd; font-weight: 700; font-size: 10px; } -.mp-island { width: 64px; height: 16px; border-radius: 10px; background: #0b0d0f; } -.mp-head { display: flex; align-items: center; gap: 8px; font-size: 15px; letter-spacing: -0.01em; padding-top: 2px; } -.mp-card { background: #2b3035; border-radius: 14px; padding: 12px; display: flex; flex-direction: column; gap: 8px; } -.mp-label { color: #6c757d; font-size: 9px; letter-spacing: 1px; font-weight: 700; display: flex; justify-content: space-between; align-items: center; } -.mp-ok { color: #75b798; font-weight: 700; letter-spacing: 0; } -.mp-rv { color: #ffcd39; font-weight: 700; } -.mp-donut { width: 128px; height: 128px; border-radius: 50%; margin: 6px auto; background: conic-gradient(#ffd000 0 100%); display: grid; place-items: center; } -.mp-donut > div { width: 92px; height: 92px; border-radius: 50%; background: #2b3035; display: flex; flex-direction: column; align-items: center; justify-content: center; } -.mp-donut b { font-size: 22px; letter-spacing: -0.02em; } -.mp-donut span { color: #adb5bd; font-size: 10px; } -.mp-tiles { display: flex; gap: 8px; } -.mp-tile { flex: 1; background: #2b3035; border-radius: 12px; padding: 10px; display: flex; flex-direction: column; gap: 2px; } -.mp-tile b { font-size: 18px; } -.mp-tile span { color: #adb5bd; font-size: 10px; } -.mp-list .mp-row { display: flex; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid #343a40; } -.mp-list .mp-row:first-of-type { border-top: 0; } -.mp-shield { font-size: 30px; } -.mp-meter { height: 6px; border-radius: 3px; background: #343a40; overflow: hidden; margin-top: 4px; } -.mp-meter i { display: block; height: 6px; border-radius: 3px; background: #ffd000; } -.mp-btn { border-radius: 10px; padding: 10px; text-align: center; font-weight: 800; } -.mp-btn-soft { background: #343a40; color: #ffcd39; } -.mp-btn-danger { background: #4a1c22; color: #ea868f; } -.mp-tabs { margin-top: auto; display: flex; justify-content: space-between; gap: 2px; border-top: 1px solid #343a40; padding: 9px 2px 12px; color: #6c757d; font-size: 8.5px; font-weight: 700; } -.mp-tabs .on { color: #ffd000; } +.land .mock-phone { width: 272px; border-radius: 42px; background: #0b0d0f; padding: 10px; border: 1px solid #343a40; box-shadow: 0 30px 60px rgba(0, 0, 0, 0.45), 0 4px 12px rgba(0, 0, 0, 0.3); } +.land .mock-phone .mp-screen { border-radius: 33px; overflow: hidden; background: #212529; color: #f8f9fa; font-size: 11px; padding: 10px 12px 0; display: flex; flex-direction: column; gap: 10px; min-height: 480px; } +.land .mp-status { display: flex; align-items: center; justify-content: space-between; color: #adb5bd; font-weight: 700; font-size: 10px; } +.land .mp-island { width: 64px; height: 16px; border-radius: 10px; background: #0b0d0f; } +.land .mp-head { display: flex; align-items: center; gap: 8px; font-size: 15px; letter-spacing: -0.01em; padding-top: 2px; } +.land .mp-card { background: #2b3035; border-radius: 14px; padding: 12px; display: flex; flex-direction: column; gap: 8px; } +.land .mp-label { color: #6c757d; font-size: 9px; letter-spacing: 1px; font-weight: 700; display: flex; justify-content: space-between; align-items: center; } +.land .mp-ok { color: #75b798; font-weight: 700; letter-spacing: 0; } +.land .mp-rv { color: #ffcd39; font-weight: 700; } +.land .mp-donut { width: 128px; height: 128px; border-radius: 50%; margin: 6px auto; background: conic-gradient(#ffd000 0 100%); display: grid; place-items: center; } +.land .mp-donut > div { width: 92px; height: 92px; border-radius: 50%; background: #2b3035; display: flex; flex-direction: column; align-items: center; justify-content: center; } +.land .mp-donut b { font-size: 22px; letter-spacing: -0.02em; } +.land .mp-donut span { color: #adb5bd; font-size: 10px; } +.land .mp-tiles { display: flex; gap: 8px; } +.land .mp-tile { flex: 1; background: #2b3035; border-radius: 12px; padding: 10px; display: flex; flex-direction: column; gap: 2px; } +.land .mp-tile b { font-size: 18px; } +.land .mp-tile span { color: #adb5bd; font-size: 10px; } +.land .mp-list .mp-row { display: flex; justify-content: space-between; gap: 8px; padding: 7px 0; border-top: 1px solid #343a40; } +.land .mp-list .mp-row:first-of-type { border-top: 0; } +.land .mp-shield { font-size: 30px; } +.land .mp-meter { height: 6px; border-radius: 3px; background: #343a40; overflow: hidden; margin-top: 4px; } +.land .mp-meter i { display: block; height: 6px; border-radius: 3px; background: #ffd000; } +.land .mp-btn { border-radius: 10px; padding: 10px; text-align: center; font-weight: 800; } +.land .mp-btn-soft { background: #343a40; color: #ffcd39; } +.land .mp-btn-danger { background: #4a1c22; color: #ea868f; } +.land .mp-tabs { margin-top: auto; display: flex; border-top: 1px solid #343a40; padding: 9px 0 12px; color: #6c757d; font-size: 8px; font-weight: 700; } .land .mp-tabs span { flex: 1; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.land .mp-tabs .on { color: #ffd000; } /* in the hero, the phone leans on the desktop mock */ -.mockwrap { position: relative; } -.float-phone { position: absolute; right: -18px; bottom: -34px; transform: rotate(4deg); z-index: 3; } -@media (max-width: 1100px) { .float-phone { display: none; } } +.land .mockwrap { position: relative; } +.land .float-phone { position: absolute; left: -40px; bottom: -40px; transform: rotate(-4deg); z-index: 3; filter: drop-shadow(0 24px 40px rgba(33, 37, 41, 0.35)); } +@media (max-width: 1100px) { .land .float-phone { display: none; } } /* in the audience cards, it stands alone */ -.art-phone { display: flex; justify-content: center; padding: 18px 0 6px; } -.art-phone .mock-phone { transform: rotate(-2deg); } +.land .art-phone { display: flex; justify-content: center; padding: 18px 0 6px; } +.land .art-phone .mock-phone { transform: rotate(-2deg); } From 65735c3a1045f4d727e29ebb49dffd0bf481ce0a Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:20:38 +0100 Subject: [PATCH 42/44] fix(web): the firewall shield panel carries its own ink A dark panel inside a light section inherited the page's near-black text, so its heading and checklist vanished into the ground. The panel now declares its own foreground, like every other dark panel on the page already did. --- app/src/marketing/styles.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/marketing/styles.css b/app/src/marketing/styles.css index 77fce1d..3bc25a3 100644 --- a/app/src/marketing/styles.css +++ b/app/src/marketing/styles.css @@ -576,8 +576,9 @@ .land .dashed p { color: #adb5bd; } .land .badges { display: flex; gap: 40px; justify-content: center; align-items: center; flex-wrap: wrap; padding: 40px 0; border-top: 1px solid #343a40; color: #adb5bd; font-weight: 700; font-size: 18px; } .land .badges .lbl { font-weight: 400; font-size: 14px; } -.land .shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; } -.land .shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; } +/* A dark panel inside a light section: it must carry its own ink, or it inherits the page's near-black and the words vanish into the ground. */ +.land .shield { background: #2b3035; border: 1px solid #343a40; border-radius: 8px; padding: 48px; display: grid; grid-template-columns: 1fr 1.2fr; gap: 40px; align-items: center; overflow: hidden; color: #f8f9fa; } +.land .shield h2 { text-align: left; font-size: 40px; margin-bottom: 16px; color: #fff; } .land .shield p { color: #adb5bd; margin-bottom: 32px; max-width: 320px; } .land .shield ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 16px; font-size: 20px; font-weight: 700; } .land .shield ul li { display: flex; gap: 12px; align-items: center; } From a60517b5e5f74fc865212af7fca52ff1c355a513 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:33:05 +0100 Subject: [PATCH 43/44] =?UTF-8?q?fix(web):=20no=20more=20blank=20page=20fr?= =?UTF-8?q?om=20the=20dapp=20=E2=80=94=20CORS,=20an=20error=20boundary,=20?= =?UTF-8?q?and=20an=20address-vs-vault=20hint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things conspired to turn a wallet click into a blank page: - The indexer API sent no CORS headers, so every browser fetch for 'your vaults' died in preflight and the UI fell back to 'the indexer is not reachable' — which is what pushed people to paste an id into Open-by-id in the first place. The API now allows the browser origin (everything it serves is public chain state). - A vault id names the shared vault object, not a wallet address, but the two look alike. Pasting an account address led to a vault page that threw on a missing object with no guard, and the whole route unmounted to white. The read error now says exactly that. - Both dapp routes are wrapped in an error boundary, so any render crash lands as a readable panel instead of a blank page. Typecheck clean, 23 pages build. --- app/src/app/(dapp)/app/page.tsx | 7 ++-- app/src/app/(dapp)/vault/[id]/page.tsx | 7 ++-- app/src/app/VaultApp.tsx | 5 +++ app/src/components/Boundary.tsx | 48 ++++++++++++++++++++++++++ server/src/api.ts | 14 ++++++++ 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 app/src/components/Boundary.tsx diff --git a/app/src/app/(dapp)/app/page.tsx b/app/src/app/(dapp)/app/page.tsx index c08114c..ef1b690 100644 --- a/app/src/app/(dapp)/app/page.tsx +++ b/app/src/app/(dapp)/app/page.tsx @@ -2,6 +2,7 @@ import dynamic from 'next/dynamic'; import { Providers } from '@/app/providers'; +import { Boundary } from '@/components/Boundary'; // Wallet detection needs a browser, so nothing in the app tree is server-rendered. const HomeApp = dynamic(() => import('@/app/HomeApp'), { @@ -11,8 +12,10 @@ const HomeApp = dynamic(() => import('@/app/HomeApp'), { export default function Page() { return ( - + + - + + ); } diff --git a/app/src/app/(dapp)/vault/[id]/page.tsx b/app/src/app/(dapp)/vault/[id]/page.tsx index ae2360b..b9106b4 100644 --- a/app/src/app/(dapp)/vault/[id]/page.tsx +++ b/app/src/app/(dapp)/vault/[id]/page.tsx @@ -3,6 +3,7 @@ import dynamic from 'next/dynamic'; import { useParams } from 'next/navigation'; import { Providers } from '@/app/providers'; +import { Boundary } from '@/components/Boundary'; const VaultApp = dynamic(() => import('@/app/VaultApp'), { ssr: false, @@ -13,8 +14,10 @@ export default function Page() { const params = useParams<{ id: string }>(); const id = Array.isArray(params.id) ? params.id[0] : params.id; return ( - + + - + + ); } diff --git a/app/src/app/VaultApp.tsx b/app/src/app/VaultApp.tsx index 4426711..54cab7a 100644 --- a/app/src/app/VaultApp.tsx +++ b/app/src/app/VaultApp.tsx @@ -50,6 +50,11 @@ export default function VaultApp({ vaultId }: { vaultId: string }) { ) : query.error ? ( Could not read that vault. Check the id and the network. +

      + A vault id names the shared vault object — it is not a wallet address, even though the + two look alike. If you pasted your account address, go back and open one of your + vaults instead, or create one. +

      {query.error instanceof Error ? query.error.message : String(query.error)}

      diff --git a/app/src/components/Boundary.tsx b/app/src/components/Boundary.tsx new file mode 100644 index 0000000..aac500c --- /dev/null +++ b/app/src/components/Boundary.tsx @@ -0,0 +1,48 @@ +'use client'; + +import React from 'react'; + +/** + * The last line against a white screen. Anything that throws during render inside the dapp tree + * lands here as a readable panel with the actual message — never a blank page. Nothing was + * signed: a render crash happens on this machine, after reads, before any wallet prompt. + */ +export class Boundary extends React.Component< + { children: React.ReactNode }, + { error: Error | null } +> { + state = { error: null as Error | null }; + + static getDerivedStateFromError(error: Error) { + return { error }; + } + + componentDidCatch(error: Error, info: React.ErrorInfo) { + console.error('dapp render crashed', error, info.componentStack); + } + + render() { + if (!this.state.error) return this.props.children; + return ( +
      +
      +

      Something broke while drawing this page

      +

      + Nothing was signed and nothing left any vault — this is a display error on your + machine. Reloading usually clears it. +

      +

      + {this.state.error.message} +

      + +
      +
      + ); + } +} diff --git a/server/src/api.ts b/server/src/api.ts index c71a910..16a1bf8 100644 --- a/server/src/api.ts +++ b/server/src/api.ts @@ -42,6 +42,20 @@ export function makeApi() { const app = express(); app.use(express.json()); + // Everything this API serves is public chain state read back out of the indexer; the browser + // is a first-class client. Without these headers every fetch from the web app dies in CORS + // preflight and the UI degrades to "the indexer is not reachable". + app.use((req, res, next) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); + if (req.method === 'OPTIONS') { + res.status(204).end(); + return; + } + next(); + }); + app.get('/health', wrap(async (_req, res) => { const { rows } = await pool.query<{ cursor: string | null; events_seen: string; last_event_at: Date | null }>( `SELECT cursor, events_seen, last_event_at FROM indexer_cursor WHERE network = $1`, From bb3d976f787efcf468b0b631f436b19bb14d9180 Mon Sep 17 00:00:00 2001 From: Olajumoke Emmanuel <41354996+Emmyhack@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:42:00 +0100 Subject: [PATCH 44/44] feat(web): publish the package from the browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The not-configured dead end becomes a working door. When no package exists on the active network, both dapp pages now offer to publish it with the connected wallet: the compiled modules (sui move build --dump-bytecode-as-base64, served beside the app, gitignored) ride an ordinary transaction, the sender pays the storage, and the UpgradeCap lands in the publisher's wallet — whoever publishes holds the upgrade rights, explicitly. No CLI, no faucet access on the serving machine. Typecheck clean, 23 pages build. --- app/.gitignore | 1 + app/src/app/HomeApp.tsx | 8 +- app/src/app/VaultApp.tsx | 6 +- app/src/components/PublishPackage.tsx | 115 ++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 app/.gitignore create mode 100644 app/src/components/PublishPackage.tsx diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..d78052c --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +public/skur-bytecode.json diff --git a/app/src/app/HomeApp.tsx b/app/src/app/HomeApp.tsx index 9b5e755..80809c0 100644 --- a/app/src/app/HomeApp.tsx +++ b/app/src/app/HomeApp.tsx @@ -7,6 +7,7 @@ import { MODE_LABELS, describeRoles } from '@skur/sdk'; import { API_URL, CONFIGURED, KNOWN_VAULTS, NETWORK } from '@/config'; import { useMyVaults, useVaultTx } from '@/hooks/useVault'; import { CreateVault } from '@/components/CreateVault'; +import { PublishPackage } from '@/components/PublishPackage'; import { Shell } from '@/components/Shell'; import { Addr, Notice } from '@/components/ui'; @@ -129,12 +130,7 @@ export default function HomeApp() {
      ) : null} - {!CONFIGURED ? ( - - No package is published for {NETWORK} yet. Run{' '} - sui/scripts/publish.sh {NETWORK}. - - ) : null} + {!CONFIGURED ? : null} )} diff --git a/app/src/app/VaultApp.tsx b/app/src/app/VaultApp.tsx index 54cab7a..0104b23 100644 --- a/app/src/app/VaultApp.tsx +++ b/app/src/app/VaultApp.tsx @@ -8,6 +8,7 @@ import { useVaultTx, useVaultView } from '@/hooks/useVault'; import { Overview } from '@/components/Overview'; import { People } from '@/components/People'; import { PolicyPanel } from '@/components/PolicyPanel'; +import { PublishPackage } from '@/components/PublishPackage'; import { Queue } from '@/components/Queue'; import { Security } from '@/components/Security'; import { Send } from '@/components/Send'; @@ -41,10 +42,7 @@ export default function VaultApp({ vaultId }: { vaultId: string }) { }))} > {!CONFIGURED ? ( - - No package is configured for this network. Publish the Move package and set{' '} - NEXT_PUBLIC_SKUR_PACKAGE_ID. - + ) : query.isLoading ? (
      Reading the vault…
      ) : query.error ? ( diff --git a/app/src/components/PublishPackage.tsx b/app/src/components/PublishPackage.tsx new file mode 100644 index 0000000..593564c --- /dev/null +++ b/app/src/components/PublishPackage.tsx @@ -0,0 +1,115 @@ +'use client'; + +import { useCurrentAccount } from '@mysten/dapp-kit-react'; +import { Transaction } from '@mysten/sui/transactions'; +import { useState } from 'react'; +import { dAppKit } from '@/dapp-kit'; +import { NETWORK } from '@/config'; +import { Notice } from '@/components/ui'; + +/** + * Publish the Move package from the browser, signed by the connected wallet. + * + * Publishing is an ordinary transaction: the compiled modules ride in the payload and the sender + * pays the storage. The bytecode is produced by `sui move build --dump-bytecode-as-base64` and + * served next to the app, so getting a network live needs nothing but a funded wallet — no CLI, + * no faucet gymnastics on the machine that runs the web app. The UpgradeCap lands in the + * publisher's wallet: whoever publishes holds the upgrade rights, explicitly. + */ +type Dump = { modules: string[]; dependencies: string[] }; +type State = + | { phase: 'idle' } + | { phase: 'busy' } + | { phase: 'done'; digest: string; packageId: string | null } + | { phase: 'error'; message: string }; + +export function PublishPackage() { + const account = useCurrentAccount(); + const [state, setState] = useState({ phase: 'idle' }); + + const publish = async () => { + if (!account) return; + setState({ phase: 'busy' }); + try { + const res = await fetch('/skur-bytecode.json'); + if (!res.ok) throw new Error('the compiled package is not being served next to this app'); + const dump = (await res.json()) as Dump; + + const tx = new Transaction(); + const cap = tx.publish({ modules: dump.modules, dependencies: dump.dependencies }); + tx.transferObjects([cap], account.address); + + const result = await dAppKit.signAndExecuteTransaction({ transaction: tx }); + if ('FailedTransaction' in result && result.FailedTransaction) { + throw new Error( + result.FailedTransaction.status?.error?.message ?? 'the network refused the publish', + ); + } + const executed = (result as { Transaction: { digest: string; effects?: unknown } }).Transaction; + + // The package id, when the effects carry it; the chain is authoritative either way. + let packageId: string | null = null; + const effects = executed.effects as + | { changedObjects?: { objectId?: string; id?: string; idOperation?: string; outputOwner?: unknown; objectType?: string }[] } + | undefined; + for (const c of effects?.changedObjects ?? []) { + if (c.idOperation === 'Created' && (c.objectType === 'package' || c.outputOwner === undefined)) { + packageId = c.objectId ?? c.id ?? null; + break; + } + } + setState({ phase: 'done', digest: executed.digest, packageId }); + } catch (e) { + const message = e instanceof Error ? e.message : String(e); + setState({ + phase: 'error', + message: /reject|denied|dismiss/i.test(message) ? 'The wallet declined it. Nothing was published.' : message, + }); + } + }; + + if (state.phase === 'done') { + return ( + + Published to {NETWORK}. Digest {state.digest} + {state.packageId ? ( + <> + {' '}· package {state.packageId} + + ) : null} +

      + Set NEXT_PUBLIC_SKUR_PACKAGE_ID to the package id and + restart the app. The UpgradeCap is in your wallet. +

      +
      + ); + } + + return ( +
      +

      No package on {NETWORK} yet

      +

      + The Skur Move package has not been published to this network. Your connected wallet can do + it right here — publishing is a transaction like any other, and costs a fraction of a SUI + in storage. The upgrade rights land in your wallet. +

      + {!account ? ( +

      Connect a wallet first.

      + ) : ( + + )} + {state.phase === 'error' ? ( +
      + {state.message} +
      + ) : null} +
      + ); +}