payment-kit 1.17.1 → 1.17.3

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.
@@ -1,5 +1,4 @@
1
1
  import env from '@blocklet/sdk/lib/env';
2
- import { env as configEnv } from '@blocklet/sdk/lib/config';
3
2
 
4
3
  export const paymentStatCronTime: string = '0 1 0 * * *'; // 默认每天一次,计算前一天的
5
4
  export const subscriptionCronTime: string = process.env.SUBSCRIPTION_CRON_TIME || '0 */30 * * * *'; // 默认每 30 min 行一次
@@ -13,7 +12,6 @@ export const revokeStakeCronTime: string = process.env.REVOKE_STAKE_CRON_TIME ||
13
12
  export const daysUntilCancel: string | undefined = process.env.DAYS_UNTIL_CANCEL;
14
13
  export const meteringSubscriptionDetectionCronTime: string =
15
14
  process.env.METERING_SUBSCRIPTION_DETECTION_CRON_TIME || '0 0 10 * * *'; // 默认每天 10:00 执行
16
- export const overdraftProtectionMaxCount: number = Number(configEnv?.preferences?.overdraftProtectionMaxCount || 10); // 透支保护次数上限
17
15
 
18
16
  // sequelize 配置相关
19
17
  export const sequelizeOptionsPoolMin: number = process.env.SEQUELIZE_OPTIONS_POOL_MIN
