@openzeppelin/relayer-plugin-channels 0.20.0 → 0.21.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/plugin/fee.d.ts +5 -0
- package/dist/plugin/fee.d.ts.map +1 -1
- package/dist/plugin/fee.js +15 -7
- package/dist/plugin/handler.d.ts.map +1 -1
- package/dist/plugin/handler.js +10 -7
- package/dist/plugin/sequence.d.ts.map +1 -1
- package/dist/plugin/sequence.js +6 -3
- package/dist/plugin/simulation.d.ts +10 -0
- package/dist/plugin/simulation.d.ts.map +1 -1
- package/dist/plugin/simulation.js +33 -9
- package/dist/plugin/submit.d.ts.map +1 -1
- package/dist/plugin/submit.js +8 -6
- package/dist/plugin/tx.d.ts +7 -0
- package/dist/plugin/tx.d.ts.map +1 -1
- package/dist/plugin/tx.js +11 -6
- package/dist/plugin/validation.d.ts +7 -0
- package/dist/plugin/validation.d.ts.map +1 -1
- package/dist/plugin/validation.js +10 -4
- package/package.json +2 -2
- package/dist/plugin/build.d.ts +0 -21
- package/dist/plugin/build.d.ts.map +0 -1
- package/dist/plugin/build.js +0 -101
package/dist/plugin/fee.d.ts
CHANGED
|
@@ -20,5 +20,10 @@ export declare function getContractIdFromFunc(func: xdr.HostFunction): string |
|
|
|
20
20
|
* Extract contract ID from a Transaction (for XDR flow)
|
|
21
21
|
*/
|
|
22
22
|
export declare function getContractIdFromTransaction(transaction: Transaction): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Compute the maximum fee (in stroops) for a transaction: the Soroban resource
|
|
25
|
+
* fee declared in the envelope's sorobanData (0 for classic transactions) plus
|
|
26
|
+
* the inclusion fee, which is higher when the invoked contract is rate-limited.
|
|
27
|
+
*/
|
|
23
28
|
export declare function calculateMaxFee(transaction: Transaction, limitedContracts: Set<string>, fees: InclusionFees): number;
|
|
24
29
|
//# sourceMappingURL=fee.d.ts.map
|
package/dist/plugin/fee.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fee.d.ts","sourceRoot":"","sources":["../../src/plugin/fee.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,GAAG,EAAqB,MAAM,sBAAsB,CAAC;AAG3E,MAAM,WAAW,aAAa;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"fee.d.ts","sourceRoot":"","sources":["../../src/plugin/fee.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,GAAG,EAAqB,MAAM,sBAAsB,CAAC;AAG3E,MAAM,WAAW,aAAa;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,GAAG,CAAC,YAAY,GAAG,MAAM,GAAG,SAAS,CAahF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAYzF;AASD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAgCpH"}
|
package/dist/plugin/fee.js
CHANGED
|
@@ -19,11 +19,14 @@ const constants_1 = require("./constants");
|
|
|
19
19
|
*/
|
|
20
20
|
function getContractIdFromFunc(func) {
|
|
21
21
|
try {
|
|
22
|
-
if (func.
|
|
22
|
+
if (func.type !== 'hostFunctionTypeInvokeContract') {
|
|
23
23
|
return undefined;
|
|
24
24
|
}
|
|
25
|
-
const
|
|
26
|
-
|
|
25
|
+
const contractAddress = func.invokeContract.contractAddress;
|
|
26
|
+
if (contractAddress.type !== 'scAddressTypeContract') {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return stellar_sdk_1.StrKey.encodeContract(contractAddress.contractId.toBytes());
|
|
27
30
|
}
|
|
28
31
|
catch {
|
|
29
32
|
return undefined;
|
|
@@ -52,13 +55,18 @@ function getInclusionFee(contractId, limitedContracts, fees) {
|
|
|
52
55
|
}
|
|
53
56
|
return fees.inclusionFeeDefault;
|
|
54
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Compute the maximum fee (in stroops) for a transaction: the Soroban resource
|
|
60
|
+
* fee declared in the envelope's sorobanData (0 for classic transactions) plus
|
|
61
|
+
* the inclusion fee, which is higher when the invoked contract is rate-limited.
|
|
62
|
+
*/
|
|
55
63
|
function calculateMaxFee(transaction, limitedContracts, fees) {
|
|
56
64
|
const envelope = transaction.toEnvelope();
|
|
57
65
|
let resourceFee = 0n;
|
|
58
|
-
if (envelope.
|
|
59
|
-
const
|
|
60
|
-
if (sorobanData) {
|
|
61
|
-
resourceFee = sorobanData.resourceFee
|
|
66
|
+
if (envelope.type === 'envelopeTypeTx') {
|
|
67
|
+
const ext = envelope.v1.tx.ext;
|
|
68
|
+
if (ext.type === 'sorobanData') {
|
|
69
|
+
resourceFee = ext.sorobanData.resourceFee;
|
|
62
70
|
}
|
|
63
71
|
}
|
|
64
72
|
const contractId = getContractIdFromTransaction(transaction);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,EAA4B,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAQnF,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAaxD,8EAA8E;AAC9E,KAAK,iBAAiB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAUnE,kDAAkD;AAClD,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAanC;AAiCD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AACvE,OAAO,KAAK,EAA4B,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAQnF,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AAaxD,8EAA8E;AAC9E,KAAK,iBAAiB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAUnE,kDAAkD;AAClD,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAanC;AAiCD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,EAAE,EAAE,WAAW,GACd;IAAE,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CAqB1E;AA6UD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -77,14 +77,17 @@ function extractFuncAuthFromUnsignedXdr(tx) {
|
|
|
77
77
|
return null;
|
|
78
78
|
}
|
|
79
79
|
const envelope = tx.toEnvelope();
|
|
80
|
-
|
|
81
|
-
if (rawOp.switch() !== stellar_sdk_1.xdr.OperationType.invokeHostFunction()) {
|
|
80
|
+
if (envelope.type !== 'envelopeTypeTx') {
|
|
82
81
|
return null;
|
|
83
82
|
}
|
|
84
|
-
const
|
|
83
|
+
const rawOp = envelope.v1.tx.operations[0].body;
|
|
84
|
+
if (rawOp.type !== 'invokeHostFunction') {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const invokeHostFn = rawOp.invokeHostFunctionOp;
|
|
85
88
|
return {
|
|
86
|
-
func: invokeHostFn.hostFunction
|
|
87
|
-
auth: invokeHostFn.auth
|
|
89
|
+
func: invokeHostFn.hostFunction,
|
|
90
|
+
auth: [...invokeHostFn.auth],
|
|
88
91
|
};
|
|
89
92
|
}
|
|
90
93
|
async function handleXdrSubmit(xdrStr, ctx, skipWait) {
|
|
@@ -116,7 +119,7 @@ async function handleXdrSubmit(xdrStr, ctx, skipWait) {
|
|
|
116
119
|
contractId,
|
|
117
120
|
isLimited: contractId ? ctx.acquireOptions.limitedContracts.has(contractId) : false,
|
|
118
121
|
};
|
|
119
|
-
return (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, validated.
|
|
122
|
+
return (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, validated.toXdr(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
|
|
120
123
|
}
|
|
121
124
|
async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
|
|
122
125
|
// Simulate once — used for both read-only detection and transaction assembly
|
|
@@ -167,7 +170,7 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
|
|
|
167
170
|
isLimited: contractId ? ctx.acquireOptions.limitedContracts.has(contractId) : false,
|
|
168
171
|
};
|
|
169
172
|
try {
|
|
170
|
-
const result = await (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, signedTx.
|
|
173
|
+
const result = await (0, submit_1.submitWithFeeBumpAndWait)(ctx.fundRelayer, signedTx.toXdr(), ctx.network, maxFee, ctx.api, ctx.startTime, ctx.tracker, submitContext, skipWait, ctx.config);
|
|
171
174
|
if (result.status === 'pending' || result.status === 'sent' || result.status === 'submitted') {
|
|
172
175
|
const extendSec = computeExtendTtlSec(txBuildTime, ctx.config.maxTimeBoundOffsetSeconds);
|
|
173
176
|
console.log(`[channels]: extending lock (${extendSec}s) and clearing sequence`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/plugin/sequence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAwBxE;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/plugin/sequence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAwBxE;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyH3F;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,2BAA2B,EAAE,MAAM,GAClC,OAAO,CAAC,MAAM,CAAC,CAwBjB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWtG"}
|
package/dist/plugin/sequence.js
CHANGED
|
@@ -56,7 +56,7 @@ async function getAccountSequence(relayer, address) {
|
|
|
56
56
|
id: Math.floor(Math.random() * 1e8).toString(),
|
|
57
57
|
method: 'getLedgerEntries',
|
|
58
58
|
params: {
|
|
59
|
-
keys: [accountKey.
|
|
59
|
+
keys: [accountKey.toXdr('base64')],
|
|
60
60
|
},
|
|
61
61
|
});
|
|
62
62
|
}
|
|
@@ -126,8 +126,11 @@ async function getAccountSequence(relayer, address) {
|
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
try {
|
|
129
|
-
const accountEntry = stellar_sdk_1.xdr.LedgerEntryData.
|
|
130
|
-
|
|
129
|
+
const accountEntry = stellar_sdk_1.xdr.LedgerEntryData.fromXdr(firstEntryXdr, 'base64');
|
|
130
|
+
if (accountEntry.type !== 'account') {
|
|
131
|
+
throw new Error(`Unexpected ledger entry type: ${accountEntry.type}`);
|
|
132
|
+
}
|
|
133
|
+
return accountEntry.account.seqNum.toString();
|
|
131
134
|
}
|
|
132
135
|
catch (error) {
|
|
133
136
|
console.error('[channels] Sequence fetch failed', {
|
|
@@ -40,6 +40,16 @@ export declare function simulateTransaction(func: xdr.HostFunction, auth: xdr.So
|
|
|
40
40
|
* obtained simulation result. No additional network calls are made.
|
|
41
41
|
*/
|
|
42
42
|
export declare function buildWithChannel(func: xdr.HostFunction, auth: xdr.SorobanAuthorizationEntry[] | undefined, channel: ChannelAccount, networkPassphrase: string, simResult: rpc.Api.RawSimulateTransactionResponse, minSignatureExpirationLedgerBuffer?: number, maxTimeBoundOffsetSeconds?: number): Transaction;
|
|
43
|
+
/**
|
|
44
|
+
* Return the signatureExpirationLedger of an address-credentialed auth entry,
|
|
45
|
+
* or undefined for source-account credentials (which carry no expiry).
|
|
46
|
+
*
|
|
47
|
+
* Reads the expiry directly off the credential arm so every variant is covered
|
|
48
|
+
* with an exhaustive switch: legacy `sorobanCredentialsAddress`, CAP-71
|
|
49
|
+
* `sorobanCredentialsAddressV2` (introduced in Protocol 27, the stellar-sdk v17
|
|
50
|
+
* default) and `sorobanCredentialsAddressWithDelegates`.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getAddressCredentialExpiry(entry: xdr.SorobanAuthorizationEntry): number | undefined;
|
|
43
53
|
/** Extract human-readable message + error type from simulation error diagnostic events */
|
|
44
54
|
export declare function parseSimulationError(error: string): string;
|
|
45
55
|
//# sourceMappingURL=simulation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,GAAG,EAAE,WAAW,EAAsB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAgD,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC;CACtD;AAOD;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,EACzB,yBAAyB,GAAE,MAA2C,GACrE,OAAO,CAAC,gBAAgB,CAAC,CAiF3B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,EACjD,kCAAkC,GAAE,MAA0D,EAC9F,yBAAyB,GAAE,MAA2C,GACrE,WAAW,
|
|
1
|
+
{"version":3,"file":"simulation.d.ts","sourceRoot":"","sources":["../../src/plugin/simulation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAsB,GAAG,EAAE,WAAW,EAAsB,GAAG,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAgD,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAGlG,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,YAAY,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,CAAC;CACtD;AAOD;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,OAAO,EAChB,iBAAiB,EAAE,MAAM,EACzB,yBAAyB,GAAE,MAA2C,GACrE,OAAO,CAAC,gBAAgB,CAAC,CAiF3B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,GAAG,CAAC,YAAY,EACtB,IAAI,EAAE,GAAG,CAAC,yBAAyB,EAAE,GAAG,SAAS,EACjD,OAAO,EAAE,cAAc,EACvB,iBAAiB,EAAE,MAAM,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,8BAA8B,EACjD,kCAAkC,GAAE,MAA0D,EAC9F,yBAAyB,GAAE,MAA2C,GACrE,WAAW,CAiGb;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,GAAG,CAAC,yBAAyB,GAAG,MAAM,GAAG,SAAS,CAYnG;AA2CD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.simulateTransaction = simulateTransaction;
|
|
12
12
|
exports.buildWithChannel = buildWithChannel;
|
|
13
|
+
exports.getAddressCredentialExpiry = getAddressCredentialExpiry;
|
|
13
14
|
exports.parseSimulationError = parseSimulationError;
|
|
14
15
|
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
15
16
|
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
@@ -42,7 +43,7 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
|
|
|
42
43
|
id: Math.floor(Math.random() * 1e8).toString(),
|
|
43
44
|
method: 'simulateTransaction',
|
|
44
45
|
// Enforce mode validates auth entry signatures during simulation.
|
|
45
|
-
params: { transaction: transaction.
|
|
46
|
+
params: { transaction: transaction.toXdr(), authMode: constants_1.SIMULATION.SIMULATION_AUTH_MODE },
|
|
46
47
|
});
|
|
47
48
|
}
|
|
48
49
|
catch (err) {
|
|
@@ -81,8 +82,8 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
|
|
|
81
82
|
let hasReadWrite = false;
|
|
82
83
|
if (simResult.transactionData) {
|
|
83
84
|
try {
|
|
84
|
-
const sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.
|
|
85
|
-
hasReadWrite = sorobanData.resources
|
|
85
|
+
const sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXdr(simResult.transactionData, 'base64');
|
|
86
|
+
hasReadWrite = sorobanData.resources.footprint.readWrite.length > 0;
|
|
86
87
|
}
|
|
87
88
|
catch {
|
|
88
89
|
// If we can't parse transactionData, treat as not read-only (safe fallback)
|
|
@@ -114,7 +115,7 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
|
|
|
114
115
|
// Parse sorobanData from the simulation result
|
|
115
116
|
let sorobanData;
|
|
116
117
|
try {
|
|
117
|
-
sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.
|
|
118
|
+
sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXdr(simResult.transactionData, 'base64');
|
|
118
119
|
}
|
|
119
120
|
catch (err) {
|
|
120
121
|
throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation transactionData', {
|
|
@@ -130,7 +131,7 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
|
|
|
130
131
|
}
|
|
131
132
|
else {
|
|
132
133
|
try {
|
|
133
|
-
resolvedAuth = (simResult.results?.[0]?.auth ?? []).map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.
|
|
134
|
+
resolvedAuth = (simResult.results?.[0]?.auth ?? []).map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXdr(a, 'base64'));
|
|
134
135
|
}
|
|
135
136
|
catch (err) {
|
|
136
137
|
throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation auth entries', {
|
|
@@ -177,7 +178,9 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
|
|
|
177
178
|
}))
|
|
178
179
|
.build();
|
|
179
180
|
try {
|
|
180
|
-
const
|
|
181
|
+
const envelope = transaction.toEnvelope();
|
|
182
|
+
const ext = envelope.type === 'envelopeTypeTx' ? envelope.v1.tx.ext : undefined;
|
|
183
|
+
const resourceFee = ext?.type === 'sorobanData' ? ext.sorobanData.resourceFee : undefined;
|
|
181
184
|
console.debug(`[channels] Assembly complete: fee=${transaction.fee}, resourceFee=${resourceFee}`);
|
|
182
185
|
return transaction;
|
|
183
186
|
}
|
|
@@ -192,6 +195,28 @@ function buildWithChannel(func, auth, channel, networkPassphrase, simResult, min
|
|
|
192
195
|
});
|
|
193
196
|
}
|
|
194
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Return the signatureExpirationLedger of an address-credentialed auth entry,
|
|
200
|
+
* or undefined for source-account credentials (which carry no expiry).
|
|
201
|
+
*
|
|
202
|
+
* Reads the expiry directly off the credential arm so every variant is covered
|
|
203
|
+
* with an exhaustive switch: legacy `sorobanCredentialsAddress`, CAP-71
|
|
204
|
+
* `sorobanCredentialsAddressV2` (introduced in Protocol 27, the stellar-sdk v17
|
|
205
|
+
* default) and `sorobanCredentialsAddressWithDelegates`.
|
|
206
|
+
*/
|
|
207
|
+
function getAddressCredentialExpiry(entry) {
|
|
208
|
+
const creds = entry.credentials;
|
|
209
|
+
switch (creds.type) {
|
|
210
|
+
case 'sorobanCredentialsSourceAccount':
|
|
211
|
+
return undefined;
|
|
212
|
+
case 'sorobanCredentialsAddress':
|
|
213
|
+
return creds.address.signatureExpirationLedger;
|
|
214
|
+
case 'sorobanCredentialsAddressV2':
|
|
215
|
+
return creds.addressV2.signatureExpirationLedger;
|
|
216
|
+
case 'sorobanCredentialsAddressWithDelegates':
|
|
217
|
+
return creds.addressWithDelegates.addressCredentials.signatureExpirationLedger;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
195
220
|
/**
|
|
196
221
|
* Reject transactions where any address-credentialed auth entry has a
|
|
197
222
|
* signatureExpirationLedger too close to the current ledger. This catches
|
|
@@ -201,11 +226,10 @@ function validateAuthExpiry(authEntries, latestLedger, minBuffer) {
|
|
|
201
226
|
if (!authEntries?.length)
|
|
202
227
|
return;
|
|
203
228
|
for (const entry of authEntries) {
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
229
|
+
const expiry = getAddressCredentialExpiry(entry);
|
|
230
|
+
if (expiry === undefined) {
|
|
206
231
|
continue;
|
|
207
232
|
}
|
|
208
|
-
const expiry = creds.address().signatureExpirationLedger();
|
|
209
233
|
const margin = expiry - latestLedger;
|
|
210
234
|
if (margin < minBuffer) {
|
|
211
235
|
console.error(`[channels] Auth entry signatureExpirationLedger too close to current ledger (expires in ${margin} ledgers, minimum ${minBuffer} required)`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/plugin/submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAO,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAEL,OAAO,EAGP,SAAS,EACV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,CAAC,CAuBtB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,EAClB,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAmHlC;AASD,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/plugin/submit.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAO,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAEL,OAAO,EAGP,SAAS,EACV,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,wBAAwB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,cAAc,EAAE,OAAO,EACvB,YAAY,EAAE,OAAO,EACrB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,WAAW,CAAC,CAuBtB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,OAAO,EACpB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,UAAU,EACpB,OAAO,CAAC,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,OAAO,EAClB,MAAM,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,GAC3E,OAAO,CAAC,uBAAuB,CAAC,CAmHlC;AASD,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAmCvF;AAeD,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAepG;AAED,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOrD"}
|
package/dist/plugin/submit.js
CHANGED
|
@@ -20,7 +20,7 @@ const constants_1 = require("./constants");
|
|
|
20
20
|
* - Both signatures are added to the transaction
|
|
21
21
|
*/
|
|
22
22
|
async function signWithChannelAndFund(transaction, channelRelayer, _fundRelayer, channelAddress, _fundAddress, networkPassphrase) {
|
|
23
|
-
const txXdr = transaction.
|
|
23
|
+
const txXdr = transaction.toXdr();
|
|
24
24
|
console.debug(`[channels] Signing transaction with channel (${channelAddress})`);
|
|
25
25
|
// Get signatures from both accounts sequentially
|
|
26
26
|
// Channel signs first
|
|
@@ -172,14 +172,16 @@ function decodeTransactionResult(reason) {
|
|
|
172
172
|
const match = reason.match(/([A-Za-z0-9+/=]{20,})$/);
|
|
173
173
|
if (!match)
|
|
174
174
|
return null;
|
|
175
|
-
const result = stellar_sdk_1.xdr.TransactionResult.
|
|
176
|
-
const outerResultCode =
|
|
175
|
+
const result = stellar_sdk_1.xdr.TransactionResult.fromXdr(match[1], 'base64');
|
|
176
|
+
const outerResultCode = result.result.type;
|
|
177
177
|
let resultCode = outerResultCode;
|
|
178
178
|
// Unwrap fee bump inner failure to get the actual result code
|
|
179
179
|
if (outerResultCode === 'txFeeBumpInnerFailed') {
|
|
180
180
|
try {
|
|
181
|
-
const
|
|
182
|
-
|
|
181
|
+
const outer = result.result;
|
|
182
|
+
if (outer.type !== 'txFeeBumpInnerFailed')
|
|
183
|
+
throw new Error('unreachable');
|
|
184
|
+
const innerResultCode = outer.innerResultPair.result.result.type;
|
|
183
185
|
resultCode = `${outerResultCode}:${innerResultCode}`;
|
|
184
186
|
}
|
|
185
187
|
catch {
|
|
@@ -187,7 +189,7 @@ function decodeTransactionResult(reason) {
|
|
|
187
189
|
}
|
|
188
190
|
}
|
|
189
191
|
return {
|
|
190
|
-
feeCharged: Number(result.feeCharged
|
|
192
|
+
feeCharged: Number(result.feeCharged),
|
|
191
193
|
resultCode,
|
|
192
194
|
};
|
|
193
195
|
}
|
package/dist/plugin/tx.d.ts
CHANGED
|
@@ -5,5 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { Transaction } from '@stellar/stellar-sdk';
|
|
7
7
|
import type { ChannelAccountsConfig } from './config';
|
|
8
|
+
/**
|
|
9
|
+
* Validate a client-built transaction for the XDR submit-only path.
|
|
10
|
+
*
|
|
11
|
+
* Rejects fee-bump envelopes, Soroban transactions whose fee exceeds the
|
|
12
|
+
* declared resource fee plus the base inclusion fee, and a `timeBounds.maxTime`
|
|
13
|
+
* that is already in the past or further out than the configured maximum offset.
|
|
14
|
+
*/
|
|
8
15
|
export declare function validateExistingTransactionForSubmitOnly(tx: Transaction, config: Pick<ChannelAccountsConfig, 'maxTimeBoundOffsetSeconds'>): Transaction;
|
|
9
16
|
//# sourceMappingURL=tx.d.ts.map
|
package/dist/plugin/tx.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tx.d.ts","sourceRoot":"","sources":["../../src/plugin/tx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"tx.d.ts","sourceRoot":"","sources":["../../src/plugin/tx.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAGtD;;;;;;GAMG;AACH,wBAAgB,wCAAwC,CACtD,EAAE,EAAE,WAAW,EACf,MAAM,EAAE,IAAI,CAAC,qBAAqB,EAAE,2BAA2B,CAAC,GAC/D,WAAW,CAkDb"}
|
package/dist/plugin/tx.js
CHANGED
|
@@ -6,25 +6,30 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.validateExistingTransactionForSubmitOnly = validateExistingTransactionForSubmitOnly;
|
|
9
|
-
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
10
9
|
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
11
10
|
const constants_1 = require("./constants");
|
|
11
|
+
/**
|
|
12
|
+
* Validate a client-built transaction for the XDR submit-only path.
|
|
13
|
+
*
|
|
14
|
+
* Rejects fee-bump envelopes, Soroban transactions whose fee exceeds the
|
|
15
|
+
* declared resource fee plus the base inclusion fee, and a `timeBounds.maxTime`
|
|
16
|
+
* that is already in the past or further out than the configured maximum offset.
|
|
17
|
+
*/
|
|
12
18
|
function validateExistingTransactionForSubmitOnly(tx, config) {
|
|
13
19
|
const { maxTimeBoundOffsetSeconds } = config;
|
|
14
20
|
const now = Math.floor(Date.now() / 1000);
|
|
15
21
|
// Reject fee-bump envelopes
|
|
16
22
|
const envelope = tx.toEnvelope();
|
|
17
|
-
|
|
18
|
-
if (kind !== stellar_sdk_1.xdr.EnvelopeType.envelopeTypeTx()) {
|
|
23
|
+
if (envelope.type !== 'envelopeTypeTx') {
|
|
19
24
|
throw (0, relayer_sdk_1.pluginError)('Input must be a regular transaction envelope (fee-bump not allowed)', {
|
|
20
25
|
code: 'INVALID_ENVELOPE_TYPE',
|
|
21
26
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
22
27
|
});
|
|
23
28
|
}
|
|
24
29
|
// Soroban sanity checks
|
|
25
|
-
const
|
|
26
|
-
if (sorobanData) {
|
|
27
|
-
const resourceFee = sorobanData.resourceFee
|
|
30
|
+
const ext = envelope.v1.tx.ext;
|
|
31
|
+
if (ext.type === 'sorobanData') {
|
|
32
|
+
const resourceFee = ext.sorobanData.resourceFee;
|
|
28
33
|
if (BigInt(tx.fee) > resourceFee + 201n) {
|
|
29
34
|
throw (0, relayer_sdk_1.pluginError)('Transaction fee must be equal to the resource fee', {
|
|
30
35
|
code: 'FEE_MISMATCH',
|
|
@@ -5,5 +5,12 @@
|
|
|
5
5
|
* Supports either a signed XDR or func+auth.
|
|
6
6
|
*/
|
|
7
7
|
import { ChannelAccountsRequest } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Validate and normalize an incoming plugin request into one of the two
|
|
10
|
+
* supported shapes: a signed transaction `xdr` (submit-only) or a `func` +
|
|
11
|
+
* `auth` pair (channel flow). Base64 XDR fields are decoded here; malformed
|
|
12
|
+
* encodings and source-account auth credentials are rejected with
|
|
13
|
+
* `INVALID_PARAMS`.
|
|
14
|
+
*/
|
|
8
15
|
export declare function validateAndParseRequest(params: any): ChannelAccountsRequest;
|
|
9
16
|
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/plugin/validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAqBjD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/plugin/validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAqBjD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,GAAG,GAAG,sBAAsB,CAkJ3E"}
|
|
@@ -25,6 +25,13 @@ function parseFundRelayerId(params) {
|
|
|
25
25
|
}
|
|
26
26
|
return undefined;
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate and normalize an incoming plugin request into one of the two
|
|
30
|
+
* supported shapes: a signed transaction `xdr` (submit-only) or a `func` +
|
|
31
|
+
* `auth` pair (channel flow). Base64 XDR fields are decoded here; malformed
|
|
32
|
+
* encodings and source-account auth credentials are rejected with
|
|
33
|
+
* `INVALID_PARAMS`.
|
|
34
|
+
*/
|
|
28
35
|
function validateAndParseRequest(params) {
|
|
29
36
|
if (!params || typeof params !== 'object') {
|
|
30
37
|
throw (0, relayer_sdk_1.pluginError)('Invalid request: params must be an object', {
|
|
@@ -109,11 +116,11 @@ function validateAndParseRequest(params) {
|
|
|
109
116
|
let func;
|
|
110
117
|
let auth = [];
|
|
111
118
|
try {
|
|
112
|
-
func = stellar_sdk_1.xdr.HostFunction.
|
|
119
|
+
func = stellar_sdk_1.xdr.HostFunction.fromXdr(params.func, 'base64');
|
|
113
120
|
if (!Array.isArray(params.auth)) {
|
|
114
121
|
throw new Error('auth must be an array of base64 strings');
|
|
115
122
|
}
|
|
116
|
-
auth = params.auth.map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.
|
|
123
|
+
auth = params.auth.map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXdr(a, 'base64'));
|
|
117
124
|
}
|
|
118
125
|
catch (e) {
|
|
119
126
|
throw (0, relayer_sdk_1.pluginError)('Invalid `func` or `auth` encoding', {
|
|
@@ -124,8 +131,7 @@ function validateAndParseRequest(params) {
|
|
|
124
131
|
}
|
|
125
132
|
// Reject SourceAccount credentials: incompatible with relayer-managed channel source
|
|
126
133
|
for (const entry of auth) {
|
|
127
|
-
|
|
128
|
-
if (credType === stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount()) {
|
|
134
|
+
if (entry.credentials.type === 'sorobanCredentialsSourceAccount') {
|
|
129
135
|
throw (0, relayer_sdk_1.pluginError)('Detached address credentials required: source-account credentials are incompatible with relayer-managed channel accounts', {
|
|
130
136
|
code: 'INVALID_PARAMS',
|
|
131
137
|
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/relayer-plugin-channels",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "OpenZeppelin Relayer Plugin for Stellar Channel Accounts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@actions/exec": "^1.1.1",
|
|
23
23
|
"@openzeppelin/relayer-sdk": "^1.10.0",
|
|
24
|
-
"@stellar/stellar-sdk": "^
|
|
24
|
+
"@stellar/stellar-sdk": "^17.0.1",
|
|
25
25
|
"axios": "^1.13.5"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
package/dist/plugin/build.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* build.ts
|
|
3
|
-
*
|
|
4
|
-
* Transaction rebuild logic to use channel account as source.
|
|
5
|
-
*/
|
|
6
|
-
import { Transaction } from '@stellar/stellar-sdk';
|
|
7
|
-
export interface RebuildParams {
|
|
8
|
-
inputXdr: string;
|
|
9
|
-
channelAddress: string;
|
|
10
|
-
channelSequence: string;
|
|
11
|
-
fundAddress: string;
|
|
12
|
-
networkPassphrase: string;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Rebuild transaction with channel account as source
|
|
16
|
-
* - Set transaction source to channel account with current sequence
|
|
17
|
-
* - Preserve memo, timeBounds, etc.
|
|
18
|
-
* - Copy operations ensuring their source equals the fund address
|
|
19
|
-
*/
|
|
20
|
-
export declare function rebuildWithChannel(params: RebuildParams): Transaction;
|
|
21
|
-
//# sourceMappingURL=build.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/plugin/build.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAe,MAAM,sBAAsB,CAAC;AAIhE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAmGrE"}
|
package/dist/plugin/build.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* build.ts
|
|
4
|
-
*
|
|
5
|
-
* Transaction rebuild logic to use channel account as source.
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.rebuildWithChannel = rebuildWithChannel;
|
|
9
|
-
const stellar_sdk_1 = require("@stellar/stellar-sdk");
|
|
10
|
-
const relayer_sdk_1 = require("@openzeppelin/relayer-sdk");
|
|
11
|
-
const constants_1 = require("./constants");
|
|
12
|
-
/**
|
|
13
|
-
* Rebuild transaction with channel account as source
|
|
14
|
-
* - Set transaction source to channel account with current sequence
|
|
15
|
-
* - Preserve memo, timeBounds, etc.
|
|
16
|
-
* - Copy operations ensuring their source equals the fund address
|
|
17
|
-
*/
|
|
18
|
-
function rebuildWithChannel(params) {
|
|
19
|
-
const { inputXdr, channelAddress, channelSequence, fundAddress, networkPassphrase } = params;
|
|
20
|
-
// Parse input transaction
|
|
21
|
-
let inputTx;
|
|
22
|
-
try {
|
|
23
|
-
const envelope = stellar_sdk_1.xdr.TransactionEnvelope.fromXDR(inputXdr, 'base64');
|
|
24
|
-
// Ensure it's a regular transaction envelope (not fee bump)
|
|
25
|
-
if (envelope.switch() !== stellar_sdk_1.xdr.EnvelopeType.envelopeTypeTx()) {
|
|
26
|
-
throw (0, relayer_sdk_1.pluginError)('Input must be a regular transaction envelope (not fee bump)', {
|
|
27
|
-
code: 'INVALID_ENVELOPE_TYPE',
|
|
28
|
-
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
inputTx = new stellar_sdk_1.Transaction(envelope, networkPassphrase);
|
|
32
|
-
}
|
|
33
|
-
catch (error) {
|
|
34
|
-
if (error.code === 'INVALID_ENVELOPE_TYPE') {
|
|
35
|
-
throw error;
|
|
36
|
-
}
|
|
37
|
-
throw (0, relayer_sdk_1.pluginError)('Failed to parse input transaction XDR', {
|
|
38
|
-
code: 'INVALID_XDR',
|
|
39
|
-
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
40
|
-
details: { message: error instanceof Error ? error.message : String(error) },
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
// Validate timeBounds
|
|
44
|
-
if (inputTx.timeBounds) {
|
|
45
|
-
const now = Math.floor(Date.now() / 1000);
|
|
46
|
-
const maxTime = Number(inputTx.timeBounds.maxTime);
|
|
47
|
-
if (maxTime > 0) {
|
|
48
|
-
if (maxTime < now) {
|
|
49
|
-
throw (0, relayer_sdk_1.pluginError)('Transaction has expired: maxTime is in the past', {
|
|
50
|
-
code: 'TIMEBOUNDS_EXPIRED',
|
|
51
|
-
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
52
|
-
details: { maxTime, now },
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
const maxAllowedTime = now + constants_1.TIME.MAX_TIME_BOUND_OFFSET_SECONDS;
|
|
56
|
-
if (maxTime > maxAllowedTime) {
|
|
57
|
-
throw (0, relayer_sdk_1.pluginError)(`Transaction maxTime is too far in the future. Max allowed: ${constants_1.TIME.MAX_TIME_BOUND_OFFSET_SECONDS} seconds from now`, {
|
|
58
|
-
code: 'INVALID_TIME_BOUNDS',
|
|
59
|
-
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
60
|
-
details: { maxTime, maxAllowedTime },
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
// Validate operations: all operation sources must be fund address or missing
|
|
66
|
-
for (let i = 0; i < inputTx.operations.length; i++) {
|
|
67
|
-
const op = inputTx.operations[i];
|
|
68
|
-
if (op.source && op.source !== fundAddress) {
|
|
69
|
-
throw (0, relayer_sdk_1.pluginError)(`Operation ${i} has source ${op.source} but must be ${fundAddress} or omitted`, {
|
|
70
|
-
code: 'INVALID_OPERATION_SOURCE',
|
|
71
|
-
status: constants_1.HTTP_STATUS.BAD_REQUEST,
|
|
72
|
-
details: { operationIndex: i, operationSource: op.source, expectedSource: fundAddress },
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// Manipulate the transaction envelope XDR directly to change source and sequence
|
|
77
|
-
// This is the most reliable approach that preserves all transaction details
|
|
78
|
-
const envelope = inputTx.toEnvelope();
|
|
79
|
-
const txBody = envelope.v1().tx();
|
|
80
|
-
// Update source account to channel address
|
|
81
|
-
const channelAccountId = stellar_sdk_1.StrKey.decodeEd25519PublicKey(channelAddress);
|
|
82
|
-
const channelMuxed = stellar_sdk_1.xdr.MuxedAccount.keyTypeEd25519(channelAccountId);
|
|
83
|
-
txBody.sourceAccount(channelMuxed);
|
|
84
|
-
// Update sequence number
|
|
85
|
-
// Sequence numbers in Stellar are represented as Int64 in XDR
|
|
86
|
-
const seqNum = stellar_sdk_1.xdr.Int64.fromString(channelSequence);
|
|
87
|
-
txBody.seqNum(seqNum);
|
|
88
|
-
// Update operation sources to fund address if not set
|
|
89
|
-
const fundAccountId = stellar_sdk_1.StrKey.decodeEd25519PublicKey(fundAddress);
|
|
90
|
-
const fundMuxed = stellar_sdk_1.xdr.MuxedAccount.keyTypeEd25519(fundAccountId);
|
|
91
|
-
const operations = txBody.operations();
|
|
92
|
-
for (let i = 0; i < operations.length; i++) {
|
|
93
|
-
const op = operations[i];
|
|
94
|
-
// If operation doesn't have a source, set it to fund address
|
|
95
|
-
if (!op.sourceAccount()) {
|
|
96
|
-
op.sourceAccount(fundMuxed);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Create new transaction from modified envelope
|
|
100
|
-
return new stellar_sdk_1.Transaction(envelope, networkPassphrase);
|
|
101
|
-
}
|