@www.hyperlinks.space/program-kit 1.2.91881 → 7.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/.eas/workflows/create-development-builds.yml +21 -0
  2. package/.eas/workflows/create-draft.yml +15 -0
  3. package/.eas/workflows/deploy-to-production.yml +68 -0
  4. package/.env.example +19 -0
  5. package/.gitattributes +48 -0
  6. package/.gitignore +52 -0
  7. package/.nvmrc +1 -0
  8. package/.vercelignore +6 -0
  9. package/README.md +10 -5
  10. package/ai/openai.ts +202 -0
  11. package/ai/transmitter.ts +367 -0
  12. package/api/{base.ts → _base.ts} +1 -1
  13. package/api/wallet/_auth.ts +143 -0
  14. package/api/wallet/register.ts +151 -0
  15. package/api/wallet/status.ts +89 -0
  16. package/app/index.tsx +319 -5
  17. package/assets/images/PreviewImage.png +0 -0
  18. package/backlogs/medium_term_backlog.md +26 -0
  19. package/backlogs/short_term_backlog.md +42 -0
  20. package/database/start.ts +0 -1
  21. package/database/wallets.ts +266 -0
  22. package/eslint.config.cjs +10 -0
  23. package/fullREADME.md +142 -71
  24. package/index.js +3 -0
  25. package/npmReadMe.md +10 -5
  26. package/npmrc.example +1 -0
  27. package/package.json +7 -27
  28. package/polyfills/buffer.ts +9 -0
  29. package/research & docs/auth-and-centralized-encrypted-keys-plan.md +440 -0
  30. package/research & docs/github-gitlab-bidirectional-mirroring.md +154 -0
  31. package/research & docs/keys-retrieval-console-scripts.js +131 -0
  32. package/{docs/security_plan_raw.md → research & docs/security_plan_raw.md } +1 -1
  33. package/{docs/security_raw.md → research & docs/security_raw.md } +22 -13
  34. package/research & docs/storage-availability-console-script.js +152 -0
  35. package/research & docs/storage-lifetime.md +33 -0
  36. package/research & docs/telegram-raw-keys-cloud-storage-risks.md +31 -0
  37. package/{docs/wallets_hosting_architecture.md → research & docs/wallets_hosting_architecture.md } +147 -1
  38. package/scripts/test-api-base.ts +2 -2
  39. package/services/wallet/tonWallet.ts +73 -0
  40. package/telegram/post.ts +44 -8
  41. package/ui/components/GlobalBottomBar.tsx +447 -0
  42. package/ui/components/GlobalBottomBarWeb.tsx +362 -0
  43. package/ui/components/GlobalLogoBar.tsx +108 -0
  44. package/ui/components/GlobalLogoBarFallback.tsx +66 -0
  45. package/ui/components/GlobalLogoBarWithFallback.tsx +24 -0
  46. package/ui/components/HyperlinksSpaceLogo.tsx +29 -0
  47. package/ui/components/Telegram.tsx +677 -0
  48. package/ui/components/telegramWebApp.ts +359 -0
  49. package/ui/fonts.ts +12 -0
  50. package/ui/theme.ts +117 -0
  51. /package/{docs → research & docs}/ai_and_search_bar_input.md +0 -0
  52. /package/{docs → research & docs}/ai_bot_messages.md +0 -0
  53. /package/{docs → research & docs}/blue_bar_tackling.md +0 -0
  54. /package/{docs → research & docs}/bot_async_streaming.md +0 -0
  55. /package/{docs → research & docs}/build_and_install.md +0 -0
  56. /package/{docs → research & docs}/database_messages.md +0 -0
  57. /package/{docs → research & docs}/fonts.md +0 -0
  58. /package/{docs → research & docs}/npm-release.md +0 -0
  59. /package/{docs → research & docs}/releases.md +0 -0
  60. /package/{docs → research & docs}/releases_github_actions.md +0 -0
  61. /package/{docs → research & docs}/scalability.md +0 -0
  62. /package/{docs → research & docs}/timing_raw.md +0 -0
  63. /package/{docs → research & docs}/tma_logo_bar_jump_investigation.md +0 -0
  64. /package/{docs → research & docs}/update.md +0 -0
  65. /package/{docs → research & docs}/wallet_telegram_standalone_multichain_proposal.md +0 -0
