@openzeppelin/relayer-plugin-channels 0.14.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":"handler.d.ts","sourceRoot":"","sources":["../../src/plugin/handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAe,MAAM,2BAA2B,CAAC;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AA2BxD;;;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,CAkB1E;
|
|
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;AASvE,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAC;AA2BxD;;;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,CAkB1E;AAiSD;;GAEG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,CAElE"}
|
package/dist/plugin/handler.js
CHANGED
|
@@ -112,8 +112,10 @@ async function handleFuncAuthSubmit(func, auth, ctx, skipWait) {
|
|
|
112
112
|
const sequence = await (0, sequence_1.getSequence)(ctx.kv, ctx.network, channelRelayer, channelInfo.address, ctx.config.sequenceNumberCacheMaxAgeMs);
|
|
113
113
|
// Assemble the transaction using the cached simulation result — no second RPC call
|
|
114
114
|
const built = (0, simulation_1.buildWithChannel)(func, auth, { address: channelInfo.address, sequence }, ctx.networkPassphrase, simulation.rawSimResult, ctx.config.minSignatureExpirationLedgerBuffer);
|
|
115
|
+
console.debug(`[channels] After assembly: built.fee=${built.fee}, minResourceFee=${simulation.rawSimResult.minResourceFee}`);
|
|
115
116
|
const signedTx = await (0, submit_1.signWithChannelAndFund)(built, channelRelayer, ctx.fundRelayer, channelInfo.address, ctx.fundAddress, ctx.networkPassphrase);
|
|
116
117
|
const maxFee = (0, fee_1.calculateMaxFee)(signedTx, ctx.acquireOptions.limitedContracts, ctx.fees);
|
|
118
|
+
console.debug(`[channels] After signing: signedTx.fee=${signedTx.fee}, maxFee=${maxFee}`);
|
|
117
119
|
const contractId = (0, fee_1.getContractIdFromFunc)(func);
|
|
118
120
|
await ctx.tracker?.checkBudget(maxFee);
|
|
119
121
|
const submitContext = {
|
|
@@ -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,31 +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
|
-
console.debug(`[channels] Assembly complete: resourceFee=${resourceFee}`);
|
|
132
|
-
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;
|
|
133
183
|
}
|
|
134
184
|
catch (err) {
|
|
135
185
|
console.error(`[channels] Assembly error: ${err instanceof Error ? err.message : String(err)}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openzeppelin/relayer-plugin-channels",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "OpenZeppelin Relayer Plugin for Stellar Channel Accounts",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@actions/exec": "^1.1.1",
|
|
23
|
-
"@openzeppelin/relayer-sdk": "^1.
|
|
24
|
-
"@stellar/stellar-sdk": "^14.
|
|
23
|
+
"@openzeppelin/relayer-sdk": "^1.10.0",
|
|
24
|
+
"@stellar/stellar-sdk": "^14.6.0",
|
|
25
25
|
"axios": "^1.13.5"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|