diff options
| author | Adam Soltys <[email protected]> | 2026-03-16 16:35:11 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-03-16 16:37:03 -0700 |
| commit | 8c1385eaf8e68ef0ad436ad9b74e5813e92bb378 (patch) | |
| tree | 16edd2c353a5d435768f901063fa146e97536d83 /lib | |
| parent | 4a3d3b676ec7c21077786c7cdd33772385b87a6d (diff) | |
| download | coinos-server-8c1385eaf8e68ef0ad436ad9b74e5813e92bb378.tar.gz coinos-server-8c1385eaf8e68ef0ad436ad9b74e5813e92bb378.zip | |
update migrate script
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/migrate.ts | 237 | ||||
| -rw-r--r-- | lib/tb.ts | 49 |
2 files changed, 0 insertions, 286 deletions
diff --git a/lib/migrate.ts b/lib/migrate.ts deleted file mode 100644 index f2320390..00000000 --- a/lib/migrate.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { db, g, s, scan } from "$lib/db"; -import { findLastUsedIndex, parseDescriptor } from "$lib/esplora"; -import { l, warn } from "$lib/logging"; -import { - createBalanceAccount, - createCreditAccounts, - createFundAccount, - tbFundCredit, - tbSetBalance, - tbSetPending, - tbSetCredit, - tbMultiplyForMicrosats, -} from "$lib/tb"; - -async function migrate(id) { - const k = id?.replace(/\s/g, "").toLowerCase(); - let user = await g(`user:${k}`); - if (typeof user === "string") user = await g(`user:${user}`); - return user; -} - -export const migrateAccounts = async () => { - const keys = await db.keys("account:*"); - let migrated = 0; - - for (const key of keys) { - try { - if ((key as string).endsWith(":invoices")) continue; - const keyType = await db.type(key); - if (keyType !== "string") continue; - - const account = await g(key); - if (!account || !account.id) continue; - if (account.pubkey || account.type === "ark" || !account.seed) continue; - if (!account.descriptors?.length) continue; - - const parsed = parseDescriptor(account.descriptors[0].desc); - if (!parsed) continue; - - account.pubkey = parsed.pubkey; - account.fingerprint = parsed.fingerprint; - try { - account.nextIndex = await findLastUsedIndex(parsed.pubkey, parsed.fingerprint); - } catch (e) { - warn("account migration index scan skipped", key, e.message); - account.nextIndex = account.nextIndex || 0; - } - - await s(`account:${account.id}`, account); - migrated++; - } catch (e) { - warn("failed to migrate account", key, e.message); - } - } - - return migrated; -}; - -export const migrateBalancesToTB = async () => { - const migrated = await db.get("tb:migrated"); - if (migrated) return 0; - - let count = 0; - - // Migrate balance:* keys - for await (const k of scan("balance:*")) { - try { - const id = (k as string).split(":")[1]; - const balance = Number.parseInt(((await db.get(k)) as string) || "0"); - await createBalanceAccount(id); - if (balance > 0) await tbSetBalance(id, balance); - count++; - } catch (e) { - warn("failed to migrate balance", k, e.message); - } - } - - // Migrate pending:* keys - for await (const k of scan("pending:*")) { - try { - const id = (k as string).split(":")[1]; - const pending = Number.parseInt(((await db.get(k)) as string) || "0"); - if (pending > 0) await tbSetPending(id, pending); - } catch (e) { - warn("failed to migrate pending", k, e.message); - } - } - - // Migrate credit:*:* keys - for await (const k of scan("credit:*:*")) { - try { - const parts = (k as string).split(":"); - const type = parts[1]; - const uid = parts[2]; - const amount = Number.parseInt(((await db.get(k)) as string) || "0"); - await createCreditAccounts(uid); - if (amount > 0) await tbSetCredit(uid, type, amount); - } catch (e) { - warn("failed to migrate credit", k, e.message); - } - } - - await db.set("tb:migrated", Date.now().toString()); - l(`Migrated ${count} balances to TigerBeetle`); - return count; -}; - -export const migrateToMicrosats = async () => { - const migrated = await db.get("tb:microsats"); - if (migrated) return 0; - - let count = 0; - - // Iterate through all users and multiply their TB balances - for await (const k of scan("user:*")) { - try { - const raw = await db.get(k); - if (!raw) continue; - - // Skip user alias keys (they just contain another key reference) - if (!(raw as string).startsWith("{")) continue; - - const user = JSON.parse(raw as string); - if (!user.id) continue; - - const multiplied = await tbMultiplyForMicrosats(user.id); - if (multiplied > 0) count++; - } catch (e) { - warn("microsats migration error", k, e.message); - } - } - - await db.set("tb:microsats", Date.now().toString()); - l(`Migrated ${count} users to microsats`); - return count; -}; - -export const migrateAutowithdraw = async () => { - const migrated = await db.get("autowithdraw:migrated"); - if (migrated) return 0; - - let count = 0; - - for await (const k of scan("user:*")) { - try { - const raw = await db.get(k); - if (!raw || !(raw as string).startsWith("{")) continue; - - const user = JSON.parse(raw as string); - if (!user.id || !user.autowithdraw) continue; - - const accountIds = await db.lRange(`${user.id}:accounts`, 0, -1); - - for (const aid of accountIds) { - const account = await g(`account:${aid}`); - if (!account) continue; - if (account.seed || account.type === "ark") continue; - if (account.autowithdraw) continue; - - account.autowithdraw = true; - account.threshold = account.threshold ?? user.threshold; - account.reserve = account.reserve ?? user.reserve; - account.destination = account.destination ?? user.destination; - - await s(`account:${aid}`, account); - count++; - } - } catch (e) { - warn("autowithdraw migration error", k, e.message); - } - } - - await db.set("autowithdraw:migrated", Date.now().toString()); - l(`Migrated autowithdraw to ${count} accounts`); - return count; -}; - -export const migrateFundsToTB = async () => { - const migrated = await db.get("tb:funds-migrated"); - if (migrated) return 0; - - let count = 0; - - for await (const k of scan("fund:*")) { - try { - // Skip sub-keys like fund:name:payments, fund:name:managers, fund:limit - const parts = (k as string).split(":"); - if (parts.length !== 2) continue; - const name = parts[1]; - if (name === "limit") continue; - - const keyType = await db.type(k); - if (keyType !== "string") continue; - - const balance = Number.parseInt(((await db.get(k)) as string) || "0"); - await createFundAccount(name); - if (balance > 0) await tbFundCredit(name, balance); - count++; - } catch (e) { - warn("failed to migrate fund", k, e.message); - } - } - - await db.set("tb:funds-migrated", Date.now().toString()); - l(`Migrated ${count} funds to TigerBeetle`); - return count; -}; - -export const hashPins = async () => { - const migrated = await db.get("pins:hashed"); - if (migrated) return 0; - - let count = 0; - - for await (const k of scan("user:*")) { - try { - const raw = await db.get(k); - if (!raw || !(raw as string).startsWith("{")) continue; - - const user = JSON.parse(raw as string); - if (!user.pin || user.pin.length !== 6) continue; - - const hash = new Bun.CryptoHasher("sha256").update(user.pin).digest("hex"); - user.pin = hash; - await s(k as string, user); - count++; - } catch (e) { - warn("pin hash migration error", k, e.message); - } - } - - await db.set("pins:hashed", Date.now().toString()); - l(`Hashed ${count} user PINs`); - return count; -}; - -export default migrate; @@ -671,52 +671,3 @@ export async function getFundBalance(name: string): Promise<number | null> { return accountBalance(account); } -// Migration helper: multiply existing balance by MULTIPLIER to convert sats→microsats -// Called by migrateToMicrosats() - adds (balance * 999999) to turn X into X*1000000 -// NOTE: This migration should only run ONCE - guarded by tb:microsats flag in migrate.ts -export async function tbMultiplyForMicrosats(uid: string): Promise<number> { - // Ensure client is initialized (needed when called during startup) - if (!client) { - await initTigerBeetle(); - } - - const MULTIPLIER = 999999n; // Adding this turns X into X*1000000 - let count = 0; - - const multiplyAccount = async (accountId: bigint, ledger: number, houseId: bigint) => { - const acct = await client.lookupAccounts([u128(accountId)]); - if (!acct.length) return; - const current = BigInt(acct[0].credits_posted) - BigInt(acct[0].debits_posted); - if (current <= 0n) return; - - const results = await client.createTransfers([ - { - id: nextTransferId(), - debit_account_id: u128(houseId), - credit_account_id: u128(accountId), - amount: current * MULTIPLIER, - pending_id: 0n, - user_data_128: 0n, - user_data_64: 0n, - user_data_32: 0, - timeout: 0, - ledger, - code: 1, - flags: 0, - timestamp: 0n, - }, - ]); - if (results.length === 0) count++; - }; - - const balId = balanceId(uid); - const pendId = pendingId(uid); - - await multiplyAccount(balId, LEDGER_SATS, HOUSE_SATS); - await multiplyAccount(pendId, LEDGER_SATS, HOUSE_SATS); - await multiplyAccount(creditId(uid, "bitcoin"), LEDGER_CREDIT_BTC, HOUSE_BTC); - await multiplyAccount(creditId(uid, "lightning"), LEDGER_CREDIT_LN, HOUSE_LN); - await multiplyAccount(creditId(uid, "liquid"), LEDGER_CREDIT_LQ, HOUSE_LQ); - - return count; -} |
