@openzeppelin/relayer-plugin-channels 0.15.0 → 0.16.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.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,CAUhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAYzF;AASD,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,
|
|
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,CAUhF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAYzF;AASD,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
|
@@ -63,7 +63,14 @@ function calculateMaxFee(transaction, limitedContracts, fees) {
|
|
|
63
63
|
}
|
|
64
64
|
const contractId = getContractIdFromTransaction(transaction);
|
|
65
65
|
const inclusionFee = getInclusionFee(contractId, limitedContracts, fees);
|
|
66
|
-
const
|
|
67
|
-
|
|
66
|
+
const computedFee = resourceFee > 0n ? resourceFee + BigInt(inclusionFee) : BigInt(constants_1.FEE.NON_SOROBAN_FEE + inclusionFee);
|
|
67
|
+
const innerTxFee = BigInt(transaction.fee);
|
|
68
|
+
// Safety floor: fee bump max_fee must always cover the actual inner transaction fee.
|
|
69
|
+
// This protects against upstream fee-field mismatches that can produce a larger inner fee.
|
|
70
|
+
const fee = computedFee >= innerTxFee ? computedFee : innerTxFee + BigInt(inclusionFee);
|
|
71
|
+
if (fee !== computedFee) {
|
|
72
|
+
console.warn(`[channels] Fee mismatch detected: computed=${computedFee}, innerTxFee=${innerTxFee}. Using max_fee=${fee}`);
|
|
73
|
+
}
|
|
74
|
+
console.debug(`[channels] Calculated max_fee: ${Number(fee)} stroops (resourceFee: ${resourceFee}, inclusionFee: ${inclusionFee}, innerTxFee: ${innerTxFee})`);
|
|
68
75
|
return Number(fee);
|
|
69
76
|
}
|
|
@@ -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,GACxB,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,GAC7F,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,GACxB,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,GAC7F,WAAW,CA+Fb;AA4CD,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAe1D"}
|
|
@@ -105,32 +105,81 @@ async function simulateTransaction(func, auth, sourceAddress, relayer, networkPa
|
|
|
105
105
|
* obtained simulation result. No additional network calls are made.
|
|
106
106
|
*/
|
|
107
107
|
function buildWithChannel(func, auth, channel, networkPassphrase, simResult, minSignatureExpirationLedgerBuffer = constants_1.SIMULATION.MIN_SIGNATURE_EXPIRATION_LEDGER_BUFFER) {
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
if (!simResult.transactionData) {
|
|
109
|
+
throw (0, relayer_sdk_1.pluginError)('Simulation response missing transactionData', {
|
|
110
|
+
code: 'SIMULATION_INVALID_RESPONSE',
|
|
111
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// Parse sorobanData from the simulation result
|
|
115
|
+
let sorobanData;
|
|
116
|
+
try {
|
|
117
|
+
sorobanData = stellar_sdk_1.xdr.SorobanTransactionData.fromXDR(simResult.transactionData, 'base64');
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation transactionData', {
|
|
121
|
+
code: 'SIMULATION_INVALID_RESPONSE',
|
|
122
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
123
|
+
details: { message: err instanceof Error ? err.message : String(err) },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// Resolve auth: use caller-provided auth if present, otherwise fall back to simulation auth
|
|
127
|
+
let resolvedAuth;
|
|
128
|
+
if (auth && auth.length > 0) {
|
|
129
|
+
resolvedAuth = auth;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
try {
|
|
133
|
+
resolvedAuth = (simResult.results?.[0]?.auth ?? []).map((a) => stellar_sdk_1.xdr.SorobanAuthorizationEntry.fromXDR(a, 'base64'));
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
throw (0, relayer_sdk_1.pluginError)('Failed to parse simulation auth entries', {
|
|
137
|
+
code: 'SIMULATION_INVALID_RESPONSE',
|
|
138
|
+
status: constants_1.HTTP_STATUS.BAD_GATEWAY,
|
|
139
|
+
details: { message: err instanceof Error ? err.message : String(err) },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Validate resolved auth expiry before doing any assembly work.
|
|
110
144
|
if (simResult.latestLedger) {
|
|
111
|
-
validateAuthExpiry(
|
|
145
|
+
validateAuthExpiry(resolvedAuth, simResult.latestLedger, minSignatureExpirationLedgerBuffer);
|
|
112
146
|
}
|
|
113
147
|
const now = Math.floor(Date.now() / 1000);
|
|
114
|
-
console.debug(`[channels] Building tx: channel=${channel.address}, seq=${channel.sequence}, auth_count=${
|
|
115
|
-
// Build
|
|
148
|
+
console.debug(`[channels] Building tx: channel=${channel.address}, seq=${channel.sequence}, auth_count=${resolvedAuth.length}`);
|
|
149
|
+
// Build the transaction directly with sorobanData instead of using rpc.assembleTransaction().
|
|
150
|
+
//
|
|
151
|
+
// Why: stellar-base >=14.1.0 changed TransactionBuilder.build() to automatically add
|
|
152
|
+
// sorobanData.resourceFee() to the transaction fee (stellar/js-stellar-base#761).
|
|
153
|
+
// However, rpc.assembleTransaction() was not updated for this change — it still computes
|
|
154
|
+
// fee = classicFee + minResourceFee before calling cloneFrom/build, so build() then adds
|
|
155
|
+
// resourceFee a second time:
|
|
156
|
+
//
|
|
157
|
+
// assembleTransaction path (broken with >=14.1.0):
|
|
158
|
+
// baseFee = classicFee(100) + minResourceFee(25102) = 25202
|
|
159
|
+
// build() adds resourceFee(25102) → final fee = 50304 (double-counted!)
|
|
160
|
+
//
|
|
161
|
+
// Direct build path (correct):
|
|
162
|
+
// baseFee = classicFee(100)
|
|
163
|
+
// build() adds resourceFee(25102) → final fee = 25202 (correct)
|
|
164
|
+
//
|
|
165
|
+
// By passing sorobanData directly to TransactionBuilder, build() adds the resourceFee
|
|
166
|
+
// exactly once. This approach also removes the assembleTransaction network-format
|
|
167
|
+
// dependency and gives us explicit control over auth resolution.
|
|
116
168
|
const transaction = new stellar_sdk_1.TransactionBuilder(new stellar_sdk_1.Account(channel.address, channel.sequence), {
|
|
117
169
|
fee: constants_1.SIMULATION.DEFAULT_FEE,
|
|
118
170
|
networkPassphrase,
|
|
119
171
|
timebounds: { minTime: constants_1.SIMULATION.MIN_TIME_BOUND, maxTime: now + constants_1.SIMULATION.MAX_TIME_BOUND_OFFSET_SECONDS },
|
|
172
|
+
sorobanData,
|
|
120
173
|
})
|
|
121
174
|
.addOperation(stellar_sdk_1.Operation.invokeHostFunction({
|
|
122
175
|
func,
|
|
123
|
-
auth,
|
|
124
|
-
// No explicit source: default to transaction source (channel account)
|
|
176
|
+
auth: resolvedAuth,
|
|
125
177
|
}))
|
|
126
178
|
.build();
|
|
127
179
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const resourceFee = prepared.toEnvelope().v1().tx().ext().sorobanData()?.resourceFee();
|
|
132
|
-
console.debug(`[channels] Post-assembly: prepared.fee=${prepared.fee}, resourceFee=${resourceFee}`);
|
|
133
|
-
return prepared;
|
|
180
|
+
const resourceFee = transaction.toEnvelope().v1().tx().ext().sorobanData()?.resourceFee();
|
|
181
|
+
console.debug(`[channels] Assembly complete: fee=${transaction.fee}, resourceFee=${resourceFee}`);
|
|
182
|
+
return transaction;
|
|
134
183
|
}
|
|
135
184
|
catch (err) {
|
|
136
185
|
console.error(`[channels] Assembly error: ${err instanceof Error ? err.message : String(err)}`);
|