payment-kit 1.13.60 → 1.13.62
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/api/src/integrations/blockchain/stake.ts +22 -1
- package/api/src/libs/logger.ts +1 -1
- package/api/src/routes/connect/setup.ts +3 -10
- package/api/src/routes/connect/shared.ts +40 -1
- package/api/src/routes/connect/subscribe.ts +3 -10
- package/api/src/store/migrate.ts +7 -1
- package/api/src/store/migrations/20230905-genesis.ts +46 -46
- package/api/src/store/migrations/20230911-seeding.ts +6 -6
- package/api/src/store/migrations/20231017-pricing-table.ts +4 -4
- package/api/src/store/migrations/20231021-nft.ts +0 -1
- package/api/src/store/sequelize.ts +1 -1
- package/blocklet.yml +1 -3
- package/package.json +4 -4
|
@@ -33,7 +33,7 @@ export async function ensureStakedForGas() {
|
|
|
33
33
|
|
|
34
34
|
const result = await client.getForgeState({});
|
|
35
35
|
const { token, txConfig } = result.state;
|
|
36
|
-
const holding = account
|
|
36
|
+
const holding = (account?.tokens || []).find((x: any) => x.address === token.address);
|
|
37
37
|
if (toBN(holding?.value || '0').lte(toBN(txConfig.txGas.minStake))) {
|
|
38
38
|
logger.info(`not enough balance to stake for gas on chain ${host}`);
|
|
39
39
|
continue;
|
|
@@ -53,3 +53,24 @@ export async function ensureStakedForGas() {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
|
|
57
|
+
export async function hasStakedForGas(method: PaymentMethod, sender = wallet.address) {
|
|
58
|
+
if (method.type === 'arcblock') {
|
|
59
|
+
const client = method.getOcapClient();
|
|
60
|
+
const address = toStakeAddress(sender, sender);
|
|
61
|
+
const { state } = await client.getStakeState({ address });
|
|
62
|
+
return !!state;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function estimateMaxGasForTx(method: PaymentMethod, typeUrl = 'fg:t:delegate') {
|
|
69
|
+
if (method.type === 'arcblock') {
|
|
70
|
+
const client = method.getOcapClient();
|
|
71
|
+
const { estimate } = await client.estimateGas({ typeUrl });
|
|
72
|
+
return estimate.max;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return '0';
|
|
76
|
+
}
|
package/api/src/libs/logger.ts
CHANGED
|
@@ -20,7 +20,7 @@ const init = (label: string): Logger => {
|
|
|
20
20
|
return instance;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
const logger = process.env.
|
|
23
|
+
const logger = process.env.BLOCKLET_ENV === 'production' ? consoleLogger : init('app');
|
|
24
24
|
|
|
25
25
|
export default logger;
|
|
26
26
|
|
|
@@ -7,10 +7,8 @@ import { subscriptionQueue } from '../../jobs/subscription';
|
|
|
7
7
|
import type { CallbackArgs } from '../../libs/auth';
|
|
8
8
|
import { wallet } from '../../libs/auth';
|
|
9
9
|
import { getGasPayerExtra } from '../../libs/payment';
|
|
10
|
-
import { getFastCheckoutAmount } from '../../libs/session';
|
|
11
10
|
import { getTxMetadata } from '../../libs/util';
|
|
12
|
-
import
|
|
13
|
-
import { ensureSetupIntent, getAuthPrincipalClaim } from './shared';
|
|
11
|
+
import { ensureSetupIntent, getAuthPrincipalClaim, getTokenRequirements } from './shared';
|
|
14
12
|
|
|
15
13
|
export default {
|
|
16
14
|
action: 'setup',
|
|
@@ -32,12 +30,7 @@ export default {
|
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
if (paymentMethod.type === 'arcblock') {
|
|
35
|
-
const
|
|
36
|
-
checkoutSession.line_items as TLineItemExpanded[],
|
|
37
|
-
checkoutSession.mode,
|
|
38
|
-
paymentCurrency,
|
|
39
|
-
!!checkoutSession.subscription_data?.trial_period_days
|
|
40
|
-
);
|
|
33
|
+
const tokenRequirements = await getTokenRequirements(checkoutSession, paymentMethod, paymentCurrency);
|
|
41
34
|
|
|
42
35
|
return {
|
|
43
36
|
signature: {
|
|
@@ -57,7 +50,7 @@ export default {
|
|
|
57
50
|
},
|
|
58
51
|
nonce: checkoutSessionId,
|
|
59
52
|
requirement: {
|
|
60
|
-
tokens:
|
|
53
|
+
tokens: tokenRequirements,
|
|
61
54
|
},
|
|
62
55
|
chainInfo: {
|
|
63
56
|
host: paymentMethod.settings?.arcblock?.api_host as string,
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { BN } from '@ocap/util';
|
|
2
2
|
|
|
3
|
+
import { estimateMaxGasForTx, hasStakedForGas } from '../../integrations/blockchain/stake';
|
|
3
4
|
import { blocklet } from '../../libs/auth';
|
|
4
5
|
import dayjs from '../../libs/dayjs';
|
|
5
6
|
import logger from '../../libs/logger';
|
|
6
|
-
import { getStatementDescriptor } from '../../libs/session';
|
|
7
|
+
import { getFastCheckoutAmount, getStatementDescriptor } from '../../libs/session';
|
|
7
8
|
import type { TLineItemExpanded } from '../../store/models';
|
|
8
9
|
import { CheckoutSession } from '../../store/models/checkout-session';
|
|
9
10
|
import { Customer } from '../../store/models/customer';
|
|
@@ -450,3 +451,41 @@ export function getAuthPrincipalClaim(method: PaymentMethod, action: string) {
|
|
|
450
451
|
chainInfo,
|
|
451
452
|
};
|
|
452
453
|
}
|
|
454
|
+
|
|
455
|
+
export async function getTokenRequirements(
|
|
456
|
+
checkoutSession: CheckoutSession,
|
|
457
|
+
paymentMethod: PaymentMethod,
|
|
458
|
+
paymentCurrency: PaymentCurrency
|
|
459
|
+
) {
|
|
460
|
+
const tokenRequirements = [];
|
|
461
|
+
let amount = getFastCheckoutAmount(
|
|
462
|
+
checkoutSession.line_items as TLineItemExpanded[],
|
|
463
|
+
checkoutSession.mode,
|
|
464
|
+
paymentCurrency,
|
|
465
|
+
!!checkoutSession.subscription_data?.trial_period_days
|
|
466
|
+
);
|
|
467
|
+
|
|
468
|
+
// If the app has not staked, we need to add the gas fee to the amount
|
|
469
|
+
if ((await hasStakedForGas(paymentMethod)) === false) {
|
|
470
|
+
const maxGas = await estimateMaxGasForTx(paymentMethod);
|
|
471
|
+
// pay with the base currency? just add gas to it
|
|
472
|
+
if (paymentCurrency.is_base_currency) {
|
|
473
|
+
amount = new BN(amount).add(new BN(maxGas)).toString();
|
|
474
|
+
tokenRequirements.push({ address: paymentCurrency.contract as string, value: amount });
|
|
475
|
+
} else {
|
|
476
|
+
tokenRequirements.push({ address: paymentCurrency.contract as string, value: amount });
|
|
477
|
+
const baseCurrency = await PaymentCurrency.findOne({
|
|
478
|
+
where: { active: true, is_base_currency: true, payment_method_id: paymentMethod.id },
|
|
479
|
+
});
|
|
480
|
+
if (baseCurrency) {
|
|
481
|
+
tokenRequirements.push({ address: baseCurrency.contract as string, value: maxGas });
|
|
482
|
+
} else {
|
|
483
|
+
throw new Error('Base currency not found since app has not staked for gas');
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
} else {
|
|
487
|
+
tokenRequirements.push({ address: paymentCurrency.contract as string, value: amount });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return tokenRequirements;
|
|
491
|
+
}
|
|
@@ -9,10 +9,8 @@ import { subscriptionQueue } from '../../jobs/subscription';
|
|
|
9
9
|
import type { CallbackArgs } from '../../libs/auth';
|
|
10
10
|
import { wallet } from '../../libs/auth';
|
|
11
11
|
import { getGasPayerExtra } from '../../libs/payment';
|
|
12
|
-
import { getFastCheckoutAmount } from '../../libs/session';
|
|
13
12
|
import { getTxMetadata } from '../../libs/util';
|
|
14
|
-
import
|
|
15
|
-
import { ensureInvoiceForCheckout, ensurePaymentIntent, getAuthPrincipalClaim } from './shared';
|
|
13
|
+
import { ensureInvoiceForCheckout, ensurePaymentIntent, getAuthPrincipalClaim, getTokenRequirements } from './shared';
|
|
16
14
|
|
|
17
15
|
export default {
|
|
18
16
|
action: 'subscription',
|
|
@@ -34,12 +32,7 @@ export default {
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
if (paymentMethod.type === 'arcblock') {
|
|
37
|
-
const
|
|
38
|
-
checkoutSession.line_items as TLineItemExpanded[],
|
|
39
|
-
checkoutSession.mode,
|
|
40
|
-
paymentCurrency,
|
|
41
|
-
!!checkoutSession.subscription_data?.trial_period_days
|
|
42
|
-
);
|
|
35
|
+
const tokenRequirements = await getTokenRequirements(checkoutSession, paymentMethod, paymentCurrency);
|
|
43
36
|
|
|
44
37
|
return {
|
|
45
38
|
signature: {
|
|
@@ -59,7 +52,7 @@ export default {
|
|
|
59
52
|
},
|
|
60
53
|
nonce: checkoutSessionId,
|
|
61
54
|
requirement: {
|
|
62
|
-
tokens:
|
|
55
|
+
tokens: tokenRequirements,
|
|
63
56
|
},
|
|
64
57
|
chainInfo: {
|
|
65
58
|
host: paymentMethod.settings?.arcblock?.api_host as string,
|
package/api/src/store/migrate.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
1
2
|
/* eslint-disable no-await-in-loop */
|
|
2
3
|
import type { QueryInterface } from 'sequelize';
|
|
3
4
|
import { SequelizeStorage, Umzug } from 'umzug';
|
|
4
5
|
|
|
6
|
+
import logger from '../libs/logger';
|
|
5
7
|
import { sequelize } from './sequelize';
|
|
6
8
|
|
|
7
9
|
const umzug = new Umzug({
|
|
8
10
|
migrations: { glob: ['migrations/*.{ts,js}', { cwd: __dirname }] },
|
|
9
11
|
context: sequelize.getQueryInterface(),
|
|
10
12
|
storage: new SequelizeStorage({ sequelize }),
|
|
11
|
-
logger
|
|
13
|
+
logger,
|
|
12
14
|
});
|
|
13
15
|
|
|
14
16
|
export default function migrate() {
|
|
@@ -17,14 +19,18 @@ export default function migrate() {
|
|
|
17
19
|
|
|
18
20
|
type ColumnChanges = Record<string, { name: string; field: any }[]>;
|
|
19
21
|
export async function safeApplyColumnChanges(context: QueryInterface, changes: ColumnChanges) {
|
|
22
|
+
console.info('safeApplyColumnChanges', changes);
|
|
20
23
|
for (const [table, columns] of Object.entries(changes)) {
|
|
21
24
|
const schema = await context.describeTable(table);
|
|
22
25
|
for (const { name, field } of columns) {
|
|
23
26
|
if (!schema[name]) {
|
|
24
27
|
await context.addColumn(table, name, field);
|
|
28
|
+
console.info('safeApplyColumnChanges.addColumn', { table, name, field });
|
|
25
29
|
if (field.defaultValue) {
|
|
26
30
|
await context.bulkUpdate(table, { [name]: field.defaultValue }, {});
|
|
27
31
|
}
|
|
32
|
+
} else {
|
|
33
|
+
console.info('safeApplyColumnChanges.skip', { table, name, field });
|
|
28
34
|
}
|
|
29
35
|
}
|
|
30
36
|
}
|
|
@@ -1,52 +1,52 @@
|
|
|
1
1
|
import type { Migration } from '../migrate';
|
|
2
2
|
import models from '../models';
|
|
3
3
|
|
|
4
|
-
export const up: Migration = async ({ context
|
|
5
|
-
await
|
|
6
|
-
await
|
|
7
|
-
await
|
|
8
|
-
await
|
|
9
|
-
await
|
|
10
|
-
await
|
|
11
|
-
await
|
|
12
|
-
await
|
|
13
|
-
await
|
|
14
|
-
await
|
|
15
|
-
await
|
|
16
|
-
await
|
|
17
|
-
await
|
|
18
|
-
await
|
|
19
|
-
await
|
|
20
|
-
await
|
|
21
|
-
await
|
|
22
|
-
await
|
|
23
|
-
await
|
|
24
|
-
await
|
|
25
|
-
await
|
|
26
|
-
await
|
|
4
|
+
export const up: Migration = async ({ context }) => {
|
|
5
|
+
await context.createTable('checkout_sessions', models.CheckoutSession.GENESIS_ATTRIBUTES);
|
|
6
|
+
await context.createTable('coupons', models.Coupon.GENESIS_ATTRIBUTES);
|
|
7
|
+
await context.createTable('customers', models.Customer.GENESIS_ATTRIBUTES);
|
|
8
|
+
await context.createTable('discounts', models.Discount.GENESIS_ATTRIBUTES);
|
|
9
|
+
await context.createTable('events', models.Event.GENESIS_ATTRIBUTES);
|
|
10
|
+
await context.createTable('invoices', models.Invoice.GENESIS_ATTRIBUTES);
|
|
11
|
+
await context.createTable('invoice_items', models.InvoiceItem.GENESIS_ATTRIBUTES);
|
|
12
|
+
await context.createTable('jobs', models.Job.GENESIS_ATTRIBUTES);
|
|
13
|
+
await context.createTable('payment_currencies', models.PaymentCurrency.GENESIS_ATTRIBUTES);
|
|
14
|
+
await context.createTable('payment_intents', models.PaymentIntent.GENESIS_ATTRIBUTES);
|
|
15
|
+
await context.createTable('payment_links', models.PaymentLink.GENESIS_ATTRIBUTES);
|
|
16
|
+
await context.createTable('payment_methods', models.PaymentMethod.GENESIS_ATTRIBUTES);
|
|
17
|
+
await context.createTable('prices', models.Price.GENESIS_ATTRIBUTES);
|
|
18
|
+
await context.createTable('products', models.Product.GENESIS_ATTRIBUTES);
|
|
19
|
+
await context.createTable('promotion_codes', models.PromotionCode.GENESIS_ATTRIBUTES);
|
|
20
|
+
await context.createTable('setup_intents', models.SetupIntent.GENESIS_ATTRIBUTES);
|
|
21
|
+
await context.createTable('subscription_items', models.SubscriptionItem.GENESIS_ATTRIBUTES);
|
|
22
|
+
await context.createTable('subscription_schedules', models.SubscriptionSchedule.GENESIS_ATTRIBUTES);
|
|
23
|
+
await context.createTable('subscriptions', models.Subscription.GENESIS_ATTRIBUTES);
|
|
24
|
+
await context.createTable('usage_records', models.UsageRecord.GENESIS_ATTRIBUTES);
|
|
25
|
+
await context.createTable('webhook_attempts', models.WebhookAttempt.GENESIS_ATTRIBUTES);
|
|
26
|
+
await context.createTable('webhook_endpoints', models.WebhookEndpoint.GENESIS_ATTRIBUTES);
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
-
export const down: Migration = async ({ context
|
|
30
|
-
await
|
|
31
|
-
await
|
|
32
|
-
await
|
|
33
|
-
await
|
|
34
|
-
await
|
|
35
|
-
await
|
|
36
|
-
await
|
|
37
|
-
await
|
|
38
|
-
await
|
|
39
|
-
await
|
|
40
|
-
await
|
|
41
|
-
await
|
|
42
|
-
await
|
|
43
|
-
await
|
|
44
|
-
await
|
|
45
|
-
await
|
|
46
|
-
await
|
|
47
|
-
await
|
|
48
|
-
await
|
|
49
|
-
await
|
|
50
|
-
await
|
|
51
|
-
await
|
|
29
|
+
export const down: Migration = async ({ context }) => {
|
|
30
|
+
await context.dropTable('checkout_sessions');
|
|
31
|
+
await context.dropTable('coupons');
|
|
32
|
+
await context.dropTable('customers');
|
|
33
|
+
await context.dropTable('discounts');
|
|
34
|
+
await context.dropTable('events');
|
|
35
|
+
await context.dropTable('invoices');
|
|
36
|
+
await context.dropTable('invoice_items');
|
|
37
|
+
await context.dropTable('jobs');
|
|
38
|
+
await context.dropTable('payment_currencies');
|
|
39
|
+
await context.dropTable('payment_intents');
|
|
40
|
+
await context.dropTable('payment_links');
|
|
41
|
+
await context.dropTable('payment_methods');
|
|
42
|
+
await context.dropTable('prices');
|
|
43
|
+
await context.dropTable('products');
|
|
44
|
+
await context.dropTable('promotion_codes');
|
|
45
|
+
await context.dropTable('setup_intents');
|
|
46
|
+
await context.dropTable('subscription_items');
|
|
47
|
+
await context.dropTable('subscription_schedules');
|
|
48
|
+
await context.dropTable('subscriptions');
|
|
49
|
+
await context.dropTable('usage_records');
|
|
50
|
+
await context.dropTable('webhook_endpoints');
|
|
51
|
+
await context.dropTable('webhook_attempts');
|
|
52
52
|
};
|
|
@@ -158,8 +158,8 @@ const paymentMethods = [
|
|
|
158
158
|
},
|
|
159
159
|
];
|
|
160
160
|
|
|
161
|
-
export const up: Migration = async ({ context
|
|
162
|
-
await
|
|
161
|
+
export const up: Migration = async ({ context }) => {
|
|
162
|
+
await context.bulkInsert(
|
|
163
163
|
'payment_methods',
|
|
164
164
|
paymentMethods,
|
|
165
165
|
{},
|
|
@@ -170,7 +170,7 @@ export const up: Migration = async ({ context: queryInterface }) => {
|
|
|
170
170
|
metadata: { type: new Sequelize.JSON() },
|
|
171
171
|
}
|
|
172
172
|
);
|
|
173
|
-
await
|
|
173
|
+
await context.bulkInsert(
|
|
174
174
|
'payment_currencies',
|
|
175
175
|
paymentCurrencies,
|
|
176
176
|
{},
|
|
@@ -180,7 +180,7 @@ export const up: Migration = async ({ context: queryInterface }) => {
|
|
|
180
180
|
);
|
|
181
181
|
};
|
|
182
182
|
|
|
183
|
-
export const down: Migration = async ({ context
|
|
184
|
-
await
|
|
185
|
-
await
|
|
183
|
+
export const down: Migration = async ({ context }) => {
|
|
184
|
+
await context.bulkDelete('payment_methods', {});
|
|
185
|
+
await context.bulkDelete('payment_currencies', {});
|
|
186
186
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Migration } from '../migrate';
|
|
2
2
|
import models from '../models';
|
|
3
3
|
|
|
4
|
-
export const up: Migration = async ({ context
|
|
5
|
-
await
|
|
4
|
+
export const up: Migration = async ({ context }) => {
|
|
5
|
+
await context.createTable('pricing_tables', models.PricingTable.GENESIS_ATTRIBUTES);
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
export const down: Migration = async ({ context
|
|
9
|
-
await
|
|
8
|
+
export const down: Migration = async ({ context }) => {
|
|
9
|
+
await context.dropTable('pricing_tables');
|
|
10
10
|
};
|
|
@@ -9,7 +9,6 @@ export const up: Migration = async ({ context }) => {
|
|
|
9
9
|
checkout_sessions: [
|
|
10
10
|
{ name: 'nft_mint_settings', field: { type: DataTypes.JSON, allowNull: true } },
|
|
11
11
|
{ name: 'payment_intent_data', field: { type: DataTypes.JSON, allowNull: true } },
|
|
12
|
-
{ name: 'nft_mint_settings', field: { type: DataTypes.JSON, allowNull: true } },
|
|
13
12
|
{ name: 'nft_mint_details', field: { type: DataTypes.JSON, allowNull: true } },
|
|
14
13
|
{
|
|
15
14
|
name: 'nft_mint_status',
|
|
@@ -10,6 +10,6 @@ import env from '../libs/env';
|
|
|
10
10
|
// eslint-disable-next-line import/prefer-default-export
|
|
11
11
|
export const sequelize = new Sequelize({
|
|
12
12
|
dialect: 'sqlite',
|
|
13
|
-
logging:
|
|
13
|
+
logging: process.env.SQL_LOG === '1',
|
|
14
14
|
storage: join(env.dataDir, 'payment-kit.db'),
|
|
15
15
|
});
|
package/blocklet.yml
CHANGED
|
@@ -14,7 +14,7 @@ repository:
|
|
|
14
14
|
type: git
|
|
15
15
|
url: git+https://github.com/blocklet/payment-kit.git
|
|
16
16
|
specVersion: 1.2.8
|
|
17
|
-
version: 1.13.
|
|
17
|
+
version: 1.13.62
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -57,9 +57,7 @@ screenshots:
|
|
|
57
57
|
- 5-admin-4.png
|
|
58
58
|
components:
|
|
59
59
|
- name: image-bin
|
|
60
|
-
required: true
|
|
61
60
|
source:
|
|
62
|
-
store: https://test.store.blocklet.dev
|
|
63
61
|
name: image-bin
|
|
64
62
|
version: latest
|
|
65
63
|
navigation:
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.62",
|
|
4
4
|
"scripts": {
|
|
5
|
-
"dev": "blocklet dev",
|
|
5
|
+
"dev": "COMPONENT_STORE_URL=https://test.store.blocklet.dev blocklet dev",
|
|
6
6
|
"eject": "vite eject",
|
|
7
7
|
"lint": "tsc --noEmit && eslint src api/src --ext .mjs,.js,.jsx,.ts,.tsx",
|
|
8
8
|
"lint:fix": "npm run lint -- --fix",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"@abtnode/types": "1.16.18",
|
|
105
105
|
"@arcblock/eslint-config": "^0.2.4",
|
|
106
106
|
"@arcblock/eslint-config-ts": "^0.2.4",
|
|
107
|
-
"@did-pay/types": "1.13.
|
|
107
|
+
"@did-pay/types": "1.13.62",
|
|
108
108
|
"@types/cookie-parser": "^1.4.6",
|
|
109
109
|
"@types/cors": "^2.8.17",
|
|
110
110
|
"@types/dotenv-flow": "^3.3.3",
|
|
@@ -141,5 +141,5 @@
|
|
|
141
141
|
"parser": "typescript"
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
|
-
"gitHead": "
|
|
144
|
+
"gitHead": "e5cd5ce0c4960a576e2ad6f6cf24e30b3cf552b8"
|
|
145
145
|
}
|