@unchainedshop/plugins 1.2.36 → 2.0.0-beta1

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.
Files changed (94) hide show
  1. package/lib/files/gridfs/gridfs-webhook.js +1 -1
  2. package/lib/files/gridfs/gridfs-webhook.js.map +1 -1
  3. package/lib/files/minio/minio-webhook.js +1 -1
  4. package/lib/files/minio/minio-webhook.js.map +1 -1
  5. package/lib/payment/apple-iap/adapter.js +1 -1
  6. package/lib/payment/apple-iap/adapter.js.map +1 -1
  7. package/lib/payment/bity/adapter.js +2 -2
  8. package/lib/payment/bity/adapter.js.map +1 -1
  9. package/lib/payment/cryptopay/db/CryptopayTransactions.d.ts +13 -0
  10. package/lib/payment/cryptopay/db/CryptopayTransactions.js +4 -0
  11. package/lib/payment/cryptopay/db/CryptopayTransactions.js.map +1 -0
  12. package/lib/payment/cryptopay/index.d.ts +5 -0
  13. package/lib/payment/cryptopay/index.js +6 -0
  14. package/lib/payment/cryptopay/index.js.map +1 -0
  15. package/lib/payment/{cryptopay.d.ts → cryptopay/middleware.d.ts} +0 -0
  16. package/lib/payment/cryptopay/middleware.js +79 -0
  17. package/lib/payment/cryptopay/middleware.js.map +1 -0
  18. package/lib/payment/cryptopay/module/configureCryptopayModule.d.ts +25 -0
  19. package/lib/payment/cryptopay/module/configureCryptopayModule.js +75 -0
  20. package/lib/payment/cryptopay/module/configureCryptopayModule.js.map +1 -0
  21. package/lib/payment/cryptopay/plugin.d.ts +3 -0
  22. package/lib/payment/cryptopay/plugin.js +201 -0
  23. package/lib/payment/cryptopay/plugin.js.map +1 -0
  24. package/lib/payment/datatrans-v2/middleware.js +1 -1
  25. package/lib/payment/datatrans-v2/middleware.js.map +1 -1
  26. package/lib/payment/postfinance-checkout/middleware.js +1 -1
  27. package/lib/payment/postfinance-checkout/middleware.js.map +1 -1
  28. package/lib/pricing/product-catalog-price.js.map +1 -1
  29. package/lib/pricing/product-price-rateconversion.js +23 -17
  30. package/lib/pricing/product-price-rateconversion.js.map +1 -1
  31. package/lib/pricing/product-price-round.js +2 -1
  32. package/lib/pricing/product-price-round.js.map +1 -1
  33. package/lib/warehousing/google-sheets.js +3 -2
  34. package/lib/warehousing/google-sheets.js.map +1 -1
  35. package/lib/{pricing/product-price-ECB-interbank-exchange.d.ts → warehousing/infinite-minter.d.ts} +0 -0
  36. package/lib/warehousing/infinite-minter.js +50 -0
  37. package/lib/warehousing/infinite-minter.js.map +1 -0
  38. package/lib/warehousing/store.js +2 -1
  39. package/lib/warehousing/store.js.map +1 -1
  40. package/lib/worker/BulkImportWorker.js +2 -3
  41. package/lib/worker/BulkImportWorker.js.map +1 -1
  42. package/lib/worker/ZombieKillerWorker.js +2 -3
  43. package/lib/worker/ZombieKillerWorker.js.map +1 -1
  44. package/lib/worker/email.js.map +1 -1
  45. package/lib/worker/export-token.d.ts +4 -0
  46. package/lib/worker/export-token.js +25 -0
  47. package/lib/worker/export-token.js.map +1 -0
  48. package/lib/worker/external.js +1 -0
  49. package/lib/worker/external.js.map +1 -1
  50. package/lib/{pricing/product-price-coinbase-exchange.d.ts → worker/update-coinbase-rates.d.ts} +0 -0
  51. package/lib/worker/update-coinbase-rates.js +69 -0
  52. package/lib/worker/update-coinbase-rates.js.map +1 -0
  53. package/lib/worker/update-ecb-rates.d.ts +1 -0
  54. package/lib/worker/update-ecb-rates.js +79 -0
  55. package/lib/worker/update-ecb-rates.js.map +1 -0
  56. package/package.json +23 -20
  57. package/src/files/gridfs/gridfs-webhook.ts +1 -1
  58. package/src/files/minio/minio-webhook.js +1 -1
  59. package/src/payment/apple-iap/adapter.ts +1 -1
  60. package/src/payment/bity/adapter.ts +2 -2
  61. package/src/payment/cryptopay/db/CryptopayTransactions.ts +17 -0
  62. package/src/payment/cryptopay/index.ts +8 -0
  63. package/src/payment/cryptopay/middleware.ts +95 -0
  64. package/src/payment/cryptopay/module/configureCryptopayModule.ts +133 -0
  65. package/src/payment/cryptopay/plugin.ts +289 -0
  66. package/src/payment/cryptopay/readme.md +1 -0
  67. package/src/payment/datatrans-v2/middleware.ts +1 -1
  68. package/src/payment/postfinance-checkout/middleware.ts +1 -1
  69. package/src/pricing/product-catalog-price.ts +1 -0
  70. package/src/pricing/product-price-rateconversion.ts +25 -28
  71. package/src/pricing/product-price-round.ts +3 -1
  72. package/src/warehousing/google-sheets.ts +4 -2
  73. package/src/warehousing/infinite-minter.ts +66 -0
  74. package/src/warehousing/store.ts +3 -1
  75. package/src/worker/BulkImportWorker.ts +2 -3
  76. package/src/worker/ZombieKillerWorker.ts +2 -3
  77. package/src/worker/email.ts +0 -1
  78. package/src/worker/export-token.ts +31 -0
  79. package/src/worker/external.ts +1 -0
  80. package/src/worker/update-coinbase-rates.ts +91 -0
  81. package/src/worker/update-ecb-rates.ts +97 -0
  82. package/lib/payment/cryptopay.js +0 -161
  83. package/lib/payment/cryptopay.js.map +0 -1
  84. package/lib/pricing/product-price-ECB-interbank-exchange.js +0 -90
  85. package/lib/pricing/product-price-ECB-interbank-exchange.js.map +0 -1
  86. package/lib/pricing/product-price-coinbase-exchange.js +0 -60
  87. package/lib/pricing/product-price-coinbase-exchange.js.map +0 -1
  88. package/lib/pricing/product-price-cryptopay.d.ts +0 -2
  89. package/lib/pricing/product-price-cryptopay.js +0 -23
  90. package/lib/pricing/product-price-cryptopay.js.map +0 -1
  91. package/src/payment/cryptopay.ts +0 -197
  92. package/src/pricing/product-price-ECB-interbank-exchange.ts +0 -108
  93. package/src/pricing/product-price-coinbase-exchange.ts +0 -82
  94. package/src/pricing/product-price-cryptopay.ts +0 -27
