From 9217b385737203020e5ff3cbf06dbcee28f9fb56 Mon Sep 17 00:00:00 2001 From: Jose Miguel Navarro Date: Tue, 24 Jun 2025 18:59:17 +0900 Subject: [PATCH 01/10] add chain to safe table and add chain to filters safes --- packages/web/drizzle/0046_red_raza.sql | 3 + packages/web/drizzle/meta/0046_snapshot.json | 2376 +++++++++++++++++ packages/web/drizzle/meta/_journal.json | 7 + packages/web/src/db/schema.ts | 5 +- packages/web/src/hooks/use-user-safes.ts | 4 +- .../src/server/routers/settings/user-safes.ts | 15 +- 6 files changed, 2404 insertions(+), 6 deletions(-) create mode 100644 packages/web/drizzle/0046_red_raza.sql create mode 100644 packages/web/drizzle/meta/0046_snapshot.json diff --git a/packages/web/drizzle/0046_red_raza.sql b/packages/web/drizzle/0046_red_raza.sql new file mode 100644 index 000000000..8a239f31c --- /dev/null +++ b/packages/web/drizzle/0046_red_raza.sql @@ -0,0 +1,3 @@ +ALTER TABLE "user_requests" ALTER COLUMN "id" SET DEFAULT '04b5c64e-42a0-4ed3-a683-86942f144795';--> statement-breakpoint +ALTER TABLE "user_safes" ALTER COLUMN "safe_address" SET DATA TYPE varchar(44);--> statement-breakpoint +ALTER TABLE "user_safes" ADD COLUMN "safe_chain" text DEFAULT 'ethereum' NOT NULL; \ No newline at end of file diff --git a/packages/web/drizzle/meta/0046_snapshot.json b/packages/web/drizzle/meta/0046_snapshot.json new file mode 100644 index 000000000..19344c3e7 --- /dev/null +++ b/packages/web/drizzle/meta/0046_snapshot.json @@ -0,0 +1,2376 @@ +{ + "id": "22c30d9b-f9fe-46bf-bfbc-db4c1f078f98", + "prevId": "b8a2bede-4867-4bfc-988a-eeef1f2e8de1", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.action_ledger": { + "name": "action_ledger", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "approved_by": { + "name": "approved_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inbox_card_id": { + "name": "inbox_card_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action_title": { + "name": "action_title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "action_subtitle": { + "name": "action_subtitle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action_type": { + "name": "action_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_details": { + "name": "source_details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "impact_data": { + "name": "impact_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "amount": { + "name": "amount", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "confidence": { + "name": "confidence", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rationale": { + "name": "rationale", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "chain_of_thought": { + "name": "chain_of_thought", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "original_card_data": { + "name": "original_card_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "parsed_invoice_data": { + "name": "parsed_invoice_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'approved'" + }, + "execution_details": { + "name": "execution_details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "executed_at": { + "name": "executed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "action_ledger_approved_by_idx": { + "name": "action_ledger_approved_by_idx", + "columns": [ + { + "expression": "approved_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "action_ledger_action_type_idx": { + "name": "action_ledger_action_type_idx", + "columns": [ + { + "expression": "action_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "action_ledger_source_type_idx": { + "name": "action_ledger_source_type_idx", + "columns": [ + { + "expression": "source_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "action_ledger_status_idx": { + "name": "action_ledger_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "action_ledger_approved_at_idx": { + "name": "action_ledger_approved_at_idx", + "columns": [ + { + "expression": "approved_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "action_ledger_approved_by_users_privy_did_fk": { + "name": "action_ledger_approved_by_users_privy_did_fk", + "tableFrom": "action_ledger", + "tableTo": "users", + "columnsFrom": [ + "approved_by" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.allocation_states": { + "name": "allocation_states", + "schema": "", + "columns": { + "user_safe_id": { + "name": "user_safe_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_checked_usdc_balance": { + "name": "last_checked_usdc_balance", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "total_deposited": { + "name": "total_deposited", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "allocated_tax": { + "name": "allocated_tax", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "allocated_liquidity": { + "name": "allocated_liquidity", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "allocated_yield": { + "name": "allocated_yield", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "pending_deposit_amount": { + "name": "pending_deposit_amount", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_updated": { + "name": "last_updated", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "allocation_states_user_safe_id_user_safes_id_fk": { + "name": "allocation_states_user_safe_id_user_safes_id_fk", + "tableFrom": "allocation_states", + "tableTo": "user_safes", + "columnsFrom": [ + "user_safe_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "allocation_states_user_safe_id_pk": { + "name": "allocation_states_user_safe_id_pk", + "columns": [ + "user_safe_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.allocation_strategies": { + "name": "allocation_strategies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_did": { + "name": "user_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destination_safe_type": { + "name": "destination_safe_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "percentage": { + "name": "percentage", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_strategy_type_unique_idx": { + "name": "user_strategy_type_unique_idx", + "columns": [ + { + "expression": "user_did", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "destination_safe_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "allocation_strategies_user_did_users_privy_did_fk": { + "name": "allocation_strategies_user_did_users_privy_did_fk", + "tableFrom": "allocation_strategies", + "tableTo": "users", + "columnsFrom": [ + "user_did" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.auto_earn_configs": { + "name": "auto_earn_configs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_did": { + "name": "user_did", + "type": "varchar(66)", + "primaryKey": false, + "notNull": true + }, + "safe_address": { + "name": "safe_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + }, + "pct": { + "name": "pct", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "last_trigger": { + "name": "last_trigger", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "auto_earn_user_safe_unique_idx": { + "name": "auto_earn_user_safe_unique_idx", + "columns": [ + { + "expression": "user_did", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "safe_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat_messages": { + "name": "chat_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parts": { + "name": "parts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "attachments": { + "name": "attachments", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tool_result": { + "name": "tool_result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "chat_messages_chat_id_idx": { + "name": "chat_messages_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "chat_messages_role_idx": { + "name": "chat_messages_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_messages_chat_id_chats_id_fk": { + "name": "chat_messages_chat_id_chats_id_fk", + "tableFrom": "chat_messages", + "tableTo": "chats", + "columnsFrom": [ + "chat_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chats": { + "name": "chats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'private'" + }, + "share_path": { + "name": "share_path", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "chats_user_id_idx": { + "name": "chats_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "chats_share_path_idx": { + "name": "chats_share_path_idx", + "columns": [ + { + "expression": "share_path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chats_user_id_users_privy_did_fk": { + "name": "chats_user_id_users_privy_did_fk", + "tableFrom": "chats", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "chats_share_path_unique": { + "name": "chats_share_path_unique", + "nullsNotDistinct": false, + "columns": [ + "share_path" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.earn_deposits": { + "name": "earn_deposits", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(255)", + "primaryKey": true, + "notNull": true + }, + "user_did": { + "name": "user_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "safe_address": { + "name": "safe_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + }, + "vault_address": { + "name": "vault_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + }, + "token_address": { + "name": "token_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": true + }, + "assets_deposited": { + "name": "assets_deposited", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "shares_received": { + "name": "shares_received", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "tx_hash": { + "name": "tx_hash", + "type": "varchar(66)", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "earn_safe_address_idx": { + "name": "earn_safe_address_idx", + "columns": [ + { + "expression": "safe_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "earn_vault_address_idx": { + "name": "earn_vault_address_idx", + "columns": [ + { + "expression": "vault_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "earn_user_did_idx": { + "name": "earn_user_did_idx", + "columns": [ + { + "expression": "user_did", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "earn_deposits_user_did_users_privy_did_fk": { + "name": "earn_deposits_user_did_users_privy_did_fk", + "tableFrom": "earn_deposits", + "tableTo": "users", + "columnsFrom": [ + "user_did" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "earn_deposits_tx_hash_unique": { + "name": "earn_deposits_tx_hash_unique", + "nullsNotDistinct": false, + "columns": [ + "tx_hash" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gmail_oauth_tokens": { + "name": "gmail_oauth_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_privy_did": { + "name": "user_privy_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expiry_date": { + "name": "expiry_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "gmail_oauth_tokens_user_did_idx": { + "name": "gmail_oauth_tokens_user_did_idx", + "columns": [ + { + "expression": "user_privy_did", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "gmail_oauth_tokens_user_privy_did_users_privy_did_fk": { + "name": "gmail_oauth_tokens_user_privy_did_users_privy_did_fk", + "tableFrom": "gmail_oauth_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_privy_did" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.inbox_cards": { + "name": "inbox_cards", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "card_id": { + "name": "card_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subtitle": { + "name": "subtitle", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "confidence": { + "name": "confidence", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "blocked": { + "name": "blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "snoozed_time": { + "name": "snoozed_time", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_ai_suggestion_pending": { + "name": "is_ai_suggestion_pending", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "requires_action": { + "name": "requires_action", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "suggested_action_label": { + "name": "suggested_action_label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "amount": { + "name": "amount", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "from_entity": { + "name": "from_entity", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "to_entity": { + "name": "to_entity", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "log_id": { + "name": "log_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rationale": { + "name": "rationale", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code_hash": { + "name": "code_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chain_of_thought": { + "name": "chain_of_thought", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "impact": { + "name": "impact", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "parsed_invoice_data": { + "name": "parsed_invoice_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source_details": { + "name": "source_details", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "comments": { + "name": "comments", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "suggested_update": { + "name": "suggested_update", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "inbox_cards_user_id_idx": { + "name": "inbox_cards_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_cards_status_idx": { + "name": "inbox_cards_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_cards_source_type_idx": { + "name": "inbox_cards_source_type_idx", + "columns": [ + { + "expression": "source_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_cards_timestamp_idx": { + "name": "inbox_cards_timestamp_idx", + "columns": [ + { + "expression": "timestamp", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_cards_confidence_idx": { + "name": "inbox_cards_confidence_idx", + "columns": [ + { + "expression": "confidence", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_cards_card_id_idx": { + "name": "inbox_cards_card_id_idx", + "columns": [ + { + "expression": "card_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "inbox_cards_user_id_users_privy_did_fk": { + "name": "inbox_cards_user_id_users_privy_did_fk", + "tableFrom": "inbox_cards", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "inbox_cards_card_id_unique": { + "name": "inbox_cards_card_id_unique", + "nullsNotDistinct": false, + "columns": [ + "card_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_states": { + "name": "oauth_states", + "schema": "", + "columns": { + "state": { + "name": "state", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_privy_did": { + "name": "user_privy_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'gmail'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_states_user_did_idx": { + "name": "oauth_states_user_did_idx", + "columns": [ + { + "expression": "user_privy_did", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_states_provider_idx": { + "name": "oauth_states_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.offramp_transfers": { + "name": "offramp_transfers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "align_transfer_id": { + "name": "align_transfer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "amount_to_send": { + "name": "amount_to_send", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destination_currency": { + "name": "destination_currency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "destination_payment_rails": { + "name": "destination_payment_rails", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination_bank_account_id": { + "name": "destination_bank_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "destination_bank_account_snapshot": { + "name": "destination_bank_account_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "deposit_amount": { + "name": "deposit_amount", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deposit_token": { + "name": "deposit_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deposit_network": { + "name": "deposit_network", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deposit_address": { + "name": "deposit_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fee_amount": { + "name": "fee_amount", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quote_expires_at": { + "name": "quote_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "transaction_hash": { + "name": "transaction_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_op_hash": { + "name": "user_op_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "offramp_transfers_user_id_idx": { + "name": "offramp_transfers_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "offramp_transfers_align_id_idx": { + "name": "offramp_transfers_align_id_idx", + "columns": [ + { + "expression": "align_transfer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "offramp_transfers_user_id_users_privy_did_fk": { + "name": "offramp_transfers_user_id_users_privy_did_fk", + "tableFrom": "offramp_transfers", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "offramp_transfers_destination_bank_account_id_user_destination_bank_accounts_id_fk": { + "name": "offramp_transfers_destination_bank_account_id_user_destination_bank_accounts_id_fk", + "tableFrom": "offramp_transfers", + "tableTo": "user_destination_bank_accounts", + "columnsFrom": [ + "destination_bank_account_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "offramp_transfers_align_transfer_id_unique": { + "name": "offramp_transfers_align_transfer_id_unique", + "nullsNotDistinct": false, + "columns": [ + "align_transfer_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_destination_bank_accounts": { + "name": "user_destination_bank_accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_name": { + "name": "account_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bank_name": { + "name": "bank_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_holder_type": { + "name": "account_holder_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_holder_first_name": { + "name": "account_holder_first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_holder_last_name": { + "name": "account_holder_last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_holder_business_name": { + "name": "account_holder_business_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "city": { + "name": "city", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "street_line_1": { + "name": "street_line_1", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "street_line_2": { + "name": "street_line_2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "postal_code": { + "name": "postal_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_type": { + "name": "account_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_number": { + "name": "account_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "routing_number": { + "name": "routing_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "iban_number": { + "name": "iban_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bic_swift": { + "name": "bic_swift", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_dest_bank_accounts_user_id_idx": { + "name": "user_dest_bank_accounts_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_destination_bank_accounts_user_id_users_privy_did_fk": { + "name": "user_destination_bank_accounts_user_id_users_privy_did_fk", + "tableFrom": "user_destination_bank_accounts", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_funding_sources": { + "name": "user_funding_sources", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_privy_did": { + "name": "user_privy_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_provider": { + "name": "source_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "align_virtual_account_id_ref": { + "name": "align_virtual_account_id_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_account_type": { + "name": "source_account_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_currency": { + "name": "source_currency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_bank_name": { + "name": "source_bank_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_bank_address": { + "name": "source_bank_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_bank_beneficiary_name": { + "name": "source_bank_beneficiary_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_bank_beneficiary_address": { + "name": "source_bank_beneficiary_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_iban": { + "name": "source_iban", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_bic_swift": { + "name": "source_bic_swift", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_routing_number": { + "name": "source_routing_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_account_number": { + "name": "source_account_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_sort_code": { + "name": "source_sort_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_payment_rail": { + "name": "source_payment_rail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_payment_rails": { + "name": "source_payment_rails", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "destination_currency": { + "name": "destination_currency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination_payment_rail": { + "name": "destination_payment_rail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination_address": { + "name": "destination_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_funding_sources_user_did_idx": { + "name": "user_funding_sources_user_did_idx", + "columns": [ + { + "expression": "user_privy_did", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_funding_sources_user_privy_did_users_privy_did_fk": { + "name": "user_funding_sources_user_privy_did_users_privy_did_fk", + "tableFrom": "user_funding_sources", + "tableTo": "users", + "columnsFrom": [ + "user_privy_did" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_profiles": { + "name": "user_profiles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "privy_did": { + "name": "privy_did", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "payment_address": { + "name": "payment_address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "primary_safe_address": { + "name": "primary_safe_address", + "type": "varchar(42)", + "primaryKey": false, + "notNull": false + }, + "business_name": { + "name": "business_name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": false + }, + "default_wallet_id": { + "name": "default_wallet_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "skipped_or_completed_onboarding_stepper": { + "name": "skipped_or_completed_onboarding_stepper", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_profiles_default_wallet_id_user_wallets_id_fk": { + "name": "user_profiles_default_wallet_id_user_wallets_id_fk", + "tableFrom": "user_profiles", + "tableTo": "user_wallets", + "columnsFrom": [ + "default_wallet_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_profiles_privy_did_unique": { + "name": "user_profiles_privy_did_unique", + "nullsNotDistinct": false, + "columns": [ + "privy_did" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_requests": { + "name": "user_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "default": "'04b5c64e-42a0-4ed3-a683-86942f144795'" + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wallet_address": { + "name": "wallet_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "amount": { + "name": "amount", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "currency_decimals": { + "name": "currency_decimals", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'db_pending'" + }, + "client": { + "name": "client", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "invoice_data": { + "name": "invoice_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_safes": { + "name": "user_safes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_did": { + "name": "user_did", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "safe_address": { + "name": "safe_address", + "type": "varchar(44)", + "primaryKey": false, + "notNull": true + }, + "safe_type": { + "name": "safe_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "safe_chain": { + "name": "safe_chain", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'ethereum'" + }, + "is_earn_module_enabled": { + "name": "is_earn_module_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_safe_type_unique_idx": { + "name": "user_safe_type_unique_idx", + "columns": [ + { + "expression": "user_did", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "safe_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_safes_user_did_users_privy_did_fk": { + "name": "user_safes_user_did_users_privy_did_fk", + "tableFrom": "user_safes", + "tableTo": "users", + "columnsFrom": [ + "user_did" + ], + "columnsTo": [ + "privy_did" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_wallets": { + "name": "user_wallets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "network": { + "name": "network", + "type": "varchar(50)", + "primaryKey": false, + "notNull": true, + "default": "'gnosis'" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_wallets_address_unique": { + "name": "user_wallets_address_unique", + "nullsNotDistinct": false, + "columns": [ + "address" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "privy_did": { + "name": "privy_did", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "align_customer_id": { + "name": "align_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kyc_provider": { + "name": "kyc_provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kyc_status": { + "name": "kyc_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'none'" + }, + "kyc_flow_link": { + "name": "kyc_flow_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "align_virtual_account_id": { + "name": "align_virtual_account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kyc_marked_done": { + "name": "kyc_marked_done", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "kyc_sub_status": { + "name": "kyc_sub_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "loops_contact_synced": { + "name": "loops_contact_synced", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_align_customer_id_unique": { + "name": "users_align_customer_id_unique", + "nullsNotDistinct": false, + "columns": [ + "align_customer_id" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/web/drizzle/meta/_journal.json b/packages/web/drizzle/meta/_journal.json index 18c27d0bd..7f8e43c98 100644 --- a/packages/web/drizzle/meta/_journal.json +++ b/packages/web/drizzle/meta/_journal.json @@ -323,6 +323,13 @@ "when": 1749415215239, "tag": "0045_yellow_lionheart", "breakpoints": true + }, + { + "idx": 46, + "version": "7", + "when": 1750758671304, + "tag": "0046_red_raza", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/web/src/db/schema.ts b/packages/web/src/db/schema.ts index 78e06fc43..5c8056ded 100644 --- a/packages/web/src/db/schema.ts +++ b/packages/web/src/db/schema.ts @@ -118,8 +118,9 @@ export const users = pgTable('users', { export const userSafes = pgTable('user_safes', { id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()), // Unique ID for the safe record userDid: text('user_did').notNull().references(() => users.privyDid), // Foreign key to users table - safeAddress: varchar('safe_address', { length: 42 }).notNull(), // Ethereum address (42 chars) - safeType: text('safe_type', { enum: ['primary', 'tax', 'liquidity', 'yield'] }).notNull(), // Type of Safe + safeAddress: varchar('safe_address', { length: 44 }).notNull(), // Ethereum address (42 chars) + safeType: text('safe_type', { enum: ['primary', 'other', 'tax', 'liquidity', 'yield'] }).notNull(), // Type of Safe + safeChain: text('safe_chain', { enum: ['ethereum', 'solana'] }).notNull().default('ethereum'), // Chain the Safe is on isEarnModuleEnabled: boolean('is_earn_module_enabled').default(false).notNull(), // Tracks if the earn module is enabled createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(), }, (table) => { diff --git a/packages/web/src/hooks/use-user-safes.ts b/packages/web/src/hooks/use-user-safes.ts index d96be57bb..f2fdd1aed 100644 --- a/packages/web/src/hooks/use-user-safes.ts +++ b/packages/web/src/hooks/use-user-safes.ts @@ -36,12 +36,12 @@ const fetchUserSafes = async (getAccessToken: () => Promise): Pro }; // The React Query hook using tRPC -export const useUserSafes = () => { +export const useUserSafes = (chain?: 'ethereum' | 'solana') => { const { authenticated } = usePrivy(); // Only need auth state now // Use the tRPC query hook with the correct path return trpc.settings.userSafes.list.useQuery( - undefined, // No input required for the list procedure + { chain }, { enabled: authenticated, // Only run query if user is authenticated // queryKey is managed by tRPC, but you can customize if needed diff --git a/packages/web/src/server/routers/settings/user-safes.ts b/packages/web/src/server/routers/settings/user-safes.ts index 4cc45cd96..e1c8cd3d2 100644 --- a/packages/web/src/server/routers/settings/user-safes.ts +++ b/packages/web/src/server/routers/settings/user-safes.ts @@ -30,14 +30,25 @@ export const userSafesRouter = router({ /** * Fetches all safes associated with the authenticated user. */ - list: protectedProcedure.query(async ({ ctx }) => { + list: protectedProcedure + .input( + z.object({ + chain: z.enum(['ethereum', 'solana']).optional(), // Optional chain filter + }) + ) + .query(async ({ ctx, input }) => { const privyDid = ctx.user.id; // Use ctx.user.id from isAuthed middleware console.log(`Fetching safes for user DID: ${privyDid}`); try { // Use the imported 'db' directly const safes = await db.query.userSafes.findMany({ - where: eq(userSafes.userDid, privyDid), + where: input.chain ? + and( + eq(userSafes.userDid, privyDid), + eq(userSafes.safeChain, input.chain) + ) : + eq(userSafes.userDid, privyDid), // Let drizzle-orm infer types for orderBy parameters orderBy: (safes, { asc }) => [asc(safes.createdAt)], }); From 3722e8279cd44de6b3ec3ec53adec58354b9cc1d Mon Sep 17 00:00:00 2001 From: Jose Miguel Navarro Date: Tue, 24 Jun 2025 19:29:14 +0900 Subject: [PATCH 02/10] create solana account --- .../dashboard/solana/SafeCard.tsx | 197 ++++++++++++++---- .../(authenticated)/dashboard/solana/page.tsx | 22 +- packages/web/src/server/routers/_app.ts | 2 + .../web/src/server/routers/solana-router.ts | 127 +++++++++++ 4 files changed, 289 insertions(+), 59 deletions(-) create mode 100644 packages/web/src/server/routers/solana-router.ts diff --git a/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx b/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx index fcaeb2b2d..66213f1f7 100644 --- a/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx +++ b/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx @@ -1,16 +1,22 @@ 'use client'; import React, { useState } from 'react'; -import { Card, CardContent } from '@/components/ui/card'; -import { Loader2 } from 'lucide-react'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import { Loader2, CheckCircle, Circle } from 'lucide-react'; import { useUserSafes } from '@/hooks/use-user-safes'; import { api } from '@/trpc/react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; export default function SafeCard() { - const { data: safes, isLoading, isError, error: fetchError } = useUserSafes(); - const { data: countFundingSources, refetch: refetchCountFundingSources, isLoading: isLoadingCountFundingSources } = + const { data: safes, isLoading, isError, error: fetchError } = useUserSafes('solana'); + const { + data: countFundingSources, + refetch: refetchCountFundingSources, + isError: isCountFundingSourcesError, + error: countFundingSourcesError, + isLoading: isLoadingCountFundingSources + } = api.fundingSource.countFundingSources.useQuery({ network: 'solana', }, { @@ -18,9 +24,26 @@ export default function SafeCard() { }); const [isRequestingAccount, setRequestingAccount] = useState(false); + const [isCreatingSafe, setCreatingSafe] = useState(false); + const solanaCreateSafeMutation = api.solana.createSafe.useMutation() const requestAccountMutation = api.align.requestVirtualAccount.useMutation(); - + + const handleCreateSafe = async () => { + if (isCreatingSafe || !safes || safes.length > 0) return; + setCreatingSafe(true); + try { + await solanaCreateSafeMutation.mutateAsync(); + await refetchCountFundingSources(); + toast.success('Solana Safe created successfully!'); + } catch (error) { + console.error('Error creating Solana Safe:', error); + toast.error('Failed to create Solana Safe. Please try again.'); + } finally { + setCreatingSafe(false); + } + }; + const handleRequestVirtualAccount = async () => { const safeAddress = safes?.[0]?.safeAddress; if (!safeAddress) { @@ -44,53 +67,135 @@ export default function SafeCard() { } }; - const solanaSafeCreated = (countFundingSources || 0) > 0; + if (isLoading || isLoadingCountFundingSources) { + return ( + + + + + + ); + } + if( isError || isCountFundingSourcesError) { + return ( + + +

Error loading Solana Safe Data: {(fetchError || countFundingSourcesError)?.message}

+
+
+ ); + } + + const hasSafes = safes && safes.length > 0; + const solanaBankAccountCreated = (countFundingSources || 0) > 0; + + const safeContent = { + title: hasSafes ? 'Your Solana Safe is ready!' : 'Create your Solana Safe', + description: hasSafes + ? 'You can now manage your Solana assets securely.' + : 'Set up your Solana Safe to start managing your assets securely.', + icon: hasSafes ? ( + + ) : ( + + ), + button: !hasSafes ? ( + + ) : null, + }; + + const bankAccountContent = { + disabled: !hasSafes, + icon: solanaBankAccountCreated ? ( + + ) : ( + + ), + title: 'Create Virtual Bank Account', + description: solanaBankAccountCreated + ? 'Your virtual bank accounts are set up and ready to use.' + : 'Set up virtual bank accounts to receive USD and EUR payments that automatically convert to stablecoins.', + button: + hasSafes && !solanaBankAccountCreated ? ( + + ) : null, + }; return ( - - { - isLoading || isLoadingCountFundingSources ? ( -
- - Loading your Solana Safe... + + Create your solana safe + + + {/* Step 1: Create Solana Safe */} +
+
+
{safeContent.icon}
+
+

{`1. ${safeContent.title}`}

+

+ {safeContent.description} +

- ) : isError ? ( -

Error loading Solana Safe: {fetchError.message}

- ) : solanaSafeCreated ? ( -

Your Solana Safe is ready!

- ) : ( -
-
-
-

- Create Virtual Bank Account -

-

- Set up virtual bank accounts to receive USD and EUR payments that automatically convert to stablecoins. -

-
+
+ {safeContent.button && ( +
+ {safeContent.button} +
+ )} +
+ + {/* Step 2: Create Virtual Bank Account */} +
+
+
{bankAccountContent.icon}
+
+

{`2. ${bankAccountContent.title}`}

+

+ {bankAccountContent.description} +

- +
+ {bankAccountContent.button && ( +
+ {bankAccountContent.button}
- ) - } + )} +
); diff --git a/packages/web/src/app/(authenticated)/dashboard/solana/page.tsx b/packages/web/src/app/(authenticated)/dashboard/solana/page.tsx index 48dc65398..d66973060 100644 --- a/packages/web/src/app/(authenticated)/dashboard/solana/page.tsx +++ b/packages/web/src/app/(authenticated)/dashboard/solana/page.tsx @@ -10,21 +10,17 @@ import SafeCard from './SafeCard'; export default function SolanaPage() { // maybe we can redirect to dashboard so we can avoid refetching the onboarding status const { data: onboardingStatus, isLoading } = - api.onboarding.getOnboardingSteps.useQuery(undefined, { - staleTime: 10 * 1000, // data considered fresh for 10s - refetchInterval: 10000, // poll every 5 seconds - refetchOnWindowFocus: false, - }); + api.onboarding.getOnboardingSteps.useQuery(undefined); if (isLoading) { - return ( - - - - - - ); - } + return ( + + + + + + ); + } const bankAccountStep = onboardingStatus?.steps?.setupBankAccount?.isCompleted ?? false; diff --git a/packages/web/src/server/routers/_app.ts b/packages/web/src/server/routers/_app.ts index bf7bb582d..3180524a1 100644 --- a/packages/web/src/server/routers/_app.ts +++ b/packages/web/src/server/routers/_app.ts @@ -14,6 +14,7 @@ import { actionLedgerRouter } from './action-ledger'; import { inboxCardsRouter } from './inbox-cards-router'; import { dashboardRouter } from './dashboard-router'; import { waitlistRouter } from './waitlist-router'; +import { solanaRouter } from './solana-router'; /** * This is the primary router for your server. @@ -40,6 +41,7 @@ export const appRouter = router({ actionLedger: actionLedgerRouter, dashboard: dashboardRouter, waitlist: waitlistRouter, + solana: solanaRouter, }); // Export type definition of API diff --git a/packages/web/src/server/routers/solana-router.ts b/packages/web/src/server/routers/solana-router.ts new file mode 100644 index 000000000..ccfb27a01 --- /dev/null +++ b/packages/web/src/server/routers/solana-router.ts @@ -0,0 +1,127 @@ +import { protectedProcedure, router } from '../create-router'; +import { USDC_ADDRESS } from '@/lib/constants'; +import { userSafes } from '@/db/schema'; +import { eq, and, count } from 'drizzle-orm'; +import { TRPCError } from '@trpc/server'; +import { getPrivyClient } from '@/lib/auth'; + +function getSafeBalance({ + safeAddress, + tokenAddress, +}: { + safeAddress: string; + tokenAddress: string; +}) { + // This function should call the actual service to get the balance + // For now, it's a placeholder + return Promise.resolve({ + // Example balance, replace with actual logic + formatted: '100.00', + }); +} + +export const solanaRouter = router({ + getBalance: protectedProcedure.query(async ({ ctx }) => { + const { userId, log, db } = ctx; + + if (!userId) { + throw new TRPCError({ code: 'UNAUTHORIZED' }); + } + + let virtualBalance = 0; + + // 2. Get user safes + const userSafeRecords = await db.query.userSafes.findMany({ + where: and( + eq(userSafes.userDid, userId), + // solana safes only + // eq(userSafes.chainId, 'solana'), + ), + columns: { + safeAddress: true, + safeType: true, + } + }); + + // 3. Get crypto balances + const safeBalances = await Promise.all( + userSafeRecords.map((safe) => + getSafeBalance({ + safeAddress: safe.safeAddress, + tokenAddress: USDC_ADDRESS, // Hardcoded USDC + }).catch(e => { + log.error(e, `Failed to get balance for safe ${safe.safeAddress}`); + return null; + }), + ), + ); + + const totalCryptoBalance = safeBalances.reduce((total: number, balance) => { + if (balance?.formatted) { + return total + parseFloat(balance.formatted); + } + return total; + }, 0); + + // 4. Aggregate balances + const totalBalance = virtualBalance + totalCryptoBalance; + const primarySafe = userSafeRecords.find((s) => s.safeType === 'primary'); + + return { + totalBalance, + primarySafeAddress: primarySafe?.safeAddress as `0x${string}` | undefined, + }; + }), + createSafe: protectedProcedure.mutation(async ({ ctx }) => { + const { userId, db } = ctx; + + if (!userId) { + throw new TRPCError({ code: 'UNAUTHORIZED' }); + } + const client = await getPrivyClient(); + if (!client) { + throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Privy client not initialized' }); + } + const countSafes = await db.select({ + count: count(), + }).from(userSafes) + .where(and( + eq(userSafes.userDid, userId), + eq(userSafes.safeChain, 'solana'), + )); + if (countSafes[0].count > 0) { + throw new TRPCError({ code: 'BAD_REQUEST', message: 'Solana safe already exists for this user' }); + } + + let safeAddress: string | undefined; + try { + const solanaAccount = await client.walletApi.createWallet({ + chainType: 'solana', + }); + console.log('Solana account created', solanaAccount); + safeAddress = solanaAccount.address; + } catch (error) { + console.error('Error creating Solana account:', error); + throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to create Solana account' }); + } + + try { + // Insert the new safe into the database + const [insertedSafe] = await db.insert(userSafes).values({ + userDid: userId, + safeAddress, + safeType: 'other', + safeChain: 'solana', + }).returning(); + console.log(`Successfully inserted ${insertedSafe.safeType} safe (ID: ${insertedSafe.id}) into DB for user DID: ${userId}`); + + return { + message: `${insertedSafe.safeType.charAt(0).toUpperCase() + insertedSafe.safeType.slice(1)} safe created successfully.`, + data: insertedSafe, + }; + } catch (error) { + console.error('Error creating Solana safe:', error); + throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Failed to create Solana safe' }); + } + }) +}); From 768f70b40f87f3ad4b5f70d941af00801cf980ff Mon Sep 17 00:00:00 2001 From: Jose Miguel Navarro Date: Wed, 25 Jun 2025 00:19:51 +0900 Subject: [PATCH 03/10] add funds display to solana and move to common components --- .../src/actions/get-user-funding-sources.ts | 11 +- .../(authenticated)/dashboard/(bank)/page.tsx | 17 ++- .../dashboard/solana/FundsCard.tsx | 12 ++ .../dashboard/solana/SafeCard.tsx | 104 ++++++++++-------- .../funds}/funds-display.tsx | 9 +- .../src/server/routers/dashboard-router.ts | 8 +- .../web/src/server/routers/solana-router.ts | 8 +- 7 files changed, 103 insertions(+), 66 deletions(-) create mode 100644 packages/web/src/app/(authenticated)/dashboard/solana/FundsCard.tsx rename packages/web/src/{app/(authenticated)/dashboard/(bank)/components/dashboard => components/funds}/funds-display.tsx (97%) diff --git a/packages/web/src/actions/get-user-funding-sources.ts b/packages/web/src/actions/get-user-funding-sources.ts index 3db55c278..10972018e 100644 --- a/packages/web/src/actions/get-user-funding-sources.ts +++ b/packages/web/src/actions/get-user-funding-sources.ts @@ -1,6 +1,6 @@ 'use server'; import { unstable_cache as cache } from 'next/cache'; -import { eq } from 'drizzle-orm'; +import { eq, and } from 'drizzle-orm'; import { db } from '@/db'; import { userFundingSources } from '@/db/schema'; @@ -20,7 +20,7 @@ export type UserFundingSourceDisplayData = { }; export const getUserFundingSources = cache( - async (privyDid: string): Promise => { + async (privyDid: string, network: 'ethereum' | 'solana' = 'ethereum'): Promise => { // Add null/undefined check for privyDid if (!privyDid) { console.error('Attempted to fetch funding sources without privyDid'); @@ -45,7 +45,12 @@ export const getUserFundingSources = cache( destinationPaymentRail: userFundingSources.destinationPaymentRail, }) .from(userFundingSources) - .where(eq(userFundingSources.userPrivyDid, privyDid)); + .where( + and( + eq(userFundingSources.userPrivyDid, privyDid), + eq(userFundingSources.destinationPaymentRail, network) + ) + ); // Return full account details without masking return sources.map(source => { diff --git a/packages/web/src/app/(authenticated)/dashboard/(bank)/page.tsx b/packages/web/src/app/(authenticated)/dashboard/(bank)/page.tsx index e3cc86a2d..aafc291bb 100644 --- a/packages/web/src/app/(authenticated)/dashboard/(bank)/page.tsx +++ b/packages/web/src/app/(authenticated)/dashboard/(bank)/page.tsx @@ -5,7 +5,7 @@ import { Suspense } from 'react'; import { ActiveAgents } from './components/agents/active-agents'; import { TransactionHistoryList } from './components/dashboard/transaction-history-list'; import { redirect } from 'next/navigation'; -import { FundsDisplay } from './components/dashboard/funds-display'; +import { FundsDisplay } from '@/components/funds/funds-display'; import { OnboardingTasksCard } from './components/dashboard/onboarding-tasks-card'; // Loading components for Suspense boundaries @@ -48,10 +48,15 @@ export default async function DashboardPage() { isCompleted: false, })); - const fundsDataPromise = caller.dashboard.getBalance().catch(() => ({ - totalBalance: 0, - primarySafeAddress: undefined, - })); + const fundsDataPromise = caller.dashboard.getBalance() + .catch((err) => { + console.error(err); + return { + totalBalance: 0, + network: 'ethereum', + primarySafeAddress: undefined, + }; + }); // Await promises for Suspense boundaries const OnboardingData = async () => { @@ -61,7 +66,7 @@ export default async function DashboardPage() { const FundsData = async () => { const data = await fundsDataPromise; - return ; + return ; }; return ( diff --git a/packages/web/src/app/(authenticated)/dashboard/solana/FundsCard.tsx b/packages/web/src/app/(authenticated)/dashboard/solana/FundsCard.tsx new file mode 100644 index 000000000..03bd840dc --- /dev/null +++ b/packages/web/src/app/(authenticated)/dashboard/solana/FundsCard.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { api } from '@/trpc/react'; +import { FundsDisplay } from '@/components/funds/funds-display'; + +export default function FundsCard({wallet}: {wallet: string}) { + const { data, isError, error, isLoading} = + api.solana.getBalance.useQuery(); + if (isError) console.error('Error fetching Solana balance:', error); + if (isLoading || !data) return null; + return ; + +} \ No newline at end of file diff --git a/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx b/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx index 66213f1f7..ec30692b2 100644 --- a/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx +++ b/packages/web/src/app/(authenticated)/dashboard/solana/SafeCard.tsx @@ -7,6 +7,7 @@ import { useUserSafes } from '@/hooks/use-user-safes'; import { api } from '@/trpc/react'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; +import FundsCard from './FundsCard'; export default function SafeCard() { const { data: safes, isLoading, isError, error: fetchError } = useUserSafes('solana'); @@ -150,53 +151,62 @@ export default function SafeCard() { }; return ( - - - Create your solana safe - - - {/* Step 1: Create Solana Safe */} -
-
-
{safeContent.icon}
-
-

{`1. ${safeContent.title}`}

-

- {safeContent.description} -

-
-
- {safeContent.button && ( -
- {safeContent.button} -
- )} -
+
+ { + !solanaBankAccountCreated && ( + + + Create your solana safe + + + {/* Step 1: Create Solana Safe */} +
+
+
{safeContent.icon}
+
+

{`1. ${safeContent.title}`}

+

+ {safeContent.description} +

+
+
+ {safeContent.button && ( +
+ {safeContent.button} +
+ )} +
- {/* Step 2: Create Virtual Bank Account */} -
-
-
{bankAccountContent.icon}
-
-

{`2. ${bankAccountContent.title}`}

-

- {bankAccountContent.description} -

-
-
- {bankAccountContent.button && ( -
- {bankAccountContent.button} -
- )} -
-
-
+ {/* Step 2: Create Virtual Bank Account */} +
+
+
{bankAccountContent.icon}
+
+

{`2. ${bankAccountContent.title}`}

+

+ {bankAccountContent.description} +

+
+
+ {bankAccountContent.button && ( +
+ {bankAccountContent.button} +
+ )} +
+ + + ) + } + {hasSafes && ( + + )} +
); } \ No newline at end of file diff --git a/packages/web/src/app/(authenticated)/dashboard/(bank)/components/dashboard/funds-display.tsx b/packages/web/src/components/funds/funds-display.tsx similarity index 97% rename from packages/web/src/app/(authenticated)/dashboard/(bank)/components/dashboard/funds-display.tsx rename to packages/web/src/components/funds/funds-display.tsx index 3a5a5d449..cd5d4a661 100644 --- a/packages/web/src/app/(authenticated)/dashboard/(bank)/components/dashboard/funds-display.tsx +++ b/packages/web/src/components/funds/funds-display.tsx @@ -11,7 +11,7 @@ import { DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; -import { Wallet, Copy, Check, Info, CreditCard, MoreHorizontal } from 'lucide-react'; +import { Copy, Check, Info, CreditCard, MoreHorizontal } from 'lucide-react'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { SimplifiedOffRamp } from '@/components/transfers/simplified-off-ramp'; import { getUserFundingSources, type UserFundingSourceDisplayData } from '@/actions/get-user-funding-sources'; @@ -30,9 +30,10 @@ const formatCurrency = (amount: number): string => { interface FundsDisplayProps { totalBalance?: number; walletAddress?: string; + network: 'ethereum' | 'solana'; } -export function FundsDisplay({ totalBalance = 0, walletAddress }: FundsDisplayProps) { +export function FundsDisplay({ totalBalance = 0, walletAddress, network }: FundsDisplayProps) { const [isCopied, setIsCopied] = useState(false); const [copiedField, setCopiedField] = useState(null); const [isMoveModalOpen, setIsMoveModalOpen] = useState(false); @@ -62,7 +63,7 @@ export function FundsDisplay({ totalBalance = 0, walletAddress }: FundsDisplayPr if (ready && authenticated && user?.id) { setIsLoadingFundingSources(true); try { - const sources = await getUserFundingSources(user.id); + const sources = await getUserFundingSources(user.id, network); setFundingSources(sources); } catch (err) { console.error("Failed to fetch funding sources:", err); @@ -320,7 +321,7 @@ export function FundsDisplay({ totalBalance = 0, walletAddress }: FundsDisplayPr {walletAddress ? (
-

Wallet Address (Base Network)

+

Wallet Address ({network === 'ethereum' ? 'Base' : network} Network)

{walletAddress}

); diff --git a/packages/web/src/components/funds/funds-display.tsx b/packages/web/src/components/funds/funds-display.tsx index 37b4503f4..2a59c08e9 100644 --- a/packages/web/src/components/funds/funds-display.tsx +++ b/packages/web/src/components/funds/funds-display.tsx @@ -45,12 +45,14 @@ interface FundsDisplayProps { totalBalance?: number; walletAddress?: string; network: 'ethereum' | 'solana'; + currency?: 'usd' | 'eur' | 'sol' } export function FundsDisplay({ totalBalance = 0, walletAddress, network, + currency = 'usd', }: FundsDisplayProps) { const [isCopied, setIsCopied] = useState(false); const [copiedField, setCopiedField] = useState(null); @@ -136,7 +138,7 @@ export function FundsDisplay({

- Personal · USD + Personal · {currency.toUpperCase()}

diff --git a/packages/web/src/lib/solana.ts b/packages/web/src/lib/solana.ts new file mode 100644 index 000000000..25c4c0fb4 --- /dev/null +++ b/packages/web/src/lib/solana.ts @@ -0,0 +1,6 @@ +import { createSolanaRpc, devnet, mainnet } from '@solana/kit'; + +export const mainnetRpc = createSolanaRpc(mainnet('https://api.mainnet-beta.solana.com')); +export const devnetRpc = createSolanaRpc(devnet('https://api.devnet.solana.com')); + +export const LAMPORTS_PER_SOL = 1_000_000_000 \ No newline at end of file diff --git a/packages/web/src/server/routers/solana-router.ts b/packages/web/src/server/routers/solana-router.ts index 3076b446f..bd8bd0461 100644 --- a/packages/web/src/server/routers/solana-router.ts +++ b/packages/web/src/server/routers/solana-router.ts @@ -1,76 +1,76 @@ import { protectedProcedure, router } from '../create-router'; -import { USDC_ADDRESS } from '@/lib/constants'; import { userSafes } from '@/db/schema'; import { eq, and, count } from 'drizzle-orm'; import { TRPCError } from '@trpc/server'; import { getPrivyClient } from '@/lib/auth'; import { z } from 'zod'; +import { devnetRpc, LAMPORTS_PER_SOL } from '@/lib/solana'; +import { Address } from '@solana/kit'; -function getSafeBalance({ +async function getSafeBalance({ safeAddress, - tokenAddress, + token, }: { safeAddress: string; - tokenAddress: string; + token: 'sol' | 'usdc' | 'eurc'; }) { - // This function should call the actual service to get the balance - // For now, it's a placeholder + if (token === 'sol') { + const { value: lamports } = await devnetRpc.getBalance(safeAddress as Address).send(); + + // Divide using bigint — you'll get integer part of SOL + const solIntegerPart = lamports / BigInt(LAMPORTS_PER_SOL); + + // Get the decimal remainder + const solRemainder = lamports % BigInt(LAMPORTS_PER_SOL); + + const formatted = `${solIntegerPart}.${solRemainder.toString().padStart(9, '0').replace(/0+$/, '')}`; + return Promise.resolve({ + formatted, + }); + } + + // handle other tokens return Promise.resolve({ - // Example balance, replace with actual logic - formatted: '100.00', + formatted: '0.00', }); } export const solanaRouter = router({ - getBalance: protectedProcedure.query(async ({ ctx }) => { + getBalance: protectedProcedure + .input(z.object( + { + address: z.string().length(44), + token: z.enum(['usdc', 'sol', 'eurc']) + } + )).query(async ({ ctx, input }) => { const { userId, log, db } = ctx; if (!userId) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } + const primarySafeAddress = input.address; let virtualBalance = 0; - // 2. Get user safes - const userSafeRecords = await db.query.userSafes.findMany({ - where: and( - eq(userSafes.userDid, userId), - eq(userSafes.safeChain, 'solana'), - ), - columns: { - safeAddress: true, - safeType: true, - } - }); // 3. Get crypto balances - const safeBalances = await Promise.all( - userSafeRecords.map((safe) => - getSafeBalance({ - safeAddress: safe.safeAddress, - tokenAddress: USDC_ADDRESS, // Hardcoded USDC - }).catch(e => { - log.error(e, `Failed to get balance for safe ${safe.safeAddress}`); - return null; - }), - ), - ); + const safeBalance = await getSafeBalance({ + safeAddress: primarySafeAddress, + token: input.token, + }).catch(e => { + log.error(e, `Failed to get balance for safe ${primarySafeAddress}`); + return null; + }) - const totalCryptoBalance = safeBalances.reduce((total: number, balance) => { - if (balance?.formatted) { - return total + parseFloat(balance.formatted); - } - return total; - }, 0); + const totalCryptoBalance = safeBalance?.formatted ? parseFloat(safeBalance.formatted) : 0 // 4. Aggregate balances const totalBalance = virtualBalance + totalCryptoBalance; - const primarySafe = userSafeRecords.find((s) => s.safeType === 'primary') || userSafeRecords[0]; return { totalBalance, network: 'solana' as 'solana', - primarySafeAddress: primarySafe?.safeAddress as string | undefined, + primarySafeAddress, }; }), createSafe: protectedProcedure diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a3879f44..98fabd88a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -270,6 +270,9 @@ importers: '@safe-global/protocol-kit': specifier: ^6.0.2 version: 6.0.2(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.49) + '@solana/kit': + specifier: ^2.3.0 + version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@tanstack/react-query': specifier: 'catalog:' version: 5.67.1(react@19.0.0) @@ -3758,10 +3761,229 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + '@solana/accounts@2.3.0': + resolution: {integrity: sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/addresses@2.3.0': + resolution: {integrity: sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/assertions@2.3.0': + resolution: {integrity: sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/buffer-layout@4.0.1': resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} engines: {node: '>=5.10'} + '@solana/codecs-core@2.3.0': + resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-data-structures@2.3.0': + resolution: {integrity: sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-numbers@2.3.0': + resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs-strings@2.3.0': + resolution: {integrity: sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' + + '@solana/codecs@2.3.0': + resolution: {integrity: sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/errors@2.3.0': + resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + + '@solana/fast-stable-stringify@2.3.0': + resolution: {integrity: sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/functional@2.3.0': + resolution: {integrity: sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/instructions@2.3.0': + resolution: {integrity: sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/keys@2.3.0': + resolution: {integrity: sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/kit@2.3.0': + resolution: {integrity: sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/nominal-types@2.3.0': + resolution: {integrity: sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/options@2.3.0': + resolution: {integrity: sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/programs@2.3.0': + resolution: {integrity: sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/promises@2.3.0': + resolution: {integrity: sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-api@2.3.0': + resolution: {integrity: sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-parsed-types@2.3.0': + resolution: {integrity: sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec-types@2.3.0': + resolution: {integrity: sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-spec@2.3.0': + resolution: {integrity: sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-api@2.3.0': + resolution: {integrity: sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions-channel-websocket@2.3.0': + resolution: {integrity: sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 + + '@solana/rpc-subscriptions-spec@2.3.0': + resolution: {integrity: sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-subscriptions@2.3.0': + resolution: {integrity: sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transformers@2.3.0': + resolution: {integrity: sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-transport-http@2.3.0': + resolution: {integrity: sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc-types@2.3.0': + resolution: {integrity: sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/rpc@2.3.0': + resolution: {integrity: sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/signers@2.3.0': + resolution: {integrity: sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/subscribable@2.3.0': + resolution: {integrity: sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/sysvars@2.3.0': + resolution: {integrity: sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-confirmation@2.3.0': + resolution: {integrity: sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transaction-messages@2.3.0': + resolution: {integrity: sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/transactions@2.3.0': + resolution: {integrity: sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + '@solana/wallet-adapter-base@0.9.23': resolution: {integrity: sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw==} engines: {node: '>=16'} @@ -4896,6 +5118,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@3.1.0: resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==} @@ -5030,6 +5256,10 @@ packages: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -5919,6 +6149,9 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + fastfile@0.0.20: resolution: {integrity: sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==} @@ -9017,6 +9250,9 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + undici-types@7.11.0: + resolution: {integrity: sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==} + undici@5.28.5: resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} engines: {node: '>=14.0'} @@ -13601,10 +13837,362 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} + '@solana/accounts@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/assertions': 2.3.0(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + '@solana/buffer-layout@4.0.1': dependencies: buffer: 6.0.3 + '@solana/codecs-core@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/codecs-data-structures@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/codecs-numbers@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/codecs-strings@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.8.2 + + '@solana/codecs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-data-structures': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/options': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/errors@2.3.0(typescript@5.8.2)': + dependencies: + chalk: 5.4.1 + commander: 14.0.0 + typescript: 5.8.2 + + '@solana/fast-stable-stringify@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/functional@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/instructions@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/keys@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/assertions': 2.3.0(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/instructions': 2.3.0(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/programs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/signers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/sysvars': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/nominal-types@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/options@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-data-structures': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/rpc-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-parsed-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/rpc-spec-types@2.3.0(typescript@5.8.2)': + dependencies: + typescript: 5.8.2 + + '@solana/rpc-spec@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/rpc-subscriptions-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.2) + '@solana/subscribable': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + + '@solana/rpc-subscriptions-spec@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/promises': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + '@solana/subscribable': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/promises': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/subscribable': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/rpc-transformers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + undici-types: 7.11.0 + + '@solana/rpc-types@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/fast-stable-stringify': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/rpc-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-spec': 2.3.0(typescript@5.8.2) + '@solana/rpc-spec-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-transport-http': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/instructions': 2.3.0(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@2.3.0(typescript@5.8.2)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.8.2) + typescript: 5.8.2 + + '@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/promises': 2.3.0(typescript@5.8.2) + '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + + '@solana/transaction-messages@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-data-structures': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/instructions': 2.3.0(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/codecs-core': 2.3.0(typescript@5.8.2) + '@solana/codecs-data-structures': 2.3.0(typescript@5.8.2) + '@solana/codecs-numbers': 2.3.0(typescript@5.8.2) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/errors': 2.3.0(typescript@5.8.2) + '@solana/functional': 2.3.0(typescript@5.8.2) + '@solana/instructions': 2.3.0(typescript@5.8.2) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/nominal-types': 2.3.0(typescript@5.8.2) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))': dependencies: '@solana/wallet-standard-features': 1.3.0 @@ -15644,6 +16232,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.4.1: {} + change-case@3.1.0: dependencies: camel-case: 3.0.0 @@ -15803,6 +16393,8 @@ snapshots: commander@10.0.1: {} + commander@14.0.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -16923,6 +17515,8 @@ snapshots: fast-uri@3.0.6: {} + fastestsmallesttextencoderdecoder@1.0.22: {} + fastfile@0.0.20: {} fastq@1.19.1: @@ -20501,6 +21095,8 @@ snapshots: undici-types@6.20.0: {} + undici-types@7.11.0: {} + undici@5.28.5: dependencies: '@fastify/busboy': 2.1.1