mppx 0.4.7 → 0.4.9
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/CHANGELOG.md +15 -3
- package/README.md +13 -13
- package/dist/BodyDigest.d.ts.map +1 -1
- package/dist/BodyDigest.js.map +1 -1
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js.map +1 -1
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Credential.js.map +1 -1
- package/dist/Errors.js +64 -67
- package/dist/Errors.js.map +1 -1
- package/dist/PaymentRequest.d.ts.map +1 -1
- package/dist/PaymentRequest.js.map +1 -1
- package/dist/Receipt.d.ts.map +1 -1
- package/dist/Receipt.js.map +1 -1
- package/dist/Store.d.ts +14 -4
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +17 -0
- package/dist/Store.js.map +1 -1
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/account.js +40 -5
- package/dist/cli/account.js.map +1 -1
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +24 -8
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/internal.d.ts.map +1 -1
- package/dist/cli/internal.js.map +1 -1
- package/dist/cli/plugins/stripe.d.ts.map +1 -1
- package/dist/cli/plugins/stripe.js.map +1 -1
- package/dist/cli/plugins/tempo.d.ts.map +1 -1
- package/dist/cli/plugins/tempo.js +11 -23
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts +2 -0
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +1 -1
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
- package/dist/mcp-sdk/client/McpClient.js +1 -1
- package/dist/mcp-sdk/client/McpClient.js.map +1 -1
- package/dist/mcp-sdk/server/Transport.d.ts.map +1 -1
- package/dist/mcp-sdk/server/Transport.js.map +1 -1
- package/dist/middlewares/elysia.d.ts.map +1 -1
- package/dist/middlewares/elysia.js +5 -1
- package/dist/middlewares/elysia.js.map +1 -1
- package/dist/middlewares/express.d.ts.map +1 -1
- package/dist/middlewares/express.js +5 -2
- package/dist/middlewares/express.js.map +1 -1
- package/dist/middlewares/hono.d.ts.map +1 -1
- package/dist/middlewares/hono.js.map +1 -1
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +3 -1
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/Service.js +1 -1
- package/dist/proxy/Service.js.map +1 -1
- package/dist/proxy/internal/Route.d.ts +2 -2
- package/dist/proxy/internal/Route.d.ts.map +1 -1
- package/dist/proxy/internal/Route.js +4 -2
- package/dist/proxy/internal/Route.js.map +1 -1
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +47 -11
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/Request.d.ts.map +1 -1
- package/dist/server/Request.js.map +1 -1
- package/dist/stripe/Methods.d.ts.map +1 -1
- package/dist/stripe/Methods.js.map +1 -1
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Methods.js.map +1 -1
- package/dist/tempo/client/ChannelOps.d.ts.map +1 -1
- package/dist/tempo/client/ChannelOps.js.map +1 -1
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Session.d.ts.map +1 -1
- package/dist/tempo/client/Session.js.map +1 -1
- package/dist/tempo/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/client/SessionManager.js +1 -1
- package/dist/tempo/client/SessionManager.js.map +1 -1
- package/dist/tempo/internal/address.d.ts +3 -0
- package/dist/tempo/internal/address.d.ts.map +1 -0
- package/dist/tempo/internal/address.js +4 -0
- package/dist/tempo/internal/address.js.map +1 -0
- package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
- package/dist/tempo/internal/auto-swap.js +4 -4
- package/dist/tempo/internal/auto-swap.js.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +4 -1
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js +12 -4
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/server/Charge.d.ts +11 -0
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +110 -51
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Session.d.ts +1 -1
- package/dist/tempo/server/Session.d.ts.map +1 -1
- package/dist/tempo/server/Session.js +31 -23
- package/dist/tempo/server/Session.js.map +1 -1
- package/dist/tempo/server/internal/transport.d.ts +1 -1
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +41 -1
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/Chain.d.ts.map +1 -1
- package/dist/tempo/session/Chain.js +51 -10
- package/dist/tempo/session/Chain.js.map +1 -1
- package/dist/tempo/session/ChannelStore.d.ts +2 -0
- package/dist/tempo/session/ChannelStore.d.ts.map +1 -1
- package/dist/tempo/session/ChannelStore.js +4 -2
- package/dist/tempo/session/ChannelStore.js.map +1 -1
- package/dist/tempo/session/Receipt.d.ts.map +1 -1
- package/dist/tempo/session/Receipt.js.map +1 -1
- package/dist/tempo/session/Sse.d.ts.map +1 -1
- package/dist/tempo/session/Sse.js.map +1 -1
- package/dist/tempo/session/Voucher.d.ts.map +1 -1
- package/dist/tempo/session/Voucher.js +3 -2
- package/dist/tempo/session/Voucher.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js.map +1 -1
- package/package.json +2 -2
- package/src/BodyDigest.ts +1 -0
- package/src/Challenge.test-d.ts +1 -0
- package/src/Challenge.ts +1 -0
- package/src/Credential.ts +1 -0
- package/src/Errors.test.ts +27 -39
- package/src/Expires.test.ts +1 -0
- package/src/PaymentRequest.ts +1 -0
- package/src/Receipt.ts +1 -0
- package/src/Store.test-d.ts +59 -0
- package/src/Store.test.ts +56 -6
- package/src/Store.ts +31 -4
- package/src/cli/account.ts +65 -30
- package/src/cli/cli.test.ts +127 -1
- package/src/cli/cli.ts +23 -8
- package/src/cli/config.test.ts +1 -0
- package/src/cli/internal.ts +1 -0
- package/src/cli/plugins/stripe.ts +1 -0
- package/src/cli/plugins/tempo.ts +21 -24
- package/src/cli/utils.ts +1 -0
- package/src/client/Mppx.test-d.ts +1 -0
- package/src/client/internal/Fetch.browser.test.ts +1 -0
- package/src/client/internal/Fetch.test-d.ts +1 -0
- package/src/client/internal/Fetch.test.ts +1 -0
- package/src/client/internal/Fetch.ts +1 -1
- package/src/internal/constantTimeEqual.test.ts +1 -0
- package/src/internal/types.ts +1 -3
- package/src/mcp-sdk/client/McpClient.test-d.ts +1 -0
- package/src/mcp-sdk/client/McpClient.test.ts +1 -0
- package/src/mcp-sdk/client/McpClient.ts +2 -0
- package/src/mcp-sdk/server/Transport.test.ts +1 -0
- package/src/mcp-sdk/server/Transport.ts +1 -0
- package/src/middlewares/elysia.test.ts +90 -0
- package/src/middlewares/elysia.ts +5 -1
- package/src/middlewares/express.test.ts +62 -2
- package/src/middlewares/express.ts +6 -2
- package/src/middlewares/hono.ts +1 -0
- package/src/middlewares/internal/mppx.test.ts +1 -0
- package/src/middlewares/nextjs.test.ts +1 -0
- package/src/proxy/Proxy.test.ts +57 -0
- package/src/proxy/Proxy.ts +8 -1
- package/src/proxy/Service.test.ts +1 -0
- package/src/proxy/Service.ts +8 -2
- package/src/proxy/internal/Headers.test.ts +1 -0
- package/src/proxy/internal/Route.test.ts +57 -0
- package/src/proxy/internal/Route.ts +3 -1
- package/src/proxy/services/openai.test.ts +1 -0
- package/src/server/Mppx.test.ts +438 -0
- package/src/server/Mppx.ts +51 -13
- package/src/server/Request.test.ts +1 -0
- package/src/server/Request.ts +1 -0
- package/src/server/Response.test.ts +1 -0
- package/src/server/Transport.test.ts +1 -0
- package/src/stripe/Methods.ts +1 -0
- package/src/stripe/client/Charge.test.ts +1 -0
- package/src/stripe/server/Charge.test.ts +1 -0
- package/src/tempo/Attribution.test.ts +1 -0
- package/src/tempo/Methods.ts +1 -0
- package/src/tempo/client/ChannelOps.test.ts +1 -0
- package/src/tempo/client/ChannelOps.ts +1 -0
- package/src/tempo/client/Charge.ts +1 -0
- package/src/tempo/client/Session.test.ts +1 -0
- package/src/tempo/client/Session.ts +1 -0
- package/src/tempo/client/SessionManager.test.ts +28 -0
- package/src/tempo/client/SessionManager.ts +2 -1
- package/src/tempo/internal/address.ts +6 -0
- package/src/tempo/internal/auto-swap.test.ts +1 -0
- package/src/tempo/internal/auto-swap.ts +4 -3
- package/src/tempo/internal/defaults.test.ts +1 -0
- package/src/tempo/internal/fee-payer.test.ts +1 -0
- package/src/tempo/internal/fee-payer.ts +19 -4
- package/src/tempo/server/Charge.test.ts +1081 -31
- package/src/tempo/server/Charge.ts +159 -63
- package/src/tempo/server/Session.test.ts +896 -107
- package/src/tempo/server/Session.ts +41 -23
- package/src/tempo/server/Sse.test.ts +2 -0
- package/src/tempo/server/internal/transport.test.ts +30 -0
- package/src/tempo/server/internal/transport.ts +41 -2
- package/src/tempo/session/Chain.test.ts +145 -0
- package/src/tempo/session/Chain.ts +59 -10
- package/src/tempo/session/Channel.test.ts +1 -0
- package/src/tempo/session/ChannelStore.test.ts +11 -0
- package/src/tempo/session/ChannelStore.ts +7 -3
- package/src/tempo/session/Receipt.test.ts +1 -0
- package/src/tempo/session/Receipt.ts +1 -0
- package/src/tempo/session/Sse.test.ts +2 -0
- package/src/tempo/session/Sse.ts +1 -0
- package/src/tempo/session/Voucher.test.ts +1 -0
- package/src/tempo/session/Voucher.ts +4 -2
- package/src/viem/Account.test.ts +1 -0
- package/src/viem/Client.test.ts +1 -0
- package/src/viem/Client.ts +1 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TempoAddress as TempoAddress_types } from 'ox/tempo'
|
|
2
|
+
import { decodeFunctionData, keccak256, parseEventLogs, type TransactionReceipt } from 'viem'
|
|
2
3
|
import {
|
|
3
4
|
getTransactionReceipt,
|
|
4
5
|
sendRawTransaction,
|
|
@@ -8,11 +9,14 @@ import {
|
|
|
8
9
|
} from 'viem/actions'
|
|
9
10
|
import { tempo as tempo_chain } from 'viem/chains'
|
|
10
11
|
import { Abis, Transaction } from 'viem/tempo'
|
|
12
|
+
|
|
11
13
|
import { PaymentExpiredError } from '../../Errors.js'
|
|
12
14
|
import type { LooseOmit } from '../../internal/types.js'
|
|
13
15
|
import * as Method from '../../Method.js'
|
|
16
|
+
import * as Store from '../../Store.js'
|
|
14
17
|
import * as Client from '../../viem/Client.js'
|
|
15
18
|
import * as Account from '../internal/account.js'
|
|
19
|
+
import * as TempoAddress from '../internal/address.js'
|
|
16
20
|
import * as defaults from '../internal/defaults.js'
|
|
17
21
|
import * as FeePayer from '../internal/fee-payer.js'
|
|
18
22
|
import * as Selectors from '../internal/selectors.js'
|
|
@@ -41,6 +45,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
41
45
|
memo,
|
|
42
46
|
waitForConfirmation = true,
|
|
43
47
|
} = parameters
|
|
48
|
+
const store = (parameters.store ?? Store.memory()) as Store.Store<charge.StoreItemMap>
|
|
44
49
|
|
|
45
50
|
const { recipient, feePayer, feePayerUrl } = Account.resolve(parameters)
|
|
46
51
|
|
|
@@ -119,74 +124,45 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
119
124
|
switch (payload.type) {
|
|
120
125
|
case 'hash': {
|
|
121
126
|
const hash = payload.hash as `0x${string}`
|
|
127
|
+
await assertHashUnused(store, hash)
|
|
128
|
+
|
|
122
129
|
const receipt = await getTransactionReceipt(client, {
|
|
123
130
|
hash,
|
|
124
131
|
})
|
|
125
132
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const match = memoLogs.find(
|
|
134
|
-
(log) =>
|
|
135
|
-
isAddressEqual(log.address, currency) &&
|
|
136
|
-
isAddressEqual(log.args.to, recipient) &&
|
|
137
|
-
log.args.amount.toString() === amount &&
|
|
138
|
-
log.args.memo.toLowerCase() === memo.toLowerCase(),
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
if (!match)
|
|
142
|
-
throw new MismatchError(
|
|
143
|
-
'Payment verification failed: no matching transfer with memo found.',
|
|
144
|
-
{
|
|
145
|
-
amount,
|
|
146
|
-
currency,
|
|
147
|
-
memo,
|
|
148
|
-
recipient,
|
|
149
|
-
},
|
|
150
|
-
)
|
|
151
|
-
} else {
|
|
152
|
-
const transferLogs = parseEventLogs({
|
|
153
|
-
abi: Abis.tip20,
|
|
154
|
-
eventName: 'Transfer',
|
|
155
|
-
logs: receipt.logs,
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
const memoLogs = parseEventLogs({
|
|
159
|
-
abi: Abis.tip20,
|
|
160
|
-
eventName: 'TransferWithMemo',
|
|
161
|
-
logs: receipt.logs,
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
const match = [...transferLogs, ...memoLogs].find(
|
|
165
|
-
(log) =>
|
|
166
|
-
isAddressEqual(log.address, currency) &&
|
|
167
|
-
isAddressEqual(log.args.to, recipient) &&
|
|
168
|
-
log.args.amount.toString() === amount,
|
|
169
|
-
)
|
|
133
|
+
assertTransferLog(receipt, {
|
|
134
|
+
amount,
|
|
135
|
+
currency,
|
|
136
|
+
from: receipt.from,
|
|
137
|
+
memo,
|
|
138
|
+
recipient,
|
|
139
|
+
})
|
|
170
140
|
|
|
171
|
-
|
|
172
|
-
throw new MismatchError('Payment verification failed: no matching transfer found.', {
|
|
173
|
-
amount,
|
|
174
|
-
currency,
|
|
175
|
-
recipient,
|
|
176
|
-
})
|
|
177
|
-
}
|
|
141
|
+
await markHashUsed(store, hash)
|
|
178
142
|
|
|
179
143
|
return toReceipt(receipt)
|
|
180
144
|
}
|
|
181
145
|
|
|
182
146
|
case 'transaction': {
|
|
183
147
|
const serializedTransaction = payload.signature as Transaction.TransactionSerializedTempo
|
|
184
|
-
const transaction = Transaction.deserialize(serializedTransaction)
|
|
185
148
|
|
|
186
|
-
|
|
149
|
+
// Pre-broadcast dedup: catch exact byte-for-byte replays early.
|
|
150
|
+
const hash = keccak256(serializedTransaction)
|
|
151
|
+
await assertHashUnused(store, hash)
|
|
152
|
+
await markHashUsed(store, hash)
|
|
153
|
+
|
|
154
|
+
if (!FeePayer.isTempoTransaction(serializedTransaction))
|
|
155
|
+
throw new MismatchError('Only Tempo (0x76/0x78) transactions are supported.', {})
|
|
187
156
|
|
|
188
|
-
const
|
|
189
|
-
|
|
157
|
+
const transaction = Transaction.deserialize(serializedTransaction)
|
|
158
|
+
if (!transaction.signature || !transaction.from)
|
|
159
|
+
throw new MismatchError(
|
|
160
|
+
'Transaction must be signed by the sender before fee payer co-signing.',
|
|
161
|
+
{},
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
const call = transaction.calls.find((call) => {
|
|
165
|
+
if (!call.to || !TempoAddress.isEqual(call.to, currency)) return false
|
|
190
166
|
if (!call.data) return false
|
|
191
167
|
|
|
192
168
|
const selector = call.data.slice(0, 10)
|
|
@@ -197,7 +173,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
197
173
|
const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data })
|
|
198
174
|
const [to, amount_, memo_] = args as [`0x${string}`, bigint, `0x${string}`]
|
|
199
175
|
return (
|
|
200
|
-
|
|
176
|
+
TempoAddress.isEqual(to, recipient) &&
|
|
201
177
|
amount_.toString() === amount &&
|
|
202
178
|
memo_.toLowerCase() === memo.toLowerCase()
|
|
203
179
|
)
|
|
@@ -210,7 +186,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
210
186
|
try {
|
|
211
187
|
const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data })
|
|
212
188
|
const [to, amount_] = args as [`0x${string}`, bigint]
|
|
213
|
-
return
|
|
189
|
+
return TempoAddress.isEqual(to, recipient) && amount_.toString() === amount
|
|
214
190
|
} catch {
|
|
215
191
|
return false
|
|
216
192
|
}
|
|
@@ -220,7 +196,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
220
196
|
try {
|
|
221
197
|
const { args } = decodeFunctionData({ abi: Abis.tip20, data: call.data })
|
|
222
198
|
const [to, amount_] = args as [`0x${string}`, bigint, `0x${string}`]
|
|
223
|
-
return
|
|
199
|
+
return TempoAddress.isEqual(to, recipient) && amount_.toString() === amount
|
|
224
200
|
} catch {
|
|
225
201
|
return false
|
|
226
202
|
}
|
|
@@ -237,7 +213,7 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
237
213
|
})
|
|
238
214
|
|
|
239
215
|
if ((feePayer || feePayerUrl) && methodDetails?.feePayer !== false)
|
|
240
|
-
FeePayer.validateCalls(calls, { amount, currency, recipient })
|
|
216
|
+
FeePayer.validateCalls(transaction.calls, { amount, currency, recipient })
|
|
241
217
|
|
|
242
218
|
const resolvedFeeToken =
|
|
243
219
|
transaction.feeToken ?? defaults.currency[chainId as keyof typeof defaults.currency]
|
|
@@ -258,6 +234,21 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
258
234
|
const receipt = await sendRawTransactionSync(client, {
|
|
259
235
|
serializedTransaction: serializedTransaction_final,
|
|
260
236
|
})
|
|
237
|
+
assertTransferLog(receipt, {
|
|
238
|
+
amount,
|
|
239
|
+
currency,
|
|
240
|
+
from: transaction.from,
|
|
241
|
+
memo,
|
|
242
|
+
recipient,
|
|
243
|
+
})
|
|
244
|
+
// Post-broadcast dedup: catch malleable input variants
|
|
245
|
+
// (different serialized bytes, same underlying tx) that
|
|
246
|
+
// bypass the pre-broadcast check. Skip if the broadcast
|
|
247
|
+
// hash matches the input hash (already stored above).
|
|
248
|
+
if (receipt.transactionHash.toLowerCase() !== hash.toLowerCase()) {
|
|
249
|
+
await assertHashUnused(store, receipt.transactionHash)
|
|
250
|
+
await markHashUsed(store, receipt.transactionHash)
|
|
251
|
+
}
|
|
261
252
|
return toReceipt(receipt)
|
|
262
253
|
} else {
|
|
263
254
|
// Optimistic path: simulate to catch obvious reverts, then broadcast
|
|
@@ -267,16 +258,21 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
267
258
|
...transaction,
|
|
268
259
|
account: transaction.from,
|
|
269
260
|
feeToken: resolvedFeeToken,
|
|
270
|
-
calls,
|
|
261
|
+
calls: transaction.calls,
|
|
271
262
|
} as never)
|
|
272
|
-
const
|
|
263
|
+
const reference = await sendRawTransaction(client, {
|
|
273
264
|
serializedTransaction: serializedTransaction_final,
|
|
274
265
|
})
|
|
266
|
+
// Post-broadcast dedup: same
|
|
267
|
+
if (reference.toLowerCase() !== hash.toLowerCase()) {
|
|
268
|
+
await assertHashUnused(store, reference)
|
|
269
|
+
await markHashUsed(store, reference)
|
|
270
|
+
}
|
|
275
271
|
return {
|
|
276
272
|
method: 'tempo',
|
|
277
273
|
status: 'success',
|
|
278
274
|
timestamp: new Date().toISOString(),
|
|
279
|
-
reference
|
|
275
|
+
reference,
|
|
280
276
|
} as const
|
|
281
277
|
}
|
|
282
278
|
}
|
|
@@ -289,11 +285,20 @@ export function charge<const parameters extends charge.Parameters>(
|
|
|
289
285
|
}
|
|
290
286
|
|
|
291
287
|
export declare namespace charge {
|
|
288
|
+
type StoreItemMap = { [key: `mppx:charge:${string}`]: number }
|
|
289
|
+
|
|
292
290
|
type Defaults = LooseOmit<Method.RequestDefaults<typeof Methods.charge>, 'feePayer' | 'recipient'>
|
|
293
291
|
|
|
294
292
|
type Parameters = {
|
|
295
293
|
/** Testnet mode. */
|
|
296
294
|
testnet?: boolean | undefined
|
|
295
|
+
/**
|
|
296
|
+
* Store for transaction hash replay protection.
|
|
297
|
+
*
|
|
298
|
+
* Use a shared store in multi-instance deployments so consumed hashes are
|
|
299
|
+
* visible across all server instances.
|
|
300
|
+
*/
|
|
301
|
+
store?: Store.Store | undefined
|
|
297
302
|
/**
|
|
298
303
|
* Whether to wait for the charge transaction to confirm on-chain before
|
|
299
304
|
* responding. @default true
|
|
@@ -318,6 +323,97 @@ export declare namespace charge {
|
|
|
318
323
|
}
|
|
319
324
|
}
|
|
320
325
|
|
|
326
|
+
/** @internal */
|
|
327
|
+
function assertTransferLog(
|
|
328
|
+
receipt: TransactionReceipt,
|
|
329
|
+
parameters: {
|
|
330
|
+
amount: string
|
|
331
|
+
currency: TempoAddress_types.Address
|
|
332
|
+
from: TempoAddress_types.Address
|
|
333
|
+
memo: `0x${string}` | undefined
|
|
334
|
+
recipient: TempoAddress_types.Address
|
|
335
|
+
},
|
|
336
|
+
): void {
|
|
337
|
+
const { amount, currency, from, memo, recipient } = parameters
|
|
338
|
+
|
|
339
|
+
if (memo) {
|
|
340
|
+
const memoLogs = parseEventLogs({
|
|
341
|
+
abi: Abis.tip20,
|
|
342
|
+
eventName: 'TransferWithMemo',
|
|
343
|
+
logs: receipt.logs,
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
const match = memoLogs.find(
|
|
347
|
+
(log) =>
|
|
348
|
+
TempoAddress.isEqual(log.address, currency) &&
|
|
349
|
+
TempoAddress.isEqual(log.args.from, from) &&
|
|
350
|
+
TempoAddress.isEqual(log.args.to, recipient) &&
|
|
351
|
+
log.args.amount.toString() === amount &&
|
|
352
|
+
log.args.memo.toLowerCase() === memo.toLowerCase(),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
if (!match)
|
|
356
|
+
throw new MismatchError(
|
|
357
|
+
'Payment verification failed: no matching transfer with memo found.',
|
|
358
|
+
{
|
|
359
|
+
amount,
|
|
360
|
+
currency,
|
|
361
|
+
memo,
|
|
362
|
+
recipient,
|
|
363
|
+
},
|
|
364
|
+
)
|
|
365
|
+
} else {
|
|
366
|
+
const transferLogs = parseEventLogs({
|
|
367
|
+
abi: Abis.tip20,
|
|
368
|
+
eventName: 'Transfer',
|
|
369
|
+
logs: receipt.logs,
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
const memoLogs = parseEventLogs({
|
|
373
|
+
abi: Abis.tip20,
|
|
374
|
+
eventName: 'TransferWithMemo',
|
|
375
|
+
logs: receipt.logs,
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
const match = [...transferLogs, ...memoLogs].find(
|
|
379
|
+
(log) =>
|
|
380
|
+
TempoAddress.isEqual(log.address, currency) &&
|
|
381
|
+
TempoAddress.isEqual(log.args.from, from) &&
|
|
382
|
+
TempoAddress.isEqual(log.args.to, recipient) &&
|
|
383
|
+
log.args.amount.toString() === amount,
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
if (!match)
|
|
387
|
+
throw new MismatchError('Payment verification failed: no matching transfer found.', {
|
|
388
|
+
amount,
|
|
389
|
+
currency,
|
|
390
|
+
recipient,
|
|
391
|
+
})
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/** @internal */
|
|
396
|
+
function getHashStoreKey(hash: `0x${string}`): `mppx:charge:${string}` {
|
|
397
|
+
return `mppx:charge:${hash.toLowerCase()}`
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** @internal */
|
|
401
|
+
async function assertHashUnused(
|
|
402
|
+
store: Store.Store<charge.StoreItemMap>,
|
|
403
|
+
hash: `0x${string}`,
|
|
404
|
+
): Promise<void> {
|
|
405
|
+
const seen = await store.get(getHashStoreKey(hash))
|
|
406
|
+
if (seen !== null) throw new Error('Transaction hash has already been used.')
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/** @internal */
|
|
410
|
+
async function markHashUsed(
|
|
411
|
+
store: Store.Store<charge.StoreItemMap>,
|
|
412
|
+
hash: `0x${string}`,
|
|
413
|
+
): Promise<void> {
|
|
414
|
+
await store.put(getHashStoreKey(hash), Date.now())
|
|
415
|
+
}
|
|
416
|
+
|
|
321
417
|
/** @internal */
|
|
322
418
|
function toReceipt(receipt: TransactionReceipt) {
|
|
323
419
|
const { status, transactionHash } = receipt
|