@@ -10,6 +10,9 @@ export async function ensureOverdraftProtectionPrice(livemode = true) {
10
10
  const exist = await Price.findOne({ where: { lookup_key: lookUpKey, livemode } });
11
11
  if (exist) {
12
12
  const product = await Product.findByPk(exist.product_id);
13
+ if (product?.name === 'Overdraft Protection') {
14
+ product.update({ name: 'SubGuard Service' });
15
+ }
13
16
  return {
14
17
  product,
15
18
  price: exist,
@@ -27,7 +30,7 @@ export async function ensureOverdraftProtectionPrice(livemode = true) {
27
30
 
28
31
  const result = await createProductAndPrices({
29
32
  type: 'service',
30
- name: 'Overdraft Protection',
33
+ name: 'SubGuard Service',
31
34
  description:
32
35
  'If you purchase this service, the overdue subscription will be protected and not be ended due to overdue',
33
36
  images: [],
@@ -1296,7 +1296,7 @@ export async function returnOverdraftProtectionStake(
1296
1296
  const item = await Refund.create({
1297
1297
  type: 'stake_return',
1298
1298
  amount: unused,
1299
- description: 'overdraft protection_return_for_subscription',
1299
+ description: 'stake_return_for_subscription_guard',
1300
1300
  status: 'pending',
1301
1301
  reason: refundReason || 'requested_by_admin',
1302
1302
  subscription_id: subscription.id,
@@ -194,8 +194,8 @@ export default flat({
194
194
  },
195
195
 
196
196
  overdraftProtectionExhausted: {
197
- title: 'Insufficient Credit for Overdraft Protection',
198
- body: 'Your subscription to {productName} has insufficient staked credit for overdraft protection. Please increase your stake to maintain the service or disable it if no longer needed.',
197
+ title: 'Insufficient Credit for SubGuard',
198
+ body: 'Your subscription to {productName} has insufficient staked credit for SubGuard. Please increase your stake to maintain the service or disable it if no longer needed.',
199
199
  },
200
200
  },
201
201
  });
@@ -187,8 +187,8 @@ export default flat({
187
187
  },
188
188
 
189
189
  overdraftProtectionExhausted: {
190
- title: '透支保护额度不足',
191
- body: '您订阅的 {productName} 透支保护额度不足,为了避免影响您的透支保护服务,请及时充值。如不再需要透支保护服务,可关闭该功能。',
190
+ title: '订阅守护服务额度不足',
191
+ body: '您订阅的 {productName} 订阅守护服务额度不足,为了避免影响您的使用,请及时充值。如不再需要订阅守护服务,可关闭该功能。',
192
192
  },
193
193
  },
194
194
  });
@@ -68,7 +68,7 @@ import {
68
68
  import {
69
69
  OverdraftProtectionExhaustedEmailTemplate,
70
70
  OverdraftProtectionExhaustedEmailTemplateOptions,
71
- } from '../libs/notification/template/subscription.overdraft-protection.exhausted';
71
+ } from '../libs/notification/template/subscription-overdraft-protection-exhausted';
72
72
 
73
73
  export type NotificationQueueJobOptions = any;
74
74
 
@@ -1211,7 +1211,7 @@ events.on('customer.stake.revoked', async ({ subscriptionId, tx }: { subscriptio
1211
1211
  feedback: 'other',
1212
1212
  comment: `Revoked by ${tx.tx.from} with tx ${tx.hash}`,
1213
1213
  },
1214
- // 关闭透支保护
1214
+ // 关闭订阅守护
1215
1215
  // @ts-ignore
1216
1216
  overdraft_protection: {
1217
1217
  ...(subscription.overdraft_protection || {}),
@@ -1,6 +1,6 @@
1
1
  import type { CallbackArgs } from '../../libs/auth';
2
2
  import { isSubscriptionOverdraftProtectionEnabled } from '../../libs/subscription';
3
- import { Lock } from '../../store/models';
3
+ import { Lock, TLineItemExpanded } from '../../store/models';
4
4
  import {
5
5
  ensureSubscriptionForOverdraftProtection,
6
6
  executeOcapTransactions,
@@ -35,6 +35,8 @@ export default {
35
35
  );
36
36
  }
37
37
 
38
+ // @ts-ignore
39
+ const items = subscription!.items as TLineItemExpanded[];
38
40
  const claims: { [type: string]: [string, object] } = {};
39
41
 
40
42
  if (paymentMethod.type === 'arcblock') {
@@ -48,6 +50,7 @@ export default {
48
50
  paymentMethod,
49
51
  stakeAmount,
50
52
  subscription,
53
+ items,
51
54
  }),
52
55
  ];
53
56
 
@@ -692,6 +692,7 @@ export async function getOverdraftProtectionStakeTxClaim({
692
692
  paymentCurrency,
693
693
  paymentMethod,
694
694
  stakeAmount,
695
+ items,
695
696
  }: {
696
697
  userDid: string;
697
698
  userPk: string;
@@ -699,6 +700,7 @@ export async function getOverdraftProtectionStakeTxClaim({
699
700
  paymentCurrency: PaymentCurrency;
700
701
  paymentMethod: PaymentMethod;
701
702
  stakeAmount: string;
703
+ items: TLineItemExpanded[];
702
704
  }) {
703
705
  // create staking amount
704
706
  logger.info('getStakeTxClaim', {
@@ -725,9 +727,11 @@ export async function getOverdraftProtectionStakeTxClaim({
725
727
  ),
726
728
  };
727
729
 
730
+ const setup = getSubscriptionCreateSetup(items, paymentCurrency.id, 0, 0);
731
+
728
732
  return {
729
733
  type: 'StakeTx',
730
- description: `Stake to complete subscription ${subscription.id} overdraft protection`,
734
+ description: `Stake to complete subscription ${subscription.id} SubGuard`,
731
735
  partialTx: {
732
736
  from: userDid,
733
737
  pk: userPk,
@@ -735,8 +739,8 @@ export async function getOverdraftProtectionStakeTxClaim({
735
739
  address,
736
740
  receiver: wallet.address,
737
741
  slashers: [wallet.address],
738
- revokeWaitingPeriod: 0,
739
- message: `Stake for subscription ${subscription.id} overdraft protection`,
742
+ revokeWaitingPeriod: setup.cycle.duration / 1000, // wait for at least 1 billing cycle
743
+ message: `Stake for subscription ${subscription.id} SubGuard`,
740
744
  nonce,
741
745
  inputs: [],
742
746
  data,
@@ -946,12 +950,13 @@ export async function ensureSubscriptionForCollectBatch(subscriptionId: string,
946
950
  export async function ensureSubscriptionForOverdraftProtection(subscriptionId: string, amount: string) {
947
951
  const subscription = await Subscription.findByPk(subscriptionId);
948
952
  if (!subscription) {
949
- throw new Error(`Subscription ${subscriptionId} not found when prepare overdraft protection`);
953
+ throw new Error(`Subscription ${subscriptionId} not found when prepare SubGuard`);
950
954
  }
951
-
955
+ // @ts-ignore
956
+ subscription.items = await expandSubscriptionItems(subscription.id);
952
957
  const paymentCurrency = await PaymentCurrency.findByPk(subscription.currency_id);
953
958
  if (!paymentCurrency) {
954
- throw new Error(`PaymentCurrency ${subscription.currency_id} not found when prepare overdraft protection`);
959
+ throw new Error(`PaymentCurrency ${subscription.currency_id} not found when prepare SubGuard`);
955
960
  }
956
961
 
957
962
  const paymentMethod = await PaymentMethod.findByPk(paymentCurrency.payment_method_id);
@@ -960,7 +965,7 @@ export async function ensureSubscriptionForOverdraftProtection(subscriptionId: s
960
965
  throw new Error(`Payment method not found for subscription ${subscriptionId}`);
961
966
  }
962
967
  if (paymentMethod.type !== 'arcblock') {
963
- throw new Error(`Payment method ${paymentMethod.type} not supported for overdraft protection`);
968
+ throw new Error(`Payment method ${paymentMethod.type} not supported for SubGuard`);
964
969
  }
965
970
 
966
971
  const customer = await Customer.findByPk(subscription.customer_id);
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
1
2
  import { isValid } from '@arcblock/did';
2
3
  import { Router } from 'express';
3
4
  import Joi from 'joi';
@@ -43,6 +44,7 @@ const schema = createListParamSchema<{
43
44
  ignore_zero?: boolean;
44
45
  include_staking?: boolean;
45
46
  include_return_staking?: boolean;
47
+ include_overdraft_protection?: boolean;
46
48
  include_recovered_from?: boolean;
47
49
  }>({
48
50
  status: Joi.string().empty(''),
@@ -53,15 +55,25 @@ const schema = createListParamSchema<{
53
55
  ignore_zero: Joi.boolean().empty(false),
54
56
  include_staking: Joi.boolean().empty(false),
55
57
  include_return_staking: Joi.boolean().empty(false),
58
+ include_overdraft_protection: Joi.boolean().default(true),
56
59
  include_recovered_from: Joi.boolean().empty(false),
57
60
  });
58
61
  router.get('/', authMine, async (req, res) => {
59
62
  // eslint-disable-next-line @typescript-eslint/naming-convention
60
- const { page, pageSize, livemode, status, ignore_zero, include_staking, include_return_staking, ...query } =
61
- await schema.validateAsync(req.query, {
62
- stripUnknown: false,
63
- allowUnknown: true,
64
- });
63
+ const {
64
+ page,
65
+ pageSize,
66
+ livemode,
67
+ status,
68
+ ignore_zero,
69
+ include_staking,
70
+ include_return_staking,
71
+ include_overdraft_protection = true,
72
+ ...query
73
+ } = await schema.validateAsync(req.query, {
74
+ stripUnknown: false,
75
+ allowUnknown: true,
76
+ });
65
77
  const where = getWhereFromKvQuery(query.q);
66
78
 
67
79
  if (status) {
@@ -107,7 +119,11 @@ router.get('/', authMine, async (req, res) => {
107
119
  // @ts-ignore
108
120
  where[key] = query[key];
109
121
  });
122
+
110
123
  const excludeBillingReasons = ['recharge'];
124
+ if (!include_overdraft_protection) {
125
+ excludeBillingReasons.push('stake_overdraft_protection');
126
+ }
111
127
  if (!!(include_staking && query.subscription_id) || !include_staking) {
112
128
  excludeBillingReasons.push('stake');
113
129
  }
@@ -1760,7 +1760,7 @@ router.get('/:id/cycle-amount', authPortal, async (req, res) => {
1760
1760
  const pastMaxAmount = await getPastInvoicesAmount(subscription.id, 'max');
1761
1761
 
1762
1762
  // return max amount
1763
- const nextAmount = new BN(result.amount === '0' ? result.minExpectedAmount : result.amount);
1763
+ const nextAmount = new BN(result.amount === '0' ? result.minExpectedAmount : result.amount).toString();
1764
1764
 
1765
1765
  const maxAmount = new BN(pastMaxAmount.amount).lte(new BN(nextAmount)) ? nextAmount : pastMaxAmount.amount;
1766
1766
 
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.17.1
17
+ version: 1.17.3
18
18
  logo: logo.png
19
19
  files:
20
20
  - dist
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payment-kit",
3
- "version": "1.17.1",
3
+ "version": "1.17.3",
4
4
  "scripts": {
5
5
  "dev": "blocklet dev --open",
6
6
  "eject": "vite eject",
@@ -44,29 +44,29 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@abtnode/cron": "^1.16.36",
47
- "@arcblock/did": "^1.18.165",
47
+ "@arcblock/did": "^1.18.166",
48
48
  "@arcblock/did-auth-storage-nedb": "^1.7.1",
49
49
  "@arcblock/did-connect": "^2.11.15",
50
- "@arcblock/did-util": "^1.18.165",
51
- "@arcblock/jwt": "^1.18.165",
50
+ "@arcblock/did-util": "^1.18.166",
51
+ "@arcblock/jwt": "^1.18.166",
52
52
  "@arcblock/ux": "^2.11.15",
53
- "@arcblock/validator": "^1.18.165",
53
+ "@arcblock/validator": "^1.18.166",
54
54
  "@blocklet/js-sdk": "^1.16.36",
55
55
  "@blocklet/logger": "^1.16.36",
56
- "@blocklet/payment-react": "1.17.1",
56
+ "@blocklet/payment-react": "1.17.3",
57
57
  "@blocklet/sdk": "^1.16.36",
58
58
  "@blocklet/ui-react": "^2.11.15",
59
- "@blocklet/uploader": "^0.1.60",
60
- "@blocklet/xss": "^0.1.17",
59
+ "@blocklet/uploader": "^0.1.62",
60
+ "@blocklet/xss": "^0.1.19",
61
61
  "@mui/icons-material": "^5.16.6",
62
62
  "@mui/lab": "^5.0.0-alpha.173",
63
63
  "@mui/material": "^5.16.6",
64
64
  "@mui/system": "^5.16.6",
65
- "@ocap/asset": "^1.18.165",
66
- "@ocap/client": "^1.18.165",
67
- "@ocap/mcrypto": "^1.18.165",
68
- "@ocap/util": "^1.18.165",
69
- "@ocap/wallet": "^1.18.165",
65
+ "@ocap/asset": "^1.18.166",
66
+ "@ocap/client": "^1.18.166",
67
+ "@ocap/mcrypto": "^1.18.166",
68
+ "@ocap/util": "^1.18.166",
69
+ "@ocap/wallet": "^1.18.166",
70
70
  "@stripe/react-stripe-js": "^2.7.3",
71
71
  "@stripe/stripe-js": "^2.4.0",
72
72
  "ahooks": "^3.8.0",
@@ -120,7 +120,7 @@
120
120
  "devDependencies": {
121
121
  "@abtnode/types": "^1.16.36",
122
122
  "@arcblock/eslint-config-ts": "^0.3.3",
123
- "@blocklet/payment-types": "1.17.1",
123
+ "@blocklet/payment-types": "1.17.3",
124
124
  "@types/cookie-parser": "^1.4.7",
125
125
  "@types/cors": "^2.8.17",
126
126
  "@types/debug": "^4.1.12",
@@ -166,5 +166,5 @@
166
166
  "parser": "typescript"
167
167
  }
168
168
  },
169
- "gitHead": "fe7302197bbf98d5490f8bc0d6738d9c51c53646"
169
+ "gitHead": "bc8adef7ff5a032048eef64dc1753bcee88acb98"
170
170
  }
@@ -16,6 +16,7 @@ import {
16
16
  FormControl,
17
17
  RadioGroup,
18
18
  Radio,
19
+ Link,
19
20
  } from '@mui/material';
20
21
  import Dialog from '@arcblock/ux/lib/Dialog';
21
22
  import { EventHandler, useState } from 'react';
@@ -23,7 +24,10 @@ import { api, formatAmountPrecisionLimit, Switch, useMobile } from '@blocklet/pa
23
24
  import { useRequest } from 'ahooks';
24
25
  import { BN, fromTokenToUnit, fromUnitToToken } from '@ocap/util';
25
26
  import type { TPaymentCurrency, TSubscriptionExpanded } from '@blocklet/payment-types';
27
+ import { joinURL } from 'ufo';
28
+ import { OpenInNewOutlined } from '@mui/icons-material';
26
29
  import Currency from '../currency';
30
+ import { formatSmartDuration, TimeUnit } from '../../libs/dayjs';
27
31
 
28
32
  const fetchCycleAmount = (
29
33
  subscriptionId: string,
@@ -58,7 +62,8 @@ type OverdraftProtectionDialogProps = {
58
62
  onSave: (data: { enabled: boolean; additionalCount?: number; returnRemaining?: boolean }) => Promise<void>;
59
63
  onCancel: EventHandler<any>;
60
64
  open: boolean;
61
- paymentAddress?: string;
65
+ stakingAddress?: string;
66
+ payerAddress?: string;
62
67
  currency: {
63
68
  symbol: string;
64
69
  logo: string;
@@ -66,10 +71,16 @@ type OverdraftProtectionDialogProps = {
66
71
  maximum_precision?: number;
67
72
  };
68
73
  subscription: TSubscriptionExpanded;
74
+ initValues?: {
75
+ enabled: boolean;
76
+ return_stake: boolean;
77
+ } | null;
69
78
  };
70
79
 
71
80
  OverdraftProtectionDialog.defaultProps = {
72
- paymentAddress: '',
81
+ payerAddress: '',
82
+ stakingAddress: '',
83
+ initValues: null,
73
84
  };
74
85
 
75
86
  export default function OverdraftProtectionDialog({
@@ -78,14 +89,16 @@ export default function OverdraftProtectionDialog({
78
89
  onSave,
79
90
  onCancel,
80
91
  open,
81
- paymentAddress,
92
+ stakingAddress,
93
+ payerAddress,
82
94
  currency,
83
95
  subscription,
96
+ initValues,
84
97
  }: OverdraftProtectionDialogProps) {
85
98
  const { t, locale } = useLocaleContext();
86
99
  const { isMobile } = useMobile();
87
100
  const [customAmount, setCustomAmount] = useState(false);
88
- const [presetAmounts, setPresetAmounts] = useState<{ amount: string; cycles: number }[]>([]);
101
+ const [presetAmounts, setPresetAmounts] = useState<{ amount: string; cycles: number; label: string }[]>([]);
89
102
 
90
103
  const {
91
104
  data: cycleAmount = {
@@ -100,10 +113,47 @@ export default function OverdraftProtectionDialog({
100
113
  {
101
114
  refreshDeps: [subscription.id],
102
115
  onSuccess: (data) => {
103
- const presets = [1, 2, 5, 10];
116
+ const presets = (() => {
117
+ const { interval, interval_count: intervalCount } = subscription.pending_invoice_item_interval;
118
+
119
+ switch (interval) {
120
+ case 'hour':
121
+ return [
122
+ { cycles: Math.ceil(24 / intervalCount), label: '1 day' },
123
+ { cycles: Math.ceil((24 * 7) / intervalCount), label: '1 week' },
124
+ { cycles: Math.ceil((24 * 30) / intervalCount), label: '1 month' },
125
+ { cycles: Math.ceil((24 * 90) / intervalCount), label: '3 months' },
126
+ { cycles: Math.ceil((24 * 180) / intervalCount), label: '6 months' },
127
+ ];
128
+ case 'day':
129
+ return [
130
+ { cycles: Math.ceil(7 / intervalCount), label: '1 week' },
131
+ { cycles: Math.ceil(30 / intervalCount), label: '1 month' },
132
+ { cycles: Math.ceil(90 / intervalCount), label: '3 months' },
133
+ { cycles: Math.ceil(180 / intervalCount), label: '6 months' },
134
+ { cycles: Math.ceil(365 / intervalCount), label: '1 year' },
135
+ ];
136
+ default:
137
+ return [
138
+ { cycles: 1, label: '1x' },
139
+ { cycles: 2, label: '2x' },
140
+ { cycles: 3, label: '6x' },
141
+ { cycles: 6, label: '6x' },
142
+ { cycles: 12, label: '12x' },
143
+ ];
144
+ }
145
+ })();
146
+
104
147
  const getCycleAmount = (cycles: number) =>
105
148
  fromUnitToToken(new BN(data.amount).mul(new BN(cycles)).toString(), data?.currency?.decimal);
106
- setPresetAmounts(presets.map((cycles) => ({ amount: getCycleAmount(cycles), cycles })));
149
+
150
+ setPresetAmounts(
151
+ presets.map(({ cycles, label }) => ({
152
+ amount: getCycleAmount(cycles),
153
+ cycles,
154
+ label,
155
+ }))
156
+ );
107
157
  },
108
158
  }
109
159
  );
@@ -117,6 +167,7 @@ export default function OverdraftProtectionDialog({
117
167
  enabled: !!subscription.overdraft_protection?.enabled,
118
168
  return_stake: false,
119
169
  amount: '0',
170
+ ...(initValues || {}),
120
171
  },
121
172
  mode: 'onChange',
122
173
  });
@@ -146,16 +197,28 @@ export default function OverdraftProtectionDialog({
146
197
  const totalIntervals = cycles * intervalCount;
147
198
  const availableUnitKeys = ['hour', 'day', 'week', 'month', 'year'];
148
199
 
149
- const unitKey = availableUnitKeys.includes(interval)
150
- ? `common.${interval}${totalIntervals > 1 ? 's' : ''}`
151
- : 'customer.overdraftProtection.intervals';
152
-
153
- return t('customer.overdraftProtection.estimatedDuration', {
154
- duration: totalIntervals,
155
- unit: t(unitKey).toLowerCase(),
200
+ if (!availableUnitKeys.includes(interval)) {
201
+ return t('customer.overdraftProtection.estimatedDuration', {
202
+ duration: totalIntervals,
203
+ unit: t('customer.overdraftProtection.intervals').toLowerCase(),
204
+ });
205
+ }
206
+ return t('common.estimatedDuration', {
207
+ duration: formatSmartDuration(totalIntervals, interval as TimeUnit, {
208
+ t,
209
+ }),
156
210
  });
157
211
  };
158
212
 
213
+ const getStakingAddressURL = () => {
214
+ return joinURL(
215
+ subscription.paymentMethod?.settings.arcblock?.explorer_host as string,
216
+ '/stakes',
217
+ stakingAddress as string,
218
+ '/tokens'
219
+ );
220
+ };
221
+
159
222
  return (
160
223
  <Dialog
161
224
  open={open}
@@ -207,16 +270,67 @@ export default function OverdraftProtectionDialog({
207
270
 
208
271
  {isEnabled ? (
209
272
  <Stack gap={1} sx={{ mt: '-8px' }}>
210
- {paymentAddress && (
211
- <Stack direction="row" alignItems="center" gap={isMobile ? 1 : 2} flexWrap="wrap">
273
+ {payerAddress && (
274
+ <Stack
275
+ sx={
276
+ isMobile
277
+ ? {
278
+ flexDirection: 'column',
279
+ gap: 1,
280
+ }
281
+ : {
282
+ flexDirection: 'row',
283
+ alignItems: 'center',
284
+ gap: 2,
285
+ }
286
+ }>
212
287
  <Typography variant="subtitle2" color="text.secondary">
213
- {t('customer.overdraftProtection.address')}
288
+ {t('customer.overdraftProtection.payerAddress')}
214
289
  </Typography>
215
290
  <Typography variant="body2" sx={{ wordBreak: 'break-all', fontFamily: 'monospace', fontWeight: '700' }}>
216
- {paymentAddress}
291
+ {payerAddress}
217
292
  </Typography>
218
293
  </Stack>
219
294
  )}
295
+
296
+ {stakingAddress && (
297
+ <Stack
298
+ sx={
299
+ isMobile
300
+ ? {
301
+ flexDirection: 'column',
302
+ gap: 1,
303
+ }
304
+ : {
305
+ flexDirection: 'row',
306
+ alignItems: 'center',
307
+ gap: 2,
308
+ }
309
+ }>
310
+ <Typography variant="subtitle2" color="text.secondary">
311
+ {t('customer.overdraftProtection.stakingAddress')}
312
+ </Typography>
313
+ <Link
314
+ href={getStakingAddressURL()}
315
+ target="_blank"
316
+ rel="noopener noreferrer"
317
+ sx={{
318
+ wordBreak: 'break-all',
319
+ fontFamily: 'monospace',
320
+ fontWeight: '700',
321
+ textDecoration: 'none',
322
+ color: 'text.link',
323
+ display: 'flex',
324
+ flexWrap: 'wrap',
325
+ alignItems: 'center',
326
+ gap: 1,
327
+ }}>
328
+ {stakingAddress}
329
+ {!isMobile && <OpenInNewOutlined fontSize="small" />}
330
+ </Link>
331
+ </Stack>
332
+ )}
333
+
220
334
  <Typography variant="body2" color="text.secondary">
221
335
  {(() => {
222
336
  if (Number(dueAmount) > 0 && !value.enabled) {
@@ -346,7 +460,7 @@ export default function OverdraftProtectionDialog({
346
460
  </FormControl>
347
461
  </Stack>
348
462
  )}
349
- {amount && Number(amount) > 0 && !methods.formState.errors.amount && (
463
+ {amount && Number(amount) > 0 && Number(estimateAmount) > 0 && !methods.formState.errors.amount && (
350
464
  <Typography variant="body2" sx={{ color: 'text.lighter', mt: '8px !important' }} fontSize={12}>
351
465
  {t('customer.overdraftProtection.total', {
352
466
  total: safeAdd(currency, amount, availableAmount),