Files
mono/components/migrator/migrations/049_migrate_phase2_progwallets.ts
T
coopops 9fb53901aa [@ant] feat(migrator): per-coop self-service миграции agreements + L3 (story 2.5/3.6/3.7)
Три миграции через ledger3-релиз rollout:

- 047_migrate_agreements_to_wallet.ts — Эпик 2 / story 2.5
  agreements3.program_id>0 (status=confirmed) → wallet::migrate3.
  Идемпотентно, без удаления исходных записей (Эпик 4 финального
  deploy soviet).

- 048_migrate_phase1_minshare.ts — Эпик 3 / story 3.6 (ADR-008)
  participants[status=accepted] → ledger2::migrate3 на w.reg.minshr.
  amount = coop.org_minimum для type=organization, иначе coop.minimum.
  w.reg.entry не затрагивается — он COOPERATIVE без L3-разбивки.

- 049_migrate_phase2_progwallets.ts — Эпик 3 / story 3.7
  progwallets → ledger2::migrate3 с маппингом program_id → wallet_name:
    1 (ЦК)        → w.wal.share (membership_contribution=0 на prod)
    3 (Генератор) → w.cap.gen
    4 (Благорост) → w.cap.blago
  Pre-flight gate (NFR18) выполняется внешним скриптом сравнения
  Σ progwallets vs Σ userwallets перед production rollout.

src/utils:
- listCoops — обход registrator::coops с фильтром is_cooperative+active
- fetchAllRows — пагинированное чтение get_table_rows с lower_bound

Все три миграции per-coop self-service, batched по 50 actions/tx,
идемпотентные (migrate3 — overwrite, не +=).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 10:26:35 +00:00

88 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Phase 2 (Эпик 3 / story 3.7): миграция soviet::progwallets → ledger2::userwallets
* через ledger2::migrate3 (per-coop self-service).
*
* Маппинг program_id → wallet_name (см. эпик 3 §6 «Migrator Phase 2»):
* 1 (ЦК) → split: w.wal.share + w.wal.member.
* На текущем prod membership_contribution = 0, поэтому всё уходит
* в w.wal.share, а w.wal.member не создаётся (no-op).
* 3 (Генератор) → w.cap.gen
* 4 (Благорост) → w.cap.blago
* 2 (marketplace) — программных кошельков нет, пропускается.
*
* Особенности:
* - Идемпотентно: ledger2::migrate3 устанавливает значение (не +=).
* - Без удаления записей из soviet::progwallets — это сделает Эпик 4
* (финальный deploy soviet); до тех пор записи остаются как избыточная
* копия (новые operations пишут только в ledger2::userwallets).
*
* Pre-flight gate (NFR18) выполняется ВНЕШНИМ скриптом на staging:
* сравнение Σ progwallets (pre) vs Σ userwallets (post) per (coopname, username,
* program_id) — дельта 0 копеек до production rollout.
*/
import { Ledger2Contract, SovietContract } from 'cooptypes';
import type { Migration } from '../src/migration_interface';
import { api } from '../src/eos';
import { listCoops } from '../src/utils/listCoops';
import { fetchAllRows } from '../src/utils/fetchAllRows';
const PROGRAM_TO_WALLET: Record<number, string> = {
1: 'w.wal.share',
3: 'w.cap.gen',
4: 'w.cap.blago',
};
const BATCH = 50;
export class MigratePhase2Progwallets implements Migration {
async run(): Promise<void> {
const coops = await listCoops();
console.log(`[049] Кооперативов найдено: ${coops.length}`);
let totalMigrated = 0;
for (const coopname of coops) {
const progwallets = await fetchAllRows<SovietContract.Tables.ProgramWallets.IProgramWallet>({
code: SovietContract.contractName.production,
scope: coopname,
table: SovietContract.Tables.ProgramWallets.tableName,
});
const eligible = progwallets.filter((pw) => PROGRAM_TO_WALLET[Number(pw.program_id)]);
if (eligible.length === 0) {
console.log(`[049] ${coopname}: нет progwallets под маппинг — пропуск`);
continue;
}
console.log(`[049] ${coopname}: progwallets ${eligible.length}`);
for (let i = 0; i < eligible.length; i += BATCH) {
const chunk = eligible.slice(i, i + BATCH);
const actions = chunk.map((pw) => ({
account: Ledger2Contract.contractName.production,
name: Ledger2Contract.Actions.Migrate3.actionName,
authorization: [{ actor: coopname, permission: 'active' }],
data: {
coopname,
wallet_name: PROGRAM_TO_WALLET[Number(pw.program_id)]!,
username: pw.username,
available: pw.available,
blocked: pw.blocked,
},
}));
await api.transact(
{ actions },
{ blocksBehind: 3, expireSeconds: 30 }
);
totalMigrated += chunk.length;
console.log(`[049] ${coopname}: ${chunk.length} progwallets → userwallets`);
}
}
console.log(`[049] Готово: всего L3-записей migrate3 ${totalMigrated}`);
}
}