@@ -0,0 +1,89 @@
1
+ import { getDefaultWalletByUsername } from '../../database/wallets.js';
2
+ import { upsertUserFromTma } from '../../database/users.js';
3
+ import { authByInitData } from './_auth.js';
4
+
5
+ const JSON_HEADERS = { 'Content-Type': 'application/json' };
6
+
7
+ function jsonResponse(body: object, status: number): Response {
8
+ return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
9
+ }
10
+
11
+ async function getBody(
12
+ request:
13
+ | Request
14
+ | {
15
+ json?: () => Promise<unknown>;
16
+ body?: unknown;
17
+ },
18
+ ): Promise<unknown> {
19
+ if (typeof (request as { json?: () => Promise<unknown> }).json === 'function') {
20
+ return (request as Request).json();
21
+ }
22
+ return (request as { body?: unknown }).body ?? null;
23
+ }
24
+
25
+ async function handler(request: Request): Promise<Response> {
26
+ const method = (request as { method?: string }).method ?? request.method;
27
+ if (method === 'GET') {
28
+ return jsonResponse(
29
+ { ok: true, endpoint: 'wallet/status', use: 'POST with initData' },
30
+ 200,
31
+ );
32
+ }
33
+ if (method !== 'POST') {
34
+ return new Response('Method Not Allowed', { status: 405 });
35
+ }
36
+
37
+ const body = (await getBody(request)) as { initData?: unknown } | null;
38
+ const initData = typeof body?.initData === 'string' ? body.initData : '';
39
+ if (!initData) return jsonResponse({ ok: false, error: 'missing_initData' }, 400);
40
+
41
+ try {
42
+ const auth = authByInitData(initData);
43
+ await upsertUserFromTma({
44
+ telegramUsername: auth.telegramUsername,
45
+ locale: auth.locale,
46
+ });
47
+
48
+ const wallet = await getDefaultWalletByUsername(auth.telegramUsername);
49
+ if (!wallet) {
50
+ return jsonResponse(
51
+ {
52
+ ok: true,
53
+ telegram_username: auth.telegramUsername,
54
+ has_wallet: false,
55
+ wallet_required: true,
56
+ },
57
+ 200,
58
+ );
59
+ }
60
+
61
+ return jsonResponse(
62
+ {
63
+ ok: true,
64
+ telegram_username: auth.telegramUsername,
65
+ has_wallet: true,
66
+ wallet: {
67
+ id: wallet.id,
68
+ wallet_address: wallet.wallet_address,
69
+ wallet_blockchain: wallet.wallet_blockchain,
70
+ wallet_net: wallet.wallet_net,
71
+ type: wallet.type,
72
+ label: wallet.label,
73
+ is_default: wallet.is_default,
74
+ source: wallet.source,
75
+ },
76
+ },
77
+ 200,
78
+ );
79
+ } catch (err) {
80
+ const msg = err instanceof Error ? err.message : 'internal_error';
81
+ const status = msg === 'bot_token_not_configured' ? 500 : msg === 'invalid_initdata' ? 401 : 400;
82
+ return jsonResponse({ ok: false, error: msg }, status);
83
+ }
84
+ }
85
+
86
+ export default handler;
87
+ export const GET = handler;
88
+ export const POST = handler;
89
+
package/app/index.tsx CHANGED
@@ -1,8 +1,288 @@
1
- import { Text, View } from "react-native";
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { Button, Text, View } from "react-native";
2
3
  import { useTelegram } from "../ui/components/Telegram";
