@arkade-os/sdk 0.3.7 → 0.3.8
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.
|
@@ -138,6 +138,15 @@ class Worker {
|
|
|
138
138
|
scripts: [script],
|
|
139
139
|
});
|
|
140
140
|
const vtxos = response.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo));
|
|
141
|
+
try {
|
|
142
|
+
// recover pending transactions
|
|
143
|
+
const { finalized, pending } = await this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
144
|
+
vtxo.virtualStatus.state !== "settled"));
|
|
145
|
+
console.info(`Recovered ${finalized.length}/${pending.length} pending transactions: ${finalized.join(", ")}`);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error("Error recovering pending transactions:", error);
|
|
149
|
+
}
|
|
141
150
|
// Get wallet address and save vtxos using unified repository
|
|
142
151
|
const address = await this.wallet.getAddress();
|
|
143
152
|
await this.walletRepository.saveVtxos(address, vtxos);
|
|
@@ -1011,6 +1011,67 @@ class Wallet {
|
|
|
1011
1011
|
message: encodedMessage,
|
|
1012
1012
|
};
|
|
1013
1013
|
}
|
|
1014
|
+
async makeGetPendingTxIntentSignature(vtxos) {
|
|
1015
|
+
const inputs = this.prepareIntentProofInputs(vtxos);
|
|
1016
|
+
const message = {
|
|
1017
|
+
type: "get-pending-tx",
|
|
1018
|
+
expire_at: 0,
|
|
1019
|
+
};
|
|
1020
|
+
const encodedMessage = JSON.stringify(message, null, 0);
|
|
1021
|
+
const proof = intent_1.Intent.create(encodedMessage, inputs, []);
|
|
1022
|
+
const signedProof = await this.identity.sign(proof);
|
|
1023
|
+
return {
|
|
1024
|
+
proof: base_1.base64.encode(signedProof.toPSBT()),
|
|
1025
|
+
message: encodedMessage,
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Finalizes pending transactions by retrieving them from the server and finalizing each one.
|
|
1030
|
+
* @param vtxos - Optional list of VTXOs to use instead of retrieving them from the server
|
|
1031
|
+
* @returns Array of transaction IDs that were finalized
|
|
1032
|
+
*/
|
|
1033
|
+
async finalizePendingTxs(vtxos) {
|
|
1034
|
+
const MAX_INPUTS_PER_INTENT = 20;
|
|
1035
|
+
if (!vtxos || vtxos.length === 0) {
|
|
1036
|
+
// get non-swept VTXOs, rely on the indexer only in case DB doesn't have the right state
|
|
1037
|
+
const scripts = [base_1.hex.encode(this.offchainTapscript.pkScript)];
|
|
1038
|
+
let { vtxos: fetchedVtxos } = await this.indexerProvider.getVtxos({
|
|
1039
|
+
scripts,
|
|
1040
|
+
});
|
|
1041
|
+
fetchedVtxos = fetchedVtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
1042
|
+
vtxo.virtualStatus.state !== "settled");
|
|
1043
|
+
if (fetchedVtxos.length === 0) {
|
|
1044
|
+
return { finalized: [], pending: [] };
|
|
1045
|
+
}
|
|
1046
|
+
vtxos = fetchedVtxos.map((v) => (0, utils_1.extendVirtualCoin)(this, v));
|
|
1047
|
+
}
|
|
1048
|
+
const finalized = [];
|
|
1049
|
+
const pending = [];
|
|
1050
|
+
for (let i = 0; i < vtxos.length; i += MAX_INPUTS_PER_INTENT) {
|
|
1051
|
+
const batch = vtxos.slice(i, i + MAX_INPUTS_PER_INTENT);
|
|
1052
|
+
const intent = await this.makeGetPendingTxIntentSignature(batch);
|
|
1053
|
+
const pendingTxs = await this.arkProvider.getPendingTxs(intent);
|
|
1054
|
+
// finalize each transaction by signing the checkpoints
|
|
1055
|
+
for (const pendingTx of pendingTxs) {
|
|
1056
|
+
pending.push(pendingTx.arkTxid);
|
|
1057
|
+
try {
|
|
1058
|
+
// sign the checkpoints
|
|
1059
|
+
const finalCheckpoints = await Promise.all(pendingTx.signedCheckpointTxs.map(async (c) => {
|
|
1060
|
+
const tx = btc_signer_1.Transaction.fromPSBT(base_1.base64.decode(c));
|
|
1061
|
+
const signedCheckpoint = await this.identity.sign(tx);
|
|
1062
|
+
return base_1.base64.encode(signedCheckpoint.toPSBT());
|
|
1063
|
+
}));
|
|
1064
|
+
await this.arkProvider.finalizeTx(pendingTx.arkTxid, finalCheckpoints);
|
|
1065
|
+
finalized.push(pendingTx.arkTxid);
|
|
1066
|
+
}
|
|
1067
|
+
catch (error) {
|
|
1068
|
+
console.error(`Failed to finalize transaction ${pendingTx.arkTxid}:`, error);
|
|
1069
|
+
// continue with other transactions even if one fails
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return { finalized, pending };
|
|
1074
|
+
}
|
|
1014
1075
|
prepareIntentProofInputs(coins) {
|
|
1015
1076
|
const inputs = [];
|
|
1016
1077
|
for (const input of coins) {
|
|
@@ -135,6 +135,15 @@ export class Worker {
|
|
|
135
135
|
scripts: [script],
|
|
136
136
|
});
|
|
137
137
|
const vtxos = response.vtxos.map((vtxo) => extendVirtualCoin(this.wallet, vtxo));
|
|
138
|
+
try {
|
|
139
|
+
// recover pending transactions
|
|
140
|
+
const { finalized, pending } = await this.wallet.finalizePendingTxs(vtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
141
|
+
vtxo.virtualStatus.state !== "settled"));
|
|
142
|
+
console.info(`Recovered ${finalized.length}/${pending.length} pending transactions: ${finalized.join(", ")}`);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
console.error("Error recovering pending transactions:", error);
|
|
146
|
+
}
|
|
138
147
|
// Get wallet address and save vtxos using unified repository
|
|
139
148
|
const address = await this.wallet.getAddress();
|
|
140
149
|
await this.walletRepository.saveVtxos(address, vtxos);
|
|
@@ -974,6 +974,67 @@ export class Wallet {
|
|
|
974
974
|
message: encodedMessage,
|
|
975
975
|
};
|
|
976
976
|
}
|
|
977
|
+
async makeGetPendingTxIntentSignature(vtxos) {
|
|
978
|
+
const inputs = this.prepareIntentProofInputs(vtxos);
|
|
979
|
+
const message = {
|
|
980
|
+
type: "get-pending-tx",
|
|
981
|
+
expire_at: 0,
|
|
982
|
+
};
|
|
983
|
+
const encodedMessage = JSON.stringify(message, null, 0);
|
|
984
|
+
const proof = Intent.create(encodedMessage, inputs, []);
|
|
985
|
+
const signedProof = await this.identity.sign(proof);
|
|
986
|
+
return {
|
|
987
|
+
proof: base64.encode(signedProof.toPSBT()),
|
|
988
|
+
message: encodedMessage,
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Finalizes pending transactions by retrieving them from the server and finalizing each one.
|
|
993
|
+
* @param vtxos - Optional list of VTXOs to use instead of retrieving them from the server
|
|
994
|
+
* @returns Array of transaction IDs that were finalized
|
|
995
|
+
*/
|
|
996
|
+
async finalizePendingTxs(vtxos) {
|
|
997
|
+
const MAX_INPUTS_PER_INTENT = 20;
|
|
998
|
+
if (!vtxos || vtxos.length === 0) {
|
|
999
|
+
// get non-swept VTXOs, rely on the indexer only in case DB doesn't have the right state
|
|
1000
|
+
const scripts = [hex.encode(this.offchainTapscript.pkScript)];
|
|
1001
|
+
let { vtxos: fetchedVtxos } = await this.indexerProvider.getVtxos({
|
|
1002
|
+
scripts,
|
|
1003
|
+
});
|
|
1004
|
+
fetchedVtxos = fetchedVtxos.filter((vtxo) => vtxo.virtualStatus.state !== "swept" &&
|
|
1005
|
+
vtxo.virtualStatus.state !== "settled");
|
|
1006
|
+
if (fetchedVtxos.length === 0) {
|
|
1007
|
+
return { finalized: [], pending: [] };
|
|
1008
|
+
}
|
|
1009
|
+
vtxos = fetchedVtxos.map((v) => extendVirtualCoin(this, v));
|
|
1010
|
+
}
|
|
1011
|
+
const finalized = [];
|
|
1012
|
+
const pending = [];
|
|
1013
|
+
for (let i = 0; i < vtxos.length; i += MAX_INPUTS_PER_INTENT) {
|
|
1014
|
+
const batch = vtxos.slice(i, i + MAX_INPUTS_PER_INTENT);
|
|
1015
|
+
const intent = await this.makeGetPendingTxIntentSignature(batch);
|
|
1016
|
+
const pendingTxs = await this.arkProvider.getPendingTxs(intent);
|
|
1017
|
+
// finalize each transaction by signing the checkpoints
|
|
1018
|
+
for (const pendingTx of pendingTxs) {
|
|
1019
|
+
pending.push(pendingTx.arkTxid);
|
|
1020
|
+
try {
|
|
1021
|
+
// sign the checkpoints
|
|
1022
|
+
const finalCheckpoints = await Promise.all(pendingTx.signedCheckpointTxs.map(async (c) => {
|
|
1023
|
+
const tx = Transaction.fromPSBT(base64.decode(c));
|
|
1024
|
+
const signedCheckpoint = await this.identity.sign(tx);
|
|
1025
|
+
return base64.encode(signedCheckpoint.toPSBT());
|
|
1026
|
+
}));
|
|
1027
|
+
await this.arkProvider.finalizeTx(pendingTx.arkTxid, finalCheckpoints);
|
|
1028
|
+
finalized.push(pendingTx.arkTxid);
|
|
1029
|
+
}
|
|
1030
|
+
catch (error) {
|
|
1031
|
+
console.error(`Failed to finalize transaction ${pendingTx.arkTxid}:`, error);
|
|
1032
|
+
// continue with other transactions even if one fails
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return { finalized, pending };
|
|
1037
|
+
}
|
|
977
1038
|
prepareIntentProofInputs(coins) {
|
|
978
1039
|
const inputs = [];
|
|
979
1040
|
for (const input of coins) {
|
|
@@ -97,6 +97,16 @@ export declare class Wallet implements IWallet {
|
|
|
97
97
|
safeRegisterIntent(intent: SignedIntent): Promise<string>;
|
|
98
98
|
makeRegisterIntentSignature(coins: ExtendedCoin[], outputs: TransactionOutput[], onchainOutputsIndexes: number[], cosignerPubKeys: string[]): Promise<SignedIntent>;
|
|
99
99
|
makeDeleteIntentSignature(coins: ExtendedCoin[]): Promise<SignedIntent>;
|
|
100
|
+
makeGetPendingTxIntentSignature(vtxos: ExtendedVirtualCoin[]): Promise<SignedIntent>;
|
|
101
|
+
/**
|
|
102
|
+
* Finalizes pending transactions by retrieving them from the server and finalizing each one.
|
|
103
|
+
* @param vtxos - Optional list of VTXOs to use instead of retrieving them from the server
|
|
104
|
+
* @returns Array of transaction IDs that were finalized
|
|
105
|
+
*/
|
|
106
|
+
finalizePendingTxs(vtxos?: ExtendedVirtualCoin[]): Promise<{
|
|
107
|
+
finalized: string[];
|
|
108
|
+
pending: string[];
|
|
109
|
+
}>;
|
|
100
110
|
private prepareIntentProofInputs;
|
|
101
111
|
}
|
|
102
112
|
/**
|