@openreceive/node 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-6HALOJYF.js → chunk-ZYS6QECW.js} +968 -25
- package/dist/cli.d.ts +19 -1
- package/dist/cli.js +273 -9
- package/dist/index.d.ts +6 -4
- package/dist/index.js +35 -974
- package/package.json +3 -2
- package/skills/debug-openreceive-payment/SKILL.md +88 -0
- package/skills/integrate-openreceive/SKILL.md +116 -0
- package/skills/integrate-openreceive/references/node.md +480 -0
- package/skills/integrate-openreceive/references/rails.md +568 -0
package/dist/cli.d.ts
CHANGED
|
@@ -48,6 +48,15 @@ declare function runScaffoldPayments(input: RunScaffoldPaymentsInput): Promise<n
|
|
|
48
48
|
interface CliIo {
|
|
49
49
|
write(message: string): void;
|
|
50
50
|
}
|
|
51
|
+
/** The two doctor probe methods a wallet client must answer. */
|
|
52
|
+
interface DoctorWalletClient {
|
|
53
|
+
preflight(): Promise<{
|
|
54
|
+
readonly methods: readonly string[];
|
|
55
|
+
readonly spendCapabilityAdvertised: boolean;
|
|
56
|
+
readonly warnings: readonly string[];
|
|
57
|
+
}>;
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
}
|
|
51
60
|
interface CliOptions {
|
|
52
61
|
readonly argv: readonly string[];
|
|
53
62
|
readonly env?: NodeJS.ProcessEnv;
|
|
@@ -57,7 +66,16 @@ interface CliOptions {
|
|
|
57
66
|
readonly stdin?: NodeJS.ReadableStream;
|
|
58
67
|
readonly isTTY?: boolean;
|
|
59
68
|
readonly prompt?: (question: string) => Promise<string>;
|
|
69
|
+
/**
|
|
70
|
+
* Testing seam for `doctor`: builds the wallet client the relay probe uses.
|
|
71
|
+
* Defaults to the real NWC client.
|
|
72
|
+
*/
|
|
73
|
+
readonly walletClientFactory?: (options: {
|
|
74
|
+
connectionString: string;
|
|
75
|
+
allowSpendCapableWallet: boolean;
|
|
76
|
+
spendCapabilityWarning: (message: string) => void;
|
|
77
|
+
}) => DoctorWalletClient;
|
|
60
78
|
}
|
|
61
79
|
declare function runCli(options: CliOptions): Promise<number>;
|
|
62
80
|
|
|
63
|
-
export { type CliIo, type CliOptions, finalizeScaffoldOptions, parseScaffoldPaymentsArgv, renderScaffoldPaymentsFiles, runCli, runScaffoldPayments };
|
|
81
|
+
export { type CliIo, type CliOptions, type DoctorWalletClient, finalizeScaffoldOptions, parseScaffoldPaymentsArgv, renderScaffoldPaymentsFiles, runCli, runScaffoldPayments };
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
|
+
createNwcReceiveClient,
|
|
2
3
|
readLscConnectionsFromEnvironment,
|
|
3
4
|
redactSecrets
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZYS6QECW.js";
|
|
5
6
|
|
|
6
7
|
// src/cli.ts
|
|
7
|
-
import {
|
|
8
|
+
import { existsSync } from "fs";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import path2 from "path";
|
|
11
|
+
import { pathToFileURL } from "url";
|
|
12
|
+
import {
|
|
13
|
+
formatInvalidNwcMessage,
|
|
14
|
+
NwcUriParseError,
|
|
15
|
+
OPENRECEIVE_NWC_CODE_HELP_URL,
|
|
16
|
+
parseNwcUri
|
|
17
|
+
} from "@openreceive/core";
|
|
8
18
|
|
|
9
19
|
// src/scaffold/index.ts
|
|
10
20
|
import { createInterface } from "readline/promises";
|
|
@@ -912,13 +922,26 @@ var HELP = `
|
|
|
912
922
|
Usage: openreceive <command> [options]
|
|
913
923
|
|
|
914
924
|
Commands:
|
|
915
|
-
doctor Validate server configuration
|
|
925
|
+
doctor Validate server configuration: Node, NWC_URI, swap
|
|
926
|
+
providers, and a receive-only wallet probe over the relay.
|
|
927
|
+
--db and --url extend the checks; exits 1 on problems.
|
|
916
928
|
debug-report Print the same diagnostics as a redacted support report
|
|
917
929
|
(alias of doctor; always exits 0).
|
|
918
930
|
scaffold payments Emit the openreceive_payments + openreceive_meta migration and wiring guide for your ORM.
|
|
919
931
|
|
|
920
932
|
Options:
|
|
921
933
|
-h, --help Show this help.
|
|
934
|
+
|
|
935
|
+
Doctor options:
|
|
936
|
+
--db <target> Also check the payment tables exist: a SQLite file
|
|
937
|
+
path, or a postgres:// / mysql:// URL (the matching
|
|
938
|
+
driver is loaded from this project's node_modules).
|
|
939
|
+
--url <base-url> Also check the OpenReceive routes answer on a
|
|
940
|
+
running app, e.g. --url http://localhost:3000.
|
|
941
|
+
--prefix <path> Route prefix for --url (default /openreceive).
|
|
942
|
+
--table-name <name> Payments table for --db (default openreceive_payments).
|
|
943
|
+
--meta-table-name <name> Reconcile-gate table for --db (default openreceive_meta).
|
|
944
|
+
--offline Skip the wallet relay probe.
|
|
922
945
|
`.trim();
|
|
923
946
|
async function runCli(options) {
|
|
924
947
|
const stdout = options.stdout ?? process.stdout;
|
|
@@ -933,8 +956,14 @@ async function runCli(options) {
|
|
|
933
956
|
return 0;
|
|
934
957
|
}
|
|
935
958
|
if (command === "doctor" || command === "debug-report") {
|
|
936
|
-
|
|
937
|
-
|
|
959
|
+
return await runDiagnostics({
|
|
960
|
+
command,
|
|
961
|
+
flags: parseDiagnosticsArgv(args),
|
|
962
|
+
env,
|
|
963
|
+
cwd,
|
|
964
|
+
stdout,
|
|
965
|
+
walletClientFactory: options.walletClientFactory
|
|
966
|
+
});
|
|
938
967
|
}
|
|
939
968
|
if (command === "scaffold") {
|
|
940
969
|
const [target = "help", ...scaffoldArgs] = args;
|
|
@@ -967,8 +996,42 @@ ${HELP}
|
|
|
967
996
|
return 1;
|
|
968
997
|
}
|
|
969
998
|
}
|
|
970
|
-
function
|
|
971
|
-
const
|
|
999
|
+
function parseDiagnosticsArgv(args) {
|
|
1000
|
+
const flags = {
|
|
1001
|
+
db: void 0,
|
|
1002
|
+
url: void 0,
|
|
1003
|
+
prefix: "/openreceive",
|
|
1004
|
+
tableName: "openreceive_payments",
|
|
1005
|
+
metaTableName: "openreceive_meta",
|
|
1006
|
+
offline: false
|
|
1007
|
+
};
|
|
1008
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
1009
|
+
const arg = args[index];
|
|
1010
|
+
const valueFor = (name) => {
|
|
1011
|
+
const value = args[index + 1];
|
|
1012
|
+
if (value === void 0 || value.startsWith("--")) {
|
|
1013
|
+
throw new Error(`${name} needs a value. See \`openreceive --help\`.`);
|
|
1014
|
+
}
|
|
1015
|
+
index += 1;
|
|
1016
|
+
return value;
|
|
1017
|
+
};
|
|
1018
|
+
if (arg === "--db") flags.db = valueFor("--db");
|
|
1019
|
+
else if (arg === "--url") flags.url = valueFor("--url");
|
|
1020
|
+
else if (arg === "--prefix") flags.prefix = valueFor("--prefix");
|
|
1021
|
+
else if (arg === "--table-name") flags.tableName = valueFor("--table-name");
|
|
1022
|
+
else if (arg === "--meta-table-name") flags.metaTableName = valueFor("--meta-table-name");
|
|
1023
|
+
else if (arg === "--offline") flags.offline = true;
|
|
1024
|
+
else throw new Error(`Unexpected option: ${arg}. See \`openreceive --help\`.`);
|
|
1025
|
+
}
|
|
1026
|
+
if (!flags.prefix.startsWith("/")) flags.prefix = `/${flags.prefix}`;
|
|
1027
|
+
return flags;
|
|
1028
|
+
}
|
|
1029
|
+
var WALLET_PROBE_TIMEOUT_MS = 1e4;
|
|
1030
|
+
var HTTP_PROBE_TIMEOUT_MS = 5e3;
|
|
1031
|
+
var SPEND_OVERRIDE_TRUE = /* @__PURE__ */ new Set(["1", "true", "yes"]);
|
|
1032
|
+
async function runDiagnostics(input) {
|
|
1033
|
+
const { flags, env } = input;
|
|
1034
|
+
const nwc = env.NWC_URI?.trim();
|
|
972
1035
|
let nwcError;
|
|
973
1036
|
try {
|
|
974
1037
|
if (nwc) parseNwcUri(nwc);
|
|
@@ -978,7 +1041,7 @@ function runDiagnostics(input) {
|
|
|
978
1041
|
let lscConnections = 0;
|
|
979
1042
|
let lscError;
|
|
980
1043
|
try {
|
|
981
|
-
lscConnections = readLscConnectionsFromEnvironment(
|
|
1044
|
+
lscConnections = readLscConnectionsFromEnvironment(env).length;
|
|
982
1045
|
} catch (error) {
|
|
983
1046
|
lscError = error;
|
|
984
1047
|
}
|
|
@@ -990,10 +1053,211 @@ function runDiagnostics(input) {
|
|
|
990
1053
|
`NWC_URI: ${nwcError === void 0 ? nwc ? "present-redacted" : "missing" : safeErrorMessage(nwcError)}`,
|
|
991
1054
|
`LSC_URI connections: ${lscError === void 0 ? lscConnections : safeErrorMessage(lscError)}`
|
|
992
1055
|
];
|
|
1056
|
+
let failed = nwcError !== void 0 || !nwc || lscError !== void 0;
|
|
1057
|
+
if (nwc && nwcError === void 0 && !flags.offline) {
|
|
1058
|
+
const wallet = await probeWallet({
|
|
1059
|
+
nwc,
|
|
1060
|
+
env,
|
|
1061
|
+
walletClientFactory: input.walletClientFactory
|
|
1062
|
+
});
|
|
1063
|
+
failed = failed || !wallet.ok;
|
|
1064
|
+
lines.push(...wallet.lines);
|
|
1065
|
+
} else if (flags.offline) {
|
|
1066
|
+
lines.push("wallet: probe skipped (--offline)");
|
|
1067
|
+
} else {
|
|
1068
|
+
lines.push("wallet: probe skipped (no parseable NWC_URI to probe)");
|
|
1069
|
+
}
|
|
1070
|
+
if (flags.db === void 0) {
|
|
1071
|
+
lines.push(
|
|
1072
|
+
"database: skipped \u2014 pass --db <sqlite file | postgres:// | mysql:// URL> to check the payment tables exist"
|
|
1073
|
+
);
|
|
1074
|
+
} else {
|
|
1075
|
+
const database = await checkDatabaseMigrated({ ...flags, db: flags.db, cwd: input.cwd });
|
|
1076
|
+
failed = failed || !database.ok;
|
|
1077
|
+
lines.push(...database.lines);
|
|
1078
|
+
}
|
|
1079
|
+
if (flags.url === void 0) {
|
|
1080
|
+
lines.push(
|
|
1081
|
+
"routes: skipped \u2014 pass --url http://localhost:3000 to check the OpenReceive routes answer"
|
|
1082
|
+
);
|
|
1083
|
+
} else {
|
|
1084
|
+
const routes = await checkRoutesMounted({ url: flags.url, prefix: flags.prefix });
|
|
1085
|
+
failed = failed || !routes.ok;
|
|
1086
|
+
lines.push(...routes.lines);
|
|
1087
|
+
}
|
|
993
1088
|
input.stdout.write(`${lines.join("\n")}
|
|
994
1089
|
`);
|
|
995
1090
|
if (input.command === "debug-report") return 0;
|
|
996
|
-
return
|
|
1091
|
+
return failed ? 1 : 0;
|
|
1092
|
+
}
|
|
1093
|
+
async function probeWallet(input) {
|
|
1094
|
+
const allowSpendCapableWallet = SPEND_OVERRIDE_TRUE.has(
|
|
1095
|
+
input.env.OPENRECEIVE_ALLOW_SPEND_CAPABLE_NWC?.trim().toLowerCase() ?? ""
|
|
1096
|
+
);
|
|
1097
|
+
const overrideWarnings = [];
|
|
1098
|
+
const factory = input.walletClientFactory ?? ((options) => createNwcReceiveClient(options));
|
|
1099
|
+
const client = factory({
|
|
1100
|
+
connectionString: input.nwc,
|
|
1101
|
+
allowSpendCapableWallet,
|
|
1102
|
+
spendCapabilityWarning: (message) => overrideWarnings.push(message)
|
|
1103
|
+
});
|
|
1104
|
+
let timer;
|
|
1105
|
+
try {
|
|
1106
|
+
const summary = await Promise.race([
|
|
1107
|
+
client.preflight(),
|
|
1108
|
+
new Promise((_, reject) => {
|
|
1109
|
+
timer = setTimeout(() => {
|
|
1110
|
+
reject(
|
|
1111
|
+
new Error(
|
|
1112
|
+
`no relay answered within ${WALLET_PROBE_TIMEOUT_MS / 1e3}s. Check the network and the wss relay in the NWC code, or rerun with --offline to skip the probe.`
|
|
1113
|
+
)
|
|
1114
|
+
);
|
|
1115
|
+
}, WALLET_PROBE_TIMEOUT_MS);
|
|
1116
|
+
timer.unref?.();
|
|
1117
|
+
})
|
|
1118
|
+
]);
|
|
1119
|
+
if (summary.spendCapabilityAdvertised) {
|
|
1120
|
+
return {
|
|
1121
|
+
ok: false,
|
|
1122
|
+
lines: [
|
|
1123
|
+
`wallet: reachable but SPEND-CAPABLE (override active). A leaked code can drain this wallet \u2014 mint a receive-only code: ${OPENRECEIVE_NWC_CODE_HELP_URL}`,
|
|
1124
|
+
...summary.warnings.map((warning) => `wallet: ${warning}`)
|
|
1125
|
+
]
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
return {
|
|
1129
|
+
ok: true,
|
|
1130
|
+
lines: [
|
|
1131
|
+
`wallet: reachable, receive-only (${summary.methods.join(", ")})`,
|
|
1132
|
+
...summary.warnings.map((warning) => `wallet: ${warning}`)
|
|
1133
|
+
]
|
|
1134
|
+
};
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
return { ok: false, lines: [`wallet: ${safeErrorMessage(error)}`] };
|
|
1137
|
+
} finally {
|
|
1138
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1139
|
+
try {
|
|
1140
|
+
await client.close();
|
|
1141
|
+
} catch {
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
async function checkDatabaseMigrated(input) {
|
|
1146
|
+
const fix = `run \`npx openreceive scaffold payments --orm <your orm>\` and apply the emitted migration through your normal workflow \u2014 https://openreceive.org/guides/storage.md`;
|
|
1147
|
+
try {
|
|
1148
|
+
const present = await listPresentTables(input);
|
|
1149
|
+
const missing = [input.tableName, input.metaTableName].filter(
|
|
1150
|
+
(table) => !present.includes(table)
|
|
1151
|
+
);
|
|
1152
|
+
if (missing.length === 0) {
|
|
1153
|
+
return {
|
|
1154
|
+
ok: true,
|
|
1155
|
+
lines: [`database: ${input.tableName} and ${input.metaTableName} present`]
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
return {
|
|
1159
|
+
ok: false,
|
|
1160
|
+
lines: [`database: ${missing.join(" and ")} missing \u2014 the migration has not run; ${fix}`]
|
|
1161
|
+
};
|
|
1162
|
+
} catch (error) {
|
|
1163
|
+
return { ok: false, lines: [`database: ${safeErrorMessage(error)}`] };
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
async function listPresentTables(input) {
|
|
1167
|
+
const tables = [input.tableName, input.metaTableName];
|
|
1168
|
+
if (/^postgres(ql)?:/.test(input.db)) {
|
|
1169
|
+
const pg = await importFromHostProject("pg", input.cwd);
|
|
1170
|
+
const client = new pg.Client({
|
|
1171
|
+
connectionString: input.db,
|
|
1172
|
+
connectionTimeoutMillis: HTTP_PROBE_TIMEOUT_MS
|
|
1173
|
+
});
|
|
1174
|
+
await client.connect();
|
|
1175
|
+
try {
|
|
1176
|
+
const result = await client.query(
|
|
1177
|
+
"SELECT to_regclass($1) AS a, to_regclass($2) AS b",
|
|
1178
|
+
tables
|
|
1179
|
+
);
|
|
1180
|
+
const row = result.rows[0] ?? {};
|
|
1181
|
+
return tables.filter((_, index) => row[index === 0 ? "a" : "b"] !== null);
|
|
1182
|
+
} finally {
|
|
1183
|
+
await client.end();
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
if (/^mysql:/.test(input.db)) {
|
|
1187
|
+
const mysql = await importFromHostProject("mysql2/promise", input.cwd);
|
|
1188
|
+
const connection = await mysql.createConnection(input.db);
|
|
1189
|
+
try {
|
|
1190
|
+
const [rows] = await connection.query(
|
|
1191
|
+
"SELECT table_name AS name FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name IN (?, ?)",
|
|
1192
|
+
tables
|
|
1193
|
+
);
|
|
1194
|
+
return rows.map((row) => String(row.name));
|
|
1195
|
+
} finally {
|
|
1196
|
+
await connection.end();
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
const sqlitePath = path2.isAbsolute(input.db) ? input.db : path2.join(input.cwd, input.db);
|
|
1200
|
+
if (!existsSync(sqlitePath)) {
|
|
1201
|
+
throw new Error(
|
|
1202
|
+
`no SQLite database at ${sqlitePath}. Pass the file your app opens, or a postgres:// / mysql:// URL.`
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1205
|
+
const { DatabaseSync } = await import("sqlite");
|
|
1206
|
+
const database = new DatabaseSync(sqlitePath, { readOnly: true });
|
|
1207
|
+
try {
|
|
1208
|
+
const rows = database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name IN (?, ?)").all(...tables);
|
|
1209
|
+
return rows.map((row) => row.name);
|
|
1210
|
+
} finally {
|
|
1211
|
+
database.close();
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
async function importFromHostProject(specifier, cwd) {
|
|
1215
|
+
let resolved;
|
|
1216
|
+
try {
|
|
1217
|
+
resolved = createRequire(path2.join(cwd, "package.json")).resolve(specifier);
|
|
1218
|
+
} catch {
|
|
1219
|
+
throw new Error(
|
|
1220
|
+
`this database needs the ${JSON.stringify(specifier.split("/")[0])} driver, which is not installed here. Install it (\`npm install ${specifier.split("/")[0]}\`) or point --db at the SQLite file directly.`
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
1224
|
+
return mod.default ?? mod;
|
|
1225
|
+
}
|
|
1226
|
+
async function checkRoutesMounted(input) {
|
|
1227
|
+
const base = input.url.replace(/\/+$/, "");
|
|
1228
|
+
const prefix = input.prefix.replace(/\/+$/, "");
|
|
1229
|
+
const probe = `${base}${prefix}/__doctor-probe__`;
|
|
1230
|
+
const fix = `mount the router (\`app.use(openreceive)\` \u2014 https://openreceive.org/guides/quickstart-node.md), or pass --prefix if it is mounted somewhere other than ${prefix}`;
|
|
1231
|
+
let response;
|
|
1232
|
+
try {
|
|
1233
|
+
response = await fetch(probe, {
|
|
1234
|
+
headers: { accept: "application/json" },
|
|
1235
|
+
signal: AbortSignal.timeout(HTTP_PROBE_TIMEOUT_MS)
|
|
1236
|
+
});
|
|
1237
|
+
} catch (error) {
|
|
1238
|
+
return {
|
|
1239
|
+
ok: false,
|
|
1240
|
+
lines: [
|
|
1241
|
+
`routes: could not reach ${base} (${safeErrorMessage(error)}) \u2014 is the app running at that URL?`
|
|
1242
|
+
]
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
let body;
|
|
1246
|
+
try {
|
|
1247
|
+
body = JSON.parse(await response.text());
|
|
1248
|
+
} catch {
|
|
1249
|
+
body = void 0;
|
|
1250
|
+
}
|
|
1251
|
+
const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : "";
|
|
1252
|
+
if (message.startsWith("No OpenReceive route matched")) {
|
|
1253
|
+
return { ok: true, lines: [`routes: OpenReceive router answering at ${base}${prefix}`] };
|
|
1254
|
+
}
|
|
1255
|
+
return {
|
|
1256
|
+
ok: false,
|
|
1257
|
+
lines: [
|
|
1258
|
+
`routes: nothing OpenReceive answered at ${base}${prefix} (HTTP ${response.status}) \u2014 ${fix}`
|
|
1259
|
+
]
|
|
1260
|
+
};
|
|
997
1261
|
}
|
|
998
1262
|
function safeErrorMessage(error) {
|
|
999
1263
|
if (error instanceof Error) return redactSecrets(error.message);
|
package/dist/index.d.ts
CHANGED
|
@@ -180,10 +180,12 @@ type SwapAvailabilityReason = "provider_unconfigured" | "amount_too_small" | "am
|
|
|
180
180
|
type SwapAttentionReason = "provider_completed_without_wallet_settlement" | "provider_order_creation_stale" | "provider_order_creation_failed" | "provider_order_creation_needs_reconcile" | "provider_reported_emergency" | "provider_status_unrecognized" | "provider_order_expires_after_shadow_invoice";
|
|
181
181
|
/**
|
|
182
182
|
* Why a swap attempt entered the refund path (`refund_required` → `refunded`).
|
|
183
|
-
* Mapped from FixedFloat `emergency.status` (LESS / EXPIRED).
|
|
184
|
-
*
|
|
183
|
+
* Mapped from FixedFloat `emergency.status` (LESS / MORE / EXPIRED). An overpay
|
|
184
|
+
* refunds the WHOLE deposit like every other emergency: the payout is a
|
|
185
|
+
* fixed-amount bolt11, so there is nothing to exchange the surplus into and
|
|
186
|
+
* `choice=EXCHANGE` is not a path this client takes.
|
|
185
187
|
*/
|
|
186
|
-
type SwapRefundReason = "underpaid" | "late_deposit" | "underpaid_and_late";
|
|
188
|
+
type SwapRefundReason = "underpaid" | "overpaid" | "late_deposit" | "underpaid_and_late" | "overpaid_and_late";
|
|
187
189
|
interface SwapQuote {
|
|
188
190
|
readonly pay_amount?: string;
|
|
189
191
|
readonly minimum_pay_amount?: string;
|
|
@@ -239,7 +241,7 @@ interface SwapOrder {
|
|
|
239
241
|
readonly attention_reason?: SwapAttentionReason;
|
|
240
242
|
/**
|
|
241
243
|
* Why a refund is needed, when the attempt is on the refund path. Mapped from
|
|
242
|
-
* FixedFloat `emergency.status` (LESS / EXPIRED).
|
|
244
|
+
* FixedFloat `emergency.status` (LESS / MORE / EXPIRED).
|
|
243
245
|
*/
|
|
244
246
|
readonly refund_reason?: SwapRefundReason;
|
|
245
247
|
/**
|