4
+ import {
5
+ createSeedCipher,
6
+ deriveAddressFromMnemonic,
7
+ deriveMasterKeyFromMnemonic,
8
+ generateMnemonic,
9
+ } from "../services/wallet/tonWallet";
10
+
11
+ type CreateStep = "idle" | "saving" | "done";
12
+
13
+ type TelegramWebAppBridge = {
14
+ SecureStorage?: {
15
+ setItem?: (key: string, value: string, callback?: (err: unknown, stored?: boolean) => void) => void;
16
+ };
17
+ DeviceStorage?: {
18
+ setItem?: (key: string, value: string, callback?: (err: unknown, stored?: boolean) => void) => void;
19
+ };
20
+ CloudStorage?: {
21
+ setItem?: (key: string, value: string, callback?: (err: unknown, stored?: boolean) => void) => void;
22
+ };
23
+ onEvent?: (eventType: string, callback: (...args: unknown[]) => void) => void;
24
+ offEvent?: (eventType: string, callback: (...args: unknown[]) => void) => void;
25
+ };
26
+
27
+ function getTelegramWebApp(): TelegramWebAppBridge | undefined {
28
+ if (typeof window === "undefined") return undefined;
29
+ return (window as unknown as { Telegram?: { WebApp?: TelegramWebAppBridge } }).Telegram?.WebApp;
30
+ }
31
+
32
+ /**
33
+ * SecureStorage.setItem: on error the first callback argument is the error; on success it is null
34
+ * and the second is whether the value was stored. Some clients also emit web events; see
35
+ * https://core.telegram.org/bots/webapps#securestorage
36
+ */
37
+ async function setTmaSecureStorageItem(key: string, value: string): Promise<boolean> {
38
+ const webApp = getTelegramWebApp();
39
+ if (!webApp) return false;
40
+ const storage = webApp.SecureStorage;
41
+ const setItem = storage?.setItem;
42
+ if (typeof setItem !== "function") return false;
43
+
44
+ return new Promise<boolean>((resolve) => {
45
+ let settled = false;
46
+ const finish = (ok: boolean) => {
47
+ if (settled) return;
48
+ settled = true;
49
+ cleanup();
50
+ resolve(ok);
51
+ };
52
+
53
+ const onSecureStorageFailed = (payload?: unknown) => {
54
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
55
+ console.warn("[wallet] secure_storage_failed", payload);
56
+ }
57
+ finish(false);
58
+ };
59
+
60
+ /** Fired when a value was saved (bridge may deliver this if the JS callback is delayed). */
61
+ const onSecureStorageKeySaved = () => {
62
+ finish(true);
63
+ };
64
+
65
+ const cleanup = () => {
66
+ try {
67
+ webApp.offEvent?.("secure_storage_failed", onSecureStorageFailed);
68
+ } catch {
69
+ /* ignore */
70
+ }
71
+ try {
72
+ webApp.offEvent?.("secure_storage_key_saved", onSecureStorageKeySaved);
73
+ } catch {
74
+ /* ignore */
75
+ }
76
+ };
77
+
78
+ try {
79
+ webApp.onEvent?.("secure_storage_failed", onSecureStorageFailed);
80
+ webApp.onEvent?.("secure_storage_key_saved", onSecureStorageKeySaved);
81
+ } catch {
82
+ /* older clients */
83
+ }
84
+
85
+ try {
86
+ setItem(key, value, (err: unknown, stored?: boolean) => {
87
+ if (err != null) {
88
+ finish(false);
89
+ return;
90
+ }
91
+ finish(stored !== false);
92
+ });
93
+ } catch {
94
+ cleanup();
95
+ resolve(false);
96
+ }
97
+ });
98
+ }
99
+
100
+ /**
101
+ * DeviceStorage: persistent local KV inside the Telegram client (not Keychain/Keystore).
102
+ * Same callback shape as SecureStorage; some clients emit device_storage_* web events.
103
+ * @see https://core.telegram.org/bots/webapps#devicestorage
104
+ */
105
+ async function setTmaDeviceStorageItem(key: string, value: string): Promise<boolean> {
106
+ const webApp = getTelegramWebApp();
107
+ if (!webApp) return false;
108
+ const storage = webApp.DeviceStorage;
109
+ const setItem = storage?.setItem;
110
+ if (typeof setItem !== "function") return false;
111
+
112
+ return new Promise<boolean>((resolve) => {
113
+ let settled = false;
114
+ const finish = (ok: boolean) => {
115
+ if (settled) return;
116
+ settled = true;
117
+ cleanup();
118
+ resolve(ok);
119
+ };
120
+
121
+ const onDeviceStorageFailed = (payload?: unknown) => {
122
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
123
+ console.warn("[wallet] device_storage_failed", payload);
124
+ }
125
+ finish(false);
126
+ };
127
+
128
+ const onDeviceStorageKeySaved = () => {
129
+ finish(true);
130
+ };
131
+
132
+ const cleanup = () => {
133
+ try {
134
+ webApp.offEvent?.("device_storage_failed", onDeviceStorageFailed);
135
+ } catch {
136
+ /* ignore */
137
+ }
138
+ try {
139
+ webApp.offEvent?.("device_storage_key_saved", onDeviceStorageKeySaved);
140
+ } catch {
141
+ /* ignore */
142
+ }
143
+ };
144
+
145
+ try {
146
+ webApp.onEvent?.("device_storage_failed", onDeviceStorageFailed);
147
+ webApp.onEvent?.("device_storage_key_saved", onDeviceStorageKeySaved);
148
+ } catch {
149
+ /* older clients */
150
+ }
151
+
152
+ try {
153
+ setItem(key, value, (err: unknown, stored?: boolean) => {
154
+ if (err != null) {
155
+ finish(false);
156
+ return;
157
+ }
158
+ finish(stored !== false);
159
+ });
160
+ } catch {
161
+ cleanup();
162
+ resolve(false);
163
+ }
164
+ });
165
+ }
166
+
167
+ export type WalletMasterKeyStorageTier = "secure" | "device" | "none";
168
+
169
+ /**
170
+ * Prefer hardware-backed SecureStorage; if missing or UNSUPPORTED, fall back to DeviceStorage
171
+ * so Desktop and older clients can still persist the key (weaker — see docs/security_raw.md).
172
+ */
173
+ async function persistWalletMasterKey(masterKey: string): Promise<WalletMasterKeyStorageTier> {
174
+ const okSecure = await setTmaSecureStorageItem("wallet_master_key", masterKey);
175
+ if (okSecure) return "secure";
176
+
177
+ const okDevice = await setTmaDeviceStorageItem("wallet_master_key", masterKey);
178
+ if (okDevice) return "device";
179
+
180
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
181
+ console.warn("[wallet] wallet_master_key not persisted (no SecureStorage nor DeviceStorage)");
182
+ }
183
+ return "none";
184
+ }
185
+
186
+ /** CloudStorage.setItem uses the same callback shape as SecureStorage. */
187
+ async function setTmaCloudStorageItem(key: string, value: string): Promise<boolean> {
188
+ const webApp = getTelegramWebApp();
189
+ const storage = webApp?.CloudStorage;
190
+ const setItem = storage?.setItem;
191
+ if (typeof setItem !== "function") return false;
192
+
193
+ return new Promise<boolean>((resolve) => {
194
+ try {
195
+ setItem(key, value, (err: unknown, stored?: boolean) => {
196
+ if (err != null) {
197
+ resolve(false);
198
+ return;
199
+ }
200
+ resolve(stored !== false);
201
+ });
202
+ } catch {
203
+ resolve(false);
204
+ }
205
+ });
206
+ }
3
207
 
