@palindromepay/sdk 1.9.8 → 2.0.0
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/PalindromePaySDK.d.ts +20 -6
- package/dist/PalindromePaySDK.js +181 -24
- package/dist/contract/PalindromePay.json +1204 -1
- package/dist/contract/PalindromePayWallet.json +306 -1
- package/package.json +1 -1
|
@@ -86,7 +86,8 @@ export declare enum SDKErrorCode {
|
|
|
86
86
|
RPC_ERROR = "RPC_ERROR",
|
|
87
87
|
EVIDENCE_ALREADY_SUBMITTED = "EVIDENCE_ALREADY_SUBMITTED",
|
|
88
88
|
ESCROW_NOT_FOUND = "ESCROW_NOT_FOUND",
|
|
89
|
-
ALREADY_ACCEPTED = "ALREADY_ACCEPTED"
|
|
89
|
+
ALREADY_ACCEPTED = "ALREADY_ACCEPTED",
|
|
90
|
+
SIGNATURE_INVALID = "SIGNATURE_INVALID"
|
|
90
91
|
}
|
|
91
92
|
export type EscrowWalletClient = WalletClient<Transport, Chain, Account>;
|
|
92
93
|
export declare class SDKError extends Error {
|
|
@@ -235,7 +236,6 @@ export declare class PalindromePaySDK {
|
|
|
235
236
|
/** Cache for token decimals (rarely changes, no eviction needed) */
|
|
236
237
|
private tokenDecimalsCache;
|
|
237
238
|
/** Cache for immutable contract values */
|
|
238
|
-
private walletBytecodeHashCache;
|
|
239
239
|
private feeReceiverCache;
|
|
240
240
|
/** Cached multicall support status per chain (null = not yet detected) */
|
|
241
241
|
private multicallSupported;
|
|
@@ -332,6 +332,11 @@ export declare class PalindromePaySDK {
|
|
|
332
332
|
* Used for: deposit, confirmDelivery, requestCancel, submitArbiterDecision
|
|
333
333
|
*/
|
|
334
334
|
signWalletAuthorization(walletClient: EscrowWalletClient, walletAddress: Address, escrowId: bigint): Promise<Hex>;
|
|
335
|
+
/**
|
|
336
|
+
* Verify a wallet authorization signature locally before submitting transaction
|
|
337
|
+
* This ensures the signature is cryptographically valid for the expected signer
|
|
338
|
+
*/
|
|
339
|
+
private verifyWalletSignature;
|
|
335
340
|
/**
|
|
336
341
|
* Sign a confirm delivery message (for gasless meta-tx)
|
|
337
342
|
*/
|
|
@@ -350,6 +355,7 @@ export declare class PalindromePaySDK {
|
|
|
350
355
|
isSignatureDeadlineExpired(deadline: bigint, safetySeconds?: number): boolean;
|
|
351
356
|
/**
|
|
352
357
|
* Predict the wallet address for a given escrow ID (before creation)
|
|
358
|
+
* Uses CREATE2 address computation: keccak256(0xff ++ deployer ++ salt ++ initCodeHash)
|
|
353
359
|
*/
|
|
354
360
|
predictWalletAddress(escrowId: bigint): Promise<Address>;
|
|
355
361
|
/**
|
|
@@ -489,6 +495,7 @@ export declare class PalindromePaySDK {
|
|
|
489
495
|
escrowId: bigint;
|
|
490
496
|
txHash: Hex;
|
|
491
497
|
walletAddress: Address;
|
|
498
|
+
signatureValid: boolean;
|
|
492
499
|
}>;
|
|
493
500
|
/**
|
|
494
501
|
* Create a new escrow and deposit funds as the buyer (single transaction)
|
|
@@ -518,6 +525,7 @@ export declare class PalindromePaySDK {
|
|
|
518
525
|
escrowId: bigint;
|
|
519
526
|
txHash: Hex;
|
|
520
527
|
walletAddress: Address;
|
|
528
|
+
signatureValid: boolean;
|
|
521
529
|
}>;
|
|
522
530
|
/**
|
|
523
531
|
* Deposit funds into an existing escrow as the buyer
|
|
@@ -531,13 +539,16 @@ export declare class PalindromePaySDK {
|
|
|
531
539
|
*
|
|
532
540
|
* @param walletClient - The buyer's wallet client (must have account connected)
|
|
533
541
|
* @param escrowId - The escrow ID to deposit into
|
|
534
|
-
* @returns
|
|
542
|
+
* @returns Object containing transaction hash and signature validity
|
|
535
543
|
* @throws {SDKError} WALLET_NOT_CONNECTED - If wallet client is not connected
|
|
536
544
|
* @throws {SDKError} NOT_BUYER - If caller is not the designated buyer
|
|
537
545
|
* @throws {SDKError} INVALID_STATE - If escrow is not in AWAITING_PAYMENT state
|
|
538
546
|
* @throws {SDKError} INSUFFICIENT_BALANCE - If buyer has insufficient token balance
|
|
539
547
|
*/
|
|
540
|
-
deposit(walletClient: EscrowWalletClient, escrowId: bigint): Promise<
|
|
548
|
+
deposit(walletClient: EscrowWalletClient, escrowId: bigint): Promise<{
|
|
549
|
+
txHash: Hex;
|
|
550
|
+
signatureValid: boolean;
|
|
551
|
+
}>;
|
|
541
552
|
/**
|
|
542
553
|
* Accept an escrow as the seller (for buyer-created escrows)
|
|
543
554
|
*
|
|
@@ -549,13 +560,16 @@ export declare class PalindromePaySDK {
|
|
|
549
560
|
*
|
|
550
561
|
* @param walletClient - The seller's wallet client (must have account connected)
|
|
551
562
|
* @param escrowId - The escrow ID to accept
|
|
552
|
-
* @returns
|
|
563
|
+
* @returns Object containing transaction hash and signature validity
|
|
553
564
|
* @throws {SDKError} WALLET_NOT_CONNECTED - If wallet client is not connected
|
|
554
565
|
* @throws {SDKError} NOT_SELLER - If caller is not the designated seller
|
|
555
566
|
* @throws {SDKError} INVALID_STATE - If escrow is not in AWAITING_DELIVERY state
|
|
556
567
|
* @throws {SDKError} ALREADY_ACCEPTED - If escrow was already accepted
|
|
557
568
|
*/
|
|
558
|
-
acceptEscrow(walletClient: EscrowWalletClient, escrowId: bigint): Promise<
|
|
569
|
+
acceptEscrow(walletClient: EscrowWalletClient, escrowId: bigint): Promise<{
|
|
570
|
+
txHash: Hex;
|
|
571
|
+
signatureValid: boolean;
|
|
572
|
+
}>;
|
|
559
573
|
/**
|
|
560
574
|
* Confirm delivery and release funds to the seller
|
|
561
575
|
*
|
package/dist/PalindromePaySDK.js
CHANGED
|
@@ -130,6 +130,7 @@ var SDKErrorCode;
|
|
|
130
130
|
SDKErrorCode["EVIDENCE_ALREADY_SUBMITTED"] = "EVIDENCE_ALREADY_SUBMITTED";
|
|
131
131
|
SDKErrorCode["ESCROW_NOT_FOUND"] = "ESCROW_NOT_FOUND";
|
|
132
132
|
SDKErrorCode["ALREADY_ACCEPTED"] = "ALREADY_ACCEPTED";
|
|
133
|
+
SDKErrorCode["SIGNATURE_INVALID"] = "SIGNATURE_INVALID";
|
|
133
134
|
})(SDKErrorCode || (exports.SDKErrorCode = SDKErrorCode = {}));
|
|
134
135
|
class SDKError extends Error {
|
|
135
136
|
constructor(message, code, details) {
|
|
@@ -199,7 +200,6 @@ class PalindromePaySDK {
|
|
|
199
200
|
/** Cache for token decimals (rarely changes, no eviction needed) */
|
|
200
201
|
this.tokenDecimalsCache = new Map();
|
|
201
202
|
/** Cache for immutable contract values */
|
|
202
|
-
this.walletBytecodeHashCache = null;
|
|
203
203
|
this.feeReceiverCache = null;
|
|
204
204
|
/** Cached multicall support status per chain (null = not yet detected) */
|
|
205
205
|
this.multicallSupported = null;
|
|
@@ -574,6 +574,32 @@ class PalindromePaySDK {
|
|
|
574
574
|
validateSignature(signature, "wallet authorization signature");
|
|
575
575
|
return signature;
|
|
576
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* Verify a wallet authorization signature locally before submitting transaction
|
|
579
|
+
* This ensures the signature is cryptographically valid for the expected signer
|
|
580
|
+
*/
|
|
581
|
+
async verifyWalletSignature(signature, walletAddress, escrowId, expectedSigner) {
|
|
582
|
+
try {
|
|
583
|
+
return await (0, viem_1.verifyTypedData)({
|
|
584
|
+
address: expectedSigner,
|
|
585
|
+
domain: this.getWalletDomain(walletAddress),
|
|
586
|
+
types: this.walletAuthorizationTypes,
|
|
587
|
+
primaryType: "WalletAuthorization",
|
|
588
|
+
message: {
|
|
589
|
+
escrowId,
|
|
590
|
+
wallet: walletAddress,
|
|
591
|
+
participant: expectedSigner,
|
|
592
|
+
},
|
|
593
|
+
signature,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
catch (error) {
|
|
597
|
+
this.log('warn', 'Signature verification failed', {
|
|
598
|
+
error: error instanceof Error ? error.message : String(error),
|
|
599
|
+
});
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
577
603
|
/**
|
|
578
604
|
* Sign a confirm delivery message (for gasless meta-tx)
|
|
579
605
|
*/
|
|
@@ -645,24 +671,28 @@ class PalindromePaySDK {
|
|
|
645
671
|
// ==========================================================================
|
|
646
672
|
/**
|
|
647
673
|
* Predict the wallet address for a given escrow ID (before creation)
|
|
674
|
+
* Uses CREATE2 address computation: keccak256(0xff ++ deployer ++ salt ++ initCodeHash)
|
|
648
675
|
*/
|
|
649
676
|
async predictWalletAddress(escrowId) {
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
abi: this.abiEscrow,
|
|
656
|
-
functionName: "WALLET_BYTECODE_HASH",
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
// Compute CREATE2 address
|
|
677
|
+
// Salt is keccak256 of the escrowId padded to 32 bytes
|
|
678
|
+
const salt = (0, viem_1.keccak256)((0, viem_1.encodeAbiParameters)([{ type: "uint256" }], [escrowId]));
|
|
679
|
+
// Get wallet bytecode from the ABI JSON
|
|
680
|
+
const walletBytecode = PalindromePayWallet_json_1.default.bytecode;
|
|
681
|
+
// Encode constructor arguments: (address _escrowContract, uint256 _escrowId)
|
|
660
682
|
const encodedArgs = (0, viem_1.encodeAbiParameters)([{ type: "address" }, { type: "uint256" }], [this.contractAddress, escrowId]);
|
|
661
|
-
//
|
|
662
|
-
|
|
663
|
-
const initCodeHash = (0, viem_1.keccak256)(
|
|
664
|
-
|
|
665
|
-
|
|
683
|
+
// initCode = bytecode + encoded constructor args
|
|
684
|
+
const initCode = (0, viem_1.concat)([walletBytecode, encodedArgs]);
|
|
685
|
+
const initCodeHash = (0, viem_1.keccak256)(initCode);
|
|
686
|
+
// CREATE2 address: keccak256(0xff ++ deployer ++ salt ++ initCodeHash)[12:]
|
|
687
|
+
const data = (0, viem_1.concat)([
|
|
688
|
+
"0xff",
|
|
689
|
+
this.contractAddress,
|
|
690
|
+
salt,
|
|
691
|
+
initCodeHash,
|
|
692
|
+
]);
|
|
693
|
+
const hash = (0, viem_1.keccak256)(data);
|
|
694
|
+
// Take the last 20 bytes (address is derived from bytes 12-31)
|
|
695
|
+
return (0, viem_1.getAddress)(`0x${hash.slice(26)}`);
|
|
666
696
|
}
|
|
667
697
|
// ==========================================================================
|
|
668
698
|
// ESCROW DATA READING
|
|
@@ -1053,6 +1083,11 @@ class PalindromePaySDK {
|
|
|
1053
1083
|
const predictedWallet = await this.predictWalletAddress(nextId);
|
|
1054
1084
|
// Sign wallet authorization
|
|
1055
1085
|
const sellerWalletSig = await this.signWalletAuthorization(walletClient, predictedWallet, nextId);
|
|
1086
|
+
// Pre-validate signature before submitting transaction
|
|
1087
|
+
const isValidSig = await this.verifyWalletSignature(sellerWalletSig, predictedWallet, nextId, walletClient.account.address);
|
|
1088
|
+
if (!isValidSig) {
|
|
1089
|
+
throw new SDKError("Seller wallet signature is invalid - cannot create escrow", SDKErrorCode.SIGNATURE_INVALID);
|
|
1090
|
+
}
|
|
1056
1091
|
// Create escrow
|
|
1057
1092
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1058
1093
|
address: this.contractAddress,
|
|
@@ -1081,7 +1116,30 @@ class PalindromePaySDK {
|
|
|
1081
1116
|
});
|
|
1082
1117
|
const escrowId = events[0]?.args?.escrowId ?? nextId;
|
|
1083
1118
|
const deal = await this.getEscrowByIdParsed(escrowId);
|
|
1084
|
-
|
|
1119
|
+
// Verify seller signature is valid on-chain after creation
|
|
1120
|
+
let sellerSigValid = false;
|
|
1121
|
+
try {
|
|
1122
|
+
sellerSigValid = await this.publicClient.readContract({
|
|
1123
|
+
address: deal.wallet,
|
|
1124
|
+
abi: this.abiWallet,
|
|
1125
|
+
functionName: "isSignatureValid",
|
|
1126
|
+
args: [walletClient.account.address],
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
this.log('warn', 'Failed to verify seller signature after escrow creation', {
|
|
1131
|
+
escrowId: escrowId.toString(),
|
|
1132
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
if (!sellerSigValid) {
|
|
1136
|
+
this.log('error', 'Seller wallet signature is invalid after escrow creation', {
|
|
1137
|
+
escrowId: escrowId.toString(),
|
|
1138
|
+
seller: walletClient.account.address,
|
|
1139
|
+
wallet: deal.wallet,
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
return { escrowId, txHash: hash, walletAddress: deal.wallet, signatureValid: sellerSigValid };
|
|
1085
1143
|
}
|
|
1086
1144
|
/**
|
|
1087
1145
|
* Create a new escrow and deposit funds as the buyer (single transaction)
|
|
@@ -1144,6 +1202,11 @@ class PalindromePaySDK {
|
|
|
1144
1202
|
const predictedWallet = await this.predictWalletAddress(nextId);
|
|
1145
1203
|
// Sign wallet authorization
|
|
1146
1204
|
const buyerWalletSig = await this.signWalletAuthorization(walletClient, predictedWallet, nextId);
|
|
1205
|
+
// Pre-validate signature before submitting transaction
|
|
1206
|
+
const isValidSig = await this.verifyWalletSignature(buyerWalletSig, predictedWallet, nextId, walletClient.account.address);
|
|
1207
|
+
if (!isValidSig) {
|
|
1208
|
+
throw new SDKError("Buyer wallet signature is invalid - cannot create escrow", SDKErrorCode.SIGNATURE_INVALID);
|
|
1209
|
+
}
|
|
1147
1210
|
// Create escrow and deposit
|
|
1148
1211
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1149
1212
|
address: this.contractAddress,
|
|
@@ -1172,7 +1235,30 @@ class PalindromePaySDK {
|
|
|
1172
1235
|
});
|
|
1173
1236
|
const escrowId = events[0]?.args?.escrowId ?? nextId;
|
|
1174
1237
|
const deal = await this.getEscrowByIdParsed(escrowId);
|
|
1175
|
-
|
|
1238
|
+
// Verify buyer signature is valid on-chain after creation
|
|
1239
|
+
let buyerSigValid = false;
|
|
1240
|
+
try {
|
|
1241
|
+
buyerSigValid = await this.publicClient.readContract({
|
|
1242
|
+
address: deal.wallet,
|
|
1243
|
+
abi: this.abiWallet,
|
|
1244
|
+
functionName: "isSignatureValid",
|
|
1245
|
+
args: [walletClient.account.address],
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
catch (error) {
|
|
1249
|
+
this.log('warn', 'Failed to verify buyer signature after escrow creation', {
|
|
1250
|
+
escrowId: escrowId.toString(),
|
|
1251
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
if (!buyerSigValid) {
|
|
1255
|
+
this.log('error', 'Buyer wallet signature is invalid after escrow creation', {
|
|
1256
|
+
escrowId: escrowId.toString(),
|
|
1257
|
+
buyer: walletClient.account.address,
|
|
1258
|
+
wallet: deal.wallet,
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
return { escrowId, txHash: hash, walletAddress: deal.wallet, signatureValid: buyerSigValid };
|
|
1176
1262
|
}
|
|
1177
1263
|
// ==========================================================================
|
|
1178
1264
|
// DEPOSIT
|
|
@@ -1189,7 +1275,7 @@ class PalindromePaySDK {
|
|
|
1189
1275
|
*
|
|
1190
1276
|
* @param walletClient - The buyer's wallet client (must have account connected)
|
|
1191
1277
|
* @param escrowId - The escrow ID to deposit into
|
|
1192
|
-
* @returns
|
|
1278
|
+
* @returns Object containing transaction hash and signature validity
|
|
1193
1279
|
* @throws {SDKError} WALLET_NOT_CONNECTED - If wallet client is not connected
|
|
1194
1280
|
* @throws {SDKError} NOT_BUYER - If caller is not the designated buyer
|
|
1195
1281
|
* @throws {SDKError} INVALID_STATE - If escrow is not in AWAITING_PAYMENT state
|
|
@@ -1203,8 +1289,13 @@ class PalindromePaySDK {
|
|
|
1203
1289
|
this.verifyState(deal, EscrowState.AWAITING_PAYMENT, "deposit");
|
|
1204
1290
|
// Approve token spending
|
|
1205
1291
|
await this.approveTokenIfNeeded(walletClient, deal.token, this.contractAddress, deal.amount);
|
|
1206
|
-
// Sign wallet authorization
|
|
1292
|
+
// Sign wallet authorization using the wallet address from the escrow
|
|
1207
1293
|
const buyerWalletSig = await this.signWalletAuthorization(walletClient, deal.wallet, escrowId);
|
|
1294
|
+
// Pre-validate signature before submitting transaction
|
|
1295
|
+
const isValidSig = await this.verifyWalletSignature(buyerWalletSig, deal.wallet, escrowId, walletClient.account.address);
|
|
1296
|
+
if (!isValidSig) {
|
|
1297
|
+
throw new SDKError("Buyer wallet signature is invalid - cannot deposit", SDKErrorCode.SIGNATURE_INVALID);
|
|
1298
|
+
}
|
|
1208
1299
|
// Deposit
|
|
1209
1300
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1210
1301
|
address: this.contractAddress,
|
|
@@ -1213,7 +1304,30 @@ class PalindromePaySDK {
|
|
|
1213
1304
|
args: [escrowId, buyerWalletSig],
|
|
1214
1305
|
});
|
|
1215
1306
|
await this.waitForReceipt(hash);
|
|
1216
|
-
|
|
1307
|
+
// Verify buyer signature is valid on-chain after deposit
|
|
1308
|
+
let buyerSigValid = false;
|
|
1309
|
+
try {
|
|
1310
|
+
buyerSigValid = await this.publicClient.readContract({
|
|
1311
|
+
address: deal.wallet,
|
|
1312
|
+
abi: this.abiWallet,
|
|
1313
|
+
functionName: "isSignatureValid",
|
|
1314
|
+
args: [walletClient.account.address],
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
catch (error) {
|
|
1318
|
+
this.log('warn', 'Failed to verify buyer signature after deposit', {
|
|
1319
|
+
escrowId: escrowId.toString(),
|
|
1320
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
if (!buyerSigValid) {
|
|
1324
|
+
this.log('error', 'Buyer wallet signature is invalid after deposit', {
|
|
1325
|
+
escrowId: escrowId.toString(),
|
|
1326
|
+
buyer: walletClient.account.address,
|
|
1327
|
+
wallet: deal.wallet,
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
return { txHash: hash, signatureValid: buyerSigValid };
|
|
1217
1331
|
}
|
|
1218
1332
|
// ==========================================================================
|
|
1219
1333
|
// ACCEPT ESCROW (for buyer-created escrows)
|
|
@@ -1229,7 +1343,7 @@ class PalindromePaySDK {
|
|
|
1229
1343
|
*
|
|
1230
1344
|
* @param walletClient - The seller's wallet client (must have account connected)
|
|
1231
1345
|
* @param escrowId - The escrow ID to accept
|
|
1232
|
-
* @returns
|
|
1346
|
+
* @returns Object containing transaction hash and signature validity
|
|
1233
1347
|
* @throws {SDKError} WALLET_NOT_CONNECTED - If wallet client is not connected
|
|
1234
1348
|
* @throws {SDKError} NOT_SELLER - If caller is not the designated seller
|
|
1235
1349
|
* @throws {SDKError} INVALID_STATE - If escrow is not in AWAITING_DELIVERY state
|
|
@@ -1245,8 +1359,13 @@ class PalindromePaySDK {
|
|
|
1245
1359
|
if (deal.sellerWalletSig && deal.sellerWalletSig !== "0x") {
|
|
1246
1360
|
throw new SDKError("Escrow already accepted", SDKErrorCode.ALREADY_ACCEPTED);
|
|
1247
1361
|
}
|
|
1248
|
-
// Sign wallet authorization
|
|
1362
|
+
// Sign wallet authorization using the wallet address from the escrow
|
|
1249
1363
|
const sellerWalletSig = await this.signWalletAuthorization(walletClient, deal.wallet, escrowId);
|
|
1364
|
+
// Pre-validate signature before submitting transaction
|
|
1365
|
+
const isValidSig = await this.verifyWalletSignature(sellerWalletSig, deal.wallet, escrowId, walletClient.account.address);
|
|
1366
|
+
if (!isValidSig) {
|
|
1367
|
+
throw new SDKError("Seller wallet signature is invalid - cannot accept escrow", SDKErrorCode.SIGNATURE_INVALID);
|
|
1368
|
+
}
|
|
1250
1369
|
// Accept escrow
|
|
1251
1370
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1252
1371
|
address: this.contractAddress,
|
|
@@ -1255,7 +1374,30 @@ class PalindromePaySDK {
|
|
|
1255
1374
|
args: [escrowId, sellerWalletSig],
|
|
1256
1375
|
});
|
|
1257
1376
|
await this.waitForReceipt(hash);
|
|
1258
|
-
|
|
1377
|
+
// Verify seller signature is valid on-chain after accept
|
|
1378
|
+
let sellerSigValid = false;
|
|
1379
|
+
try {
|
|
1380
|
+
sellerSigValid = await this.publicClient.readContract({
|
|
1381
|
+
address: deal.wallet,
|
|
1382
|
+
abi: this.abiWallet,
|
|
1383
|
+
functionName: "isSignatureValid",
|
|
1384
|
+
args: [walletClient.account.address],
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
catch (error) {
|
|
1388
|
+
this.log('warn', 'Failed to verify seller signature after accept', {
|
|
1389
|
+
escrowId: escrowId.toString(),
|
|
1390
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
if (!sellerSigValid) {
|
|
1394
|
+
this.log('error', 'Seller wallet signature is invalid after accept', {
|
|
1395
|
+
escrowId: escrowId.toString(),
|
|
1396
|
+
seller: walletClient.account.address,
|
|
1397
|
+
wallet: deal.wallet,
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
return { txHash: hash, signatureValid: sellerSigValid };
|
|
1259
1401
|
}
|
|
1260
1402
|
// ==========================================================================
|
|
1261
1403
|
// CONFIRM DELIVERY
|
|
@@ -1286,6 +1428,11 @@ class PalindromePaySDK {
|
|
|
1286
1428
|
this.verifyState(deal, EscrowState.AWAITING_DELIVERY, "confirm delivery");
|
|
1287
1429
|
// Sign wallet authorization
|
|
1288
1430
|
const buyerWalletSig = await this.signWalletAuthorization(walletClient, deal.wallet, escrowId);
|
|
1431
|
+
// Pre-validate signature before submitting transaction
|
|
1432
|
+
const isValidSig = await this.verifyWalletSignature(buyerWalletSig, deal.wallet, escrowId, walletClient.account.address);
|
|
1433
|
+
if (!isValidSig) {
|
|
1434
|
+
throw new SDKError("Buyer wallet signature is invalid - cannot confirm delivery", SDKErrorCode.SIGNATURE_INVALID);
|
|
1435
|
+
}
|
|
1289
1436
|
// Confirm delivery
|
|
1290
1437
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1291
1438
|
address: this.contractAddress,
|
|
@@ -1397,6 +1544,11 @@ class PalindromePaySDK {
|
|
|
1397
1544
|
}
|
|
1398
1545
|
// Sign wallet authorization
|
|
1399
1546
|
const walletSig = await this.signWalletAuthorization(walletClient, deal.wallet, escrowId);
|
|
1547
|
+
// Pre-validate signature before submitting transaction
|
|
1548
|
+
const isValidSig = await this.verifyWalletSignature(walletSig, deal.wallet, escrowId, walletClient.account.address);
|
|
1549
|
+
if (!isValidSig) {
|
|
1550
|
+
throw new SDKError("Wallet signature is invalid - cannot request cancel", SDKErrorCode.SIGNATURE_INVALID);
|
|
1551
|
+
}
|
|
1400
1552
|
// Request cancel
|
|
1401
1553
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1402
1554
|
address: this.contractAddress,
|
|
@@ -1634,6 +1786,11 @@ class PalindromePaySDK {
|
|
|
1634
1786
|
this.verifyArbiter(walletClient.account.address, deal);
|
|
1635
1787
|
// Sign wallet authorization
|
|
1636
1788
|
const arbiterWalletSig = await this.signWalletAuthorization(walletClient, deal.wallet, escrowId);
|
|
1789
|
+
// Pre-validate signature before submitting transaction
|
|
1790
|
+
const isValidSig = await this.verifyWalletSignature(arbiterWalletSig, deal.wallet, escrowId, walletClient.account.address);
|
|
1791
|
+
if (!isValidSig) {
|
|
1792
|
+
throw new SDKError("Arbiter wallet signature is invalid - cannot submit decision", SDKErrorCode.SIGNATURE_INVALID);
|
|
1793
|
+
}
|
|
1637
1794
|
// Submit decision
|
|
1638
1795
|
const hash = await this.resilientWriteContract(walletClient, {
|
|
1639
1796
|
address: this.contractAddress,
|