@@ -1,197 +0,0 @@
1
- import { Context } from '@unchainedshop/types/api';
2
- import { IPaymentAdapter } from '@unchainedshop/types/payments';
3
- import bodyParser from 'body-parser';
4
- import { useMiddlewareWithCurrentContext } from '@unchainedshop/api';
5
- import { PaymentAdapter, PaymentDirector, PaymentError } from '@unchainedshop/core-payment';
6
- import { OrderPricingSheet } from '@unchainedshop/core-orders';
7
- import { ethers } from 'ethers';
8
- import BIP32Factory from 'bip32';
9
- import * as ecc from 'tiny-secp256k1';
10
- import * as bitcoin from 'bitcoinjs-lib';
11
- import { createLogger } from '@unchainedshop/logger';
12
-
13
- const logger = createLogger('unchained:core-payment:cryptopay');
14
-
15
- const {
16
- CRYPTOPAY_SECRET,
17
- CRYPTOPAY_WEBHOOK_PATH = '/payment/cryptopay',
18
- CRYPTOPAY_BTC_XPUB,
19
- CRYPTOPAY_ETH_XPUB,
20
- CRYPTOPAY_BTC_TESTNET = false,
21
- CRYPTOPAY_MAX_RATE_AGE = '360', // seconds
22
- CRYPTOPAY_MAX_CONV_DIFF = '0.01',
23
- } = process.env;
24
-
25
- enum CryptopayCurrencies { // eslint-disable-line
26
- BTC = 'BTC',
27
- ETH = 'ETH',
28
- }
29
-
30
- const MAX_RATE_AGE = parseInt(CRYPTOPAY_MAX_RATE_AGE, 10);
31
- const MAX_ALLOWED_DIFF = parseFloat(CRYPTOPAY_MAX_CONV_DIFF); // Accept payments when the converted amount differs by adapterActions much (in percent)
32
-
33
- export default (app) => {
34
- useMiddlewareWithCurrentContext(app, CRYPTOPAY_WEBHOOK_PATH, bodyParser.json());
35
-
36
- useMiddlewareWithCurrentContext(app, CRYPTOPAY_WEBHOOK_PATH, async (request, response) => {
37
- // Return a 200 response to acknowledge receipt of the event
38
- const resolvedContext = request.unchainedContext as Context;
39
- const { currency, contract, decimals, address, amount, secret } = request.body;
40
- if (secret !== CRYPTOPAY_SECRET) {
41
- logger.warn(`Cryptopay Plugin: Invalid Cryptopay Secret provided`);
42
- response.end(JSON.stringify({ success: false }));
43
- return;
44
- }
45
- const orderPayment = await resolvedContext.modules.orders.payments.findOrderPaymentByContextData({
46
- context: { cryptoAddresses: { currency, address } },
47
- });
48
- if (orderPayment) {
49
- if (currency === CryptopayCurrencies.ETH && contract && contract !== '') {
50
- const ERC20CurrencyCount = await resolvedContext.modules.currencies.count({
51
- includeInactive: false,
52
- contractAddress: contract,
53
- });
54
- if (!ERC20CurrencyCount) {
55
- logger.warn(`Cryptopay Plugin: ERC20 token address ${contract} not whitelisted.`);
56
- response.end(JSON.stringify({ success: false }));
57
- return;
58
- }
59
- }
60
- const order = await resolvedContext.modules.orders.findOrder({
61
- orderId: orderPayment.orderId,
62
- });
63
- const pricing = OrderPricingSheet({
64
- calculation: order.calculation,
65
- currency: order.currency,
66
- });
67
- const totalAmount = pricing?.total({ useNetPrice: false }).amount;
68
- let convertedAmount: number;
69
- if (order.currency === currency) {
70
- convertedAmount = amount / 10 ** (decimals - 8); // All crypto native prices denoted with 8 decimals
71
- } else {
72
- // Need to convert
73
- const rate = await resolvedContext.modules.products.prices.rates.getRate(
74
- order.currency,
75
- contract && contract !== '' ? contract : currency, // Convert to the smart contract if given
76
- MAX_RATE_AGE,
77
- );
78
- if (rate) {
79
- // We assume that we are converting to a fiat currency here (with 2 decimals).
80
- // Paying an order with prices in crypto in another crypto is not supported.
81
- convertedAmount = Math.round((amount / 10 ** decimals) * rate * 100);
82
- }
83
- }
84
- if (convertedAmount && convertedAmount >= totalAmount * (1 - MAX_ALLOWED_DIFF)) {
85
- await resolvedContext.modules.orders.checkout(
86
- order._id,
87
- {
88
- transactionContext: { address },
89
- paymentContext: { address },
90
- },
91
- resolvedContext,
92
- );
93
- response.end(JSON.stringify({ success: true }));
94
- } else {
95
- logger.warn(
96
- `Cryptopay Plugin: OrderPayment ${orderPayment._id} not marked as paid. Converted amount is ${convertedAmount}`,
97
- );
98
- response.end(JSON.stringify({ success: false }));
99
- }
100
- } else {
101
- logger.info(
102
- `Cryptopay Plugin: No orderPayment with address ${address} and currency ${currency} found`,
103
- );
104
- response.end(JSON.stringify({ success: false }));
105
- }
106
- });
107
- };
108
-
109
- const Cryptopay: IPaymentAdapter = {
110
- ...PaymentAdapter,
111
-
112
- key: 'shop.unchained.payment.cryptopay',
113
- label: 'Cryptopay',
114
- version: '1.0',
115
-
116
- typeSupported(type) {
117
- return type === 'GENERIC';
118
- },
119
-
120
- actions: (params) => {
121
- const { modules } = params.context;
122
-
123
- const adapterActions = {
124
- ...PaymentAdapter.actions(params),
125
-
126
- // eslint-disable-next-line
127
- configurationError() {
128
- // eslint-disable-line
129
- if (!CRYPTOPAY_SECRET) {
130
- return PaymentError.INCOMPLETE_CONFIGURATION;
131
- }
132
- return null;
133
- },
134
-
135
- isActive() {
136
- if (adapterActions.configurationError() === null) return true;
137
- return false;
138
- },
139
-
140
- isPayLaterAllowed() {
141
- return false;
142
- },
143
-
144
- sign: async () => {
145
- const { orderPayment } = params.paymentContext;
146
- if (orderPayment?.context.length) {
147
- // Do not derive address a second time for order payment, return existing address
148
- const existingAddresses = orderPayment.context.filter((c) => c.currency);
149
- if (existingAddresses) {
150
- return JSON.stringify(existingAddresses);
151
- }
152
- }
153
- const cryptoAddresses: { currency: CryptopayCurrencies; address: string }[] = [];
154
- if (CRYPTOPAY_BTC_XPUB) {
155
- const network = CRYPTOPAY_BTC_TESTNET ? bitcoin.networks.testnet : bitcoin.networks.bitcoin;
156
- const bip32 = BIP32Factory(ecc);
157
- const hardenedMaster = bip32.fromBase58(CRYPTOPAY_BTC_XPUB, network);
158
- const btcDerivationNumber = await modules.orders.payments.countOrderPaymentsByContextData({
159
- context: { cryptoAddresses: { currency: CryptopayCurrencies.BTC } },
160
- });
161
- const child = hardenedMaster.derivePath(`0/${btcDerivationNumber}`);
162
- cryptoAddresses.push({
163
- currency: CryptopayCurrencies.BTC,
164
- address: bitcoin.payments.p2pkh({
165
- pubkey: child.publicKey,
166
- network,
167
- }).address,
168
- });
169
- }
170
- if (CRYPTOPAY_ETH_XPUB) {
171
- const hardenedMaster = ethers.utils.HDNode.fromExtendedKey(CRYPTOPAY_ETH_XPUB);
172
- const ethDerivationNumber = await modules.orders.payments.countOrderPaymentsByContextData({
173
- context: { cryptoAddresses: { currency: CryptopayCurrencies.ETH } },
174
- });
175
- cryptoAddresses.push({
176
- currency: CryptopayCurrencies.ETH,
177
- address: hardenedMaster.derivePath(`0/${ethDerivationNumber}`).address,
178
- });
179
- }
180
- await modules.orders.payments.updateContext(
181
- orderPayment._id,
182
- { cryptoAddresses },
183
- params.context,
184
- );
185
- return JSON.stringify(cryptoAddresses);
186
- },
187
-
188
- charge: async (): Promise<false> => {
189
- return false;
190
- },
191
- };
192
-
193
- return adapterActions;
194
- },
195
- };
196
-
197
- PaymentDirector.registerAdapter(Cryptopay);
@@ -1,108 +0,0 @@
1
- import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing';
2
- import fetch from 'node-fetch';
3
- import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
4
- import xmlJs from 'xml-js';
5
-
6
- import Cache from './utils/cache';
7
-
8
- const CACHE_PERIOD = 60 * 60 * 24; // 1 day
9
-
10
- const SUPPORTED_CURRENCIES = [
11
- 'USD',
12
- 'JPY',
13
- 'BGN',
14
- 'CZK',
15
- 'DKK',
16
- 'GBP',
17
- 'HUF',
18
- 'PLN',
19
- 'RON',
20
- 'SEK',
21
- 'CHF',
22
- 'ISK',
23
- 'NOK',
24
- 'HRK',
25
- 'RUB',
26
- 'TRY',
27
- 'AUD',
28
- 'BRL',
29
- 'CAD',
30
- 'CNY',
31
- 'HKD',
32
- 'IDR',
33
- 'ILS',
34
- 'INR',
35
- 'KRW',
36
- 'MXN',
37
- 'MYR',
38
- 'NZD',
39
- 'PHP',
40
- 'SGD',
41
- 'THB',
42
- 'ZAR',
43
- ];
44
-
45
- const cache = new Cache(CACHE_PERIOD);
46
-
47
- const getEURexchangeRateForCurrency = async (currency) => {
48
- const response = cache.get(currency, () =>
49
- fetch(`https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml`, {
50
- method: 'GET',
51
- })
52
- .then((res) => res.text())
53
- .then((text) => JSON.parse(xmlJs.xml2json(text)))
54
- .then(
55
- (json) =>
56
- json.elements?.[0]?.elements
57
- .filter((e) => e.name.toLowerCase() === 'cube')[0]
58
- ?.elements[0]?.elements.filter((a) => a.attributes.currency === currency)?.[0]?.attributes,
59
- ),
60
- );
61
- return response;
62
- };
63
-
64
- const ProductPriceECBIntraBankExchange: IProductPricingAdapter = {
65
- ...ProductPricingAdapter,
66
-
67
- key: 'shop.unchained.pricing.price-ECB-intrabank-exchange',
68
- version: '1.0',
69
- label: 'Convert EUR to X with current exchange rate',
70
- orderIndex: 1,
71
-
72
- isActivatedFor: (context) => {
73
- return SUPPORTED_CURRENCIES.indexOf(context.currency) !== -1;
74
- },
75
-
76
- actions: (params) => {
77
- const pricingAdapter = ProductPricingAdapter.actions(params);
78
-
79
- return {
80
- ...pricingAdapter,
81
-
82
- calculate: async () => {
83
- const { product, country, quantity, currency, modules } = params.context;
84
- const { calculation = [] } = params.calculationSheet;
85
- const EURprice = await modules.products.prices.price(product, {
86
- country,
87
- currency: 'EUR',
88
- quantity,
89
- });
90
- if (!EURprice || !EURprice?.amount || calculation?.length) return pricingAdapter.calculate();
91
-
92
- const exchange = await getEURexchangeRateForCurrency(currency);
93
- const convertedAmount = EURprice.amount * exchange.rate;
94
- pricingAdapter.resultSheet().resetCalculation(params.calculationSheet);
95
- pricingAdapter.resultSheet().addItem({
96
- amount: convertedAmount * quantity,
97
- isTaxable: EURprice.isTaxable,
98
- isNetPrice: EURprice.isNetPrice,
99
- meta: { adapter: ProductPriceECBIntraBankExchange.key },
100
- });
101
-
102
- return pricingAdapter.calculate();
103
- },
104
- };
105
- },
106
- };
107
-
108
- ProductPricingDirector.registerAdapter(ProductPriceECBIntraBankExchange);
@@ -1,82 +0,0 @@
1
- import { IProductPricingAdapter } from '@unchainedshop/types/products.pricing';
2
- import fetch from 'node-fetch';
3
- import { ProductPricingDirector, ProductPricingAdapter } from '@unchainedshop/core-products';
4
-
5
- import Cache from './utils/cache';
6
-
7
- const CACHE_PERIOD = 60 * 60 * 0.1; // 10 minutes
8
- const SUPPORTED_CURRENCIES = ['BTC', 'ETH', 'XRP', 'USDT', 'BCH', 'BSV', 'LTC', 'EOS', 'BNB', 'XTZ'];
9
- const cache = new Cache(CACHE_PERIOD);
10
-
11
- const getFiatexchangeRateForCrypto = async (base, target) => {
12
- const { data } = await cache.get(`${base}-${target}`, () =>
13
- fetch(`https://api.coinbase.com/v2/exchange-rates?currency=${base}`, {
14
- method: 'GET',
15
- }).then((res) => res.json()),
16
- );
17
- return data?.rates?.[target];
18
- };
19
-
20
- const ProductPriceCoinbaseExchange: IProductPricingAdapter = {
21
- ...ProductPricingAdapter,
22
-
23
- key: 'shop.unchained.pricing.price-coinbase-exchange',
24
- version: '1.0',
25
- label: 'Convert fiat/crypto to crypto with current exchange rate',
26
- orderIndex: 1,
27
-
28
- isActivatedFor: (context) => {
29
- return SUPPORTED_CURRENCIES.indexOf(context.currency.toUpperCase()) !== -1;
30
- },
31
-
32
- actions: (params) => {
33
- const pricingAdapter = ProductPricingAdapter.actions(params);
34
- const { services, modules } = params.context;
35
- return {
36
- ...pricingAdapter,
37
-
38
- calculate: async () => {
39
- const { product, country, quantity, currency } = params.context;
40
- const defaultCurrency = await services.countries.resolveDefaultCurrencyCode(
41
- {
42
- isoCode: country,
43
- },
44
- params.context,
45
- );
46
-
47
- const productPrice = await modules.products.prices.price(product, {
48
- country,
49
- currency: defaultCurrency,
50
- quantity,
51
- });
52
-
53
- const { calculation = [] } = params.calculationSheet;
54
-
55
- if (
56
- !productPrice ||
57
- !productPrice?.amount ||
58
- calculation?.length ||
59
- defaultCurrency === currency
60
- )
61
- return pricingAdapter.calculate();
62
-
63
- const rate = await getFiatexchangeRateForCrypto(defaultCurrency, currency);
64
-
65
- if (rate > 0) {
66
- const convertedAmount = productPrice.amount * rate;
67
- pricingAdapter.resultSheet().resetCalculation(params.calculationSheet);
68
- pricingAdapter.resultSheet().addItem({
69
- amount: convertedAmount * quantity,
70
- isTaxable: productPrice?.isTaxable,
71
- isNetPrice: productPrice?.isNetPrice,
72
- meta: { adapter: ProductPriceCoinbaseExchange.key },
73
- });
74
- }
75
-
76
- return pricingAdapter.calculate();
77
- },
78
- };
79
- },
80
- };
81
-
82
- ProductPricingDirector.registerAdapter(ProductPriceCoinbaseExchange);
@@ -1,27 +0,0 @@
1
- import { Context } from '@unchainedshop/types/api';
2
- import { ProductPriceRate } from '@unchainedshop/types/products.pricing';
3
- import bodyParser from 'body-parser';
4
- import { useMiddlewareWithCurrentContext } from '@unchainedshop/api';
5
-
6
- const { CRYPTOPAY_SECRET, CRYPTOPAY_PRICING_WEBHOOK_PATH = '/pricing/cryptopay' } = process.env;
7
-
8
- export default (app) => {
9
- useMiddlewareWithCurrentContext(app, CRYPTOPAY_PRICING_WEBHOOK_PATH, bodyParser.json());
10
-
11
- useMiddlewareWithCurrentContext(app, CRYPTOPAY_PRICING_WEBHOOK_PATH, async (request, response) => {
12
- const resolvedContext = request.unchainedContext as Context;
13
- const { baseCurrency, token, rate, timestamp, secret } = request.body;
14
- if (secret !== CRYPTOPAY_SECRET) {
15
- response.end(JSON.stringify({ success: false }));
16
- return;
17
- }
18
- const rateData: ProductPriceRate = {
19
- baseCurrency,
20
- quoteCurrency: token,
21
- rate,
22
- timestamp,
23
- };
24
- const success = await resolvedContext.modules.products.prices.rates.updateRate(rateData);
25
- response.end(JSON.stringify({ success }));
26
- });
27
- };