4
208
  export default function Index() {
5
- const { status, telegramUsername, error, debug } = useTelegram();
209
+ const {
210
+ status,
211
+ telegramUsername,
212
+ hasWallet,
213
+ walletRequired,
214
+ wallet,
215
+ initData,
216
+ error,
217
+ debug,
218
+ } = useTelegram();
219
+ const [step, setStep] = useState<CreateStep>("idle");
220
+ const [flowError, setFlowError] = useState<string | null>(null);
221
+ const [createdWalletAddress, setCreatedWalletAddress] = useState<string | null>(null);
222
+ const [masterKeyStorageTier, setMasterKeyStorageTier] = useState<WalletMasterKeyStorageTier | null>(null);
223
+ const effectiveWalletAddress = wallet?.wallet_address ?? createdWalletAddress;
224
+ const effectiveHasWallet = hasWallet || Boolean(createdWalletAddress);
225
+
226
+ const createAndRegisterWalletFlow = useCallback(async () => {
227
+ if (!initData) {
228
+ setFlowError("Missing Telegram initData.");
229
+ return;
230
+ }
231
+ setFlowError(null);
232
+ setStep("saving");
233
+ try {
234
+ const mnemonic = await generateMnemonic();
235
+ const walletAddress = await deriveAddressFromMnemonic({ mnemonic, testnet: false });
236
+ const masterKey = await deriveMasterKeyFromMnemonic(mnemonic);
237
+ const seedCipher = await createSeedCipher(masterKey, mnemonic.join(" "));
238
+
239
+ // Register with API first: SecureStorage can fail/hang (see secure_storage_failed) and must not block.
240
+ const response = await fetch("/api/wallet/register", {
241
+ method: "POST",
242
+ headers: { "Content-Type": "application/json" },
243
+ body: JSON.stringify({
244
+ initData,
245
+ wallet_address: walletAddress,
246
+ wallet_blockchain: "ton",
247
+ wallet_net: "mainnet",
248
+ type: "internal",
249
+ label: "Main wallet",
250
+ source: "miniapp",
251
+ }),
252
+ });
253
+ const json = await response.json().catch(() => ({}));
254
+ if (!response.ok || !json?.ok) {
255
+ throw new Error(json?.error || `HTTP ${response.status}`);
256
+ }
257
+ const [tier, cloudOk] = await Promise.all([
258
+ persistWalletMasterKey(masterKey),
259
+ setTmaCloudStorageItem("wallet_seed_cipher", seedCipher),
260
+ ]);
261
+ setMasterKeyStorageTier(tier);
262
+ if (!cloudOk && typeof __DEV__ !== "undefined" && __DEV__) {
263
+ console.warn("[wallet] wallet_seed_cipher not saved to CloudStorage");
264
+ }
265
+
266
+ setCreatedWalletAddress(walletAddress);
267
+ setStep("done");
268
+ } catch (e) {
269
+ setFlowError(e instanceof Error ? e.message : "Wallet registration failed");
270
+ setStep("idle");
271
+ }
272
+ }, [initData]);
273
+
274
+ useEffect(() => {
275
+ if (
276
+ status === "ok" &&
277
+ walletRequired &&
278
+ !hasWallet &&
279
+ !createdWalletAddress &&
280
+ step === "idle" &&
281
+ initData
282
+ ) {
283
+ void createAndRegisterWalletFlow();
284
+ }
285
+ }, [status, walletRequired, hasWallet, createdWalletAddress, step, initData, createAndRegisterWalletFlow]);
6
286
 
7
287
  if (status === "idle" || status === "loading") {
8
288
  return (
@@ -79,6 +359,21 @@ export default function Index() {
79
359
  );
80
360
  }
81
361
 
362
+ if (status === "ok" && walletRequired && !effectiveHasWallet) {
363
+ return (
364
+ <View style={{ flex: 1, justifyContent: "center", padding: 16, gap: 10 }}>
365
+ <Text style={{ fontWeight: "700", fontSize: 18 }}>Preparing your wallet</Text>
366
+ <Text>
367
+ No wallet found for this Telegram account. Creating one now and registering public wallet
368
+ data.
369
+ </Text>
370
+ {step === "saving" && <Text>Saving secrets and registering wallet...</Text>}
371
+ {flowError ? <Text style={{ color: "#b00020" }}>{flowError}</Text> : null}
372
+ {flowError ? <Button title="Retry wallet creation" onPress={createAndRegisterWalletFlow} /> : null}
373
+ </View>
374
+ );
375
+ }
376
+
82
377
  return (
83
378
  <View
84
379
  style={{
@@ -91,11 +386,30 @@ export default function Index() {
91
386
  <Text style={{ fontWeight: "600", marginBottom: 8 }}>
92
387
  HyperlinksSpace Wallet
93
388
  </Text>
94
- {telegramUsername && (
95
- <Text style={{ textAlign: "center" }}>
389
+ {telegramUsername ? (
390
+ <Text style={{ textAlign: "center", marginBottom: 8 }}>
96
391
  You are logged in via Telegram as @{telegramUsername}.
97
392
  </Text>
98
- )}
393
+ ) : null}
394
+ {effectiveWalletAddress ? (
395
+ <View style={{ alignItems: "center" }}>
396
+ <Text style={{ textAlign: "center" }}>Wallet:</Text>
397
+ <Text style={{ textAlign: "center", marginTop: 4 }}>{effectiveWalletAddress}</Text>
398
+ </View>
399
+ ) : null}
400
+ {masterKeyStorageTier === "device" ? (
401
+ <Text style={{ marginTop: 14, fontSize: 12, color: "#856404", textAlign: "center", paddingHorizontal: 8 }}>
402
+ This Telegram client does not support SecureStorage, so your wallet key was stored in DeviceStorage
403
+ (persistent app storage, not the system keychain). That is weaker than SecureStorage; keep your seed
404
+ phrase safe and prefer Telegram on iOS/Android when possible.
405
+ </Text>
406
+ ) : null}
407
+ {masterKeyStorageTier === "none" ? (
408
+ <Text style={{ marginTop: 14, fontSize: 12, color: "#b00020", textAlign: "center", paddingHorizontal: 8 }}>
409
+ Could not save your wallet key on this device. Cloud ciphertext may still sync, but you will need your
410
+ recovery phrase to sign here until storage works. Try another Telegram client or update the app.
411
+ </Text>
412
+ ) : null}
99
413
  </View>
100
414
  );
101
415
  }
Binary file
@@ -0,0 +1,26 @@
1
+ header indent bag in fullsize<br>
2
+ rotation on swap page<br>
3
+ edit interval healthcheck<br>
4
+ Ticker link<br>
5
+ Scrolling in AI widget fix<br>
6
+ Finish bot parts isolation<br>
7
+ ld timeout<br>
8
+ AI bd<br>
9
+ Hovers<br>
10
+ Languages<br>
11
+ Favicon change<br>
12
+ Wallet creation and nickname generation<br>
13
+ Jetton lockup<br>
14
+ Theme in Chrome<br>
15
+ Bd<br>
16
+ Wallet creation<br>
17
+ Apps design<br>
18
+ Plan users bd for search<br>
19
+ Brand book<br>
20
+ Fix<br>
21
+ Starting Rewards<br>
22
+ Feed items types<br>
23
+ PAY BY QR<br>
24
+ swap long rate state<br>
25
+ swaps<br>
26
+ tokns<br>
@@ -0,0 +1,42 @@
1
+ Polyfils refactoring<br>
2
+ Wallet: Telegram, Connected, Unhosted<br>
3
+ Username loaded without intermediate state<br>
4
+ Bottom bar refactor<br>
5
+ AI options page<br>
6
+ Bottom bar icon review<br>
7
+ AI chat page<br>
8
+ Bring repository root app to demo design state<br>
9
+ GitHub and GitLab bidirectional mirroring<br>
10
+ readme.md<br>
11
+ Windows setup refactor<br>
12
+ https://azure.microsoft.com/en-us/products/artifact-signing<br>
13
+ README.md: Project news, discussions, where to learn for contributions<br>
14
+
15
+ Issues:<br>
16
+ Several chats async streaming<br>
17
+
18
+ Pull requests:<br>
19
+ AI responce checkup in bot (message interruption on new prompt)<br>
20
+ Typing in the middle of the text on large inputting<br>
21
+
22
+ To think about:<br>
23
+ Branding and naming
24
+ Place of the install update dialog in the UI<br>
25
+ Updater: fasten instant reload<br>
26
+ Custom installer design<br>
27
+ Fluent installer progress bar<br>
28
+ Optional cleanup of legacy Forge v5 deps<br>
29
+ Workflows dry mode (build check without releasing)<br>
30
+ Move Telegram folder contents to API<br>
31
+ https://www.npmjs.com/package/electron-log<br>
32
+ PGP release signing<br>
33
+ File's formats and folders structure<br>
34
+ Selection and pointing text detalization<br>
35
+ on word tapping places at the end of the word<br>
36
+ zoom-in cursor placing on long tap<br>
37
+ Instructions.ts in AI<br>
38
+
39
+ Abandoned:<br>
40
+ Placeholder refactor<br>
41
+ Logo bar visibility<br>
42
+ Overlay on screen expansion from mobile<br>
package/database/start.ts CHANGED
@@ -30,7 +30,6 @@ async function runSchemaMigrations() {
30
30
  last_tma_seen_at TIMESTAMPTZ,
31
31
  locale TEXT,
32
32
  time_zone TEXT,
33
- number_of_wallets INTEGER NOT NULL DEFAULT 0,
34
33
  default_wallet BIGINT
35
34
  );
36
35
  `;