@instadapp/avocado-base 0.0.0-dev.f24809a → 0.0.0-dev.f307ae7

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 (95) hide show
  1. package/.github/workflows/npm-publish-dev.yml +2 -5
  2. package/.vscode/settings.json +67 -0
  3. package/abi/avoFactoryProxy.json +1 -1
  4. package/abi/forwarder.json +1252 -148
  5. package/abi/multisigAgnosticForwarder.json +937 -0
  6. package/abi/multisigForwarder.json +697 -0
  7. package/app.vue +9 -2
  8. package/assets/images/icons/arrow-left.svg +5 -0
  9. package/assets/images/icons/arrow-right.svg +5 -0
  10. package/assets/images/icons/avocado.svg +4 -0
  11. package/assets/images/icons/bridge-2.svg +3 -0
  12. package/assets/images/icons/bridge.svg +7 -0
  13. package/assets/images/icons/calendar.svg +8 -0
  14. package/assets/images/icons/change-threshold.svg +4 -0
  15. package/assets/images/icons/check-circle.svg +4 -0
  16. package/assets/images/icons/check.svg +3 -0
  17. package/assets/images/icons/chevron-down.svg +4 -0
  18. package/assets/images/icons/clipboard.svg +7 -0
  19. package/assets/images/icons/clock-circle.svg +5 -0
  20. package/assets/images/icons/copy.svg +12 -0
  21. package/assets/images/icons/cross-transfer.svg +7 -0
  22. package/assets/images/icons/dapp.svg +4 -0
  23. package/assets/images/icons/deploy.svg +12 -0
  24. package/assets/images/icons/error-circle.svg +6 -0
  25. package/assets/images/icons/exclamation-circle.svg +13 -0
  26. package/assets/images/icons/exclamation-octagon.svg +13 -0
  27. package/assets/images/icons/exclamation-triangle.svg +5 -0
  28. package/assets/images/icons/external-link.svg +6 -0
  29. package/assets/images/icons/eye.svg +4 -0
  30. package/assets/images/icons/flowers.svg +8 -0
  31. package/assets/images/icons/gas-emoji.svg +193 -0
  32. package/assets/images/icons/gas.svg +14 -0
  33. package/assets/images/icons/gift.svg +153 -0
  34. package/assets/images/icons/globe.svg +110 -0
  35. package/assets/images/icons/hamburger.svg +6 -0
  36. package/assets/images/icons/hammer.svg +5 -0
  37. package/assets/images/icons/info-2.svg +12 -0
  38. package/assets/images/icons/instadapp-pro.svg +4 -0
  39. package/assets/images/icons/logout.svg +3 -0
  40. package/assets/images/icons/moon.svg +3 -0
  41. package/assets/images/icons/multi-send.svg +7 -0
  42. package/assets/images/icons/network.svg +13 -0
  43. package/assets/images/icons/options.svg +5 -0
  44. package/assets/images/icons/permit-sign.svg +11 -0
  45. package/assets/images/icons/plus-circle.svg +6 -0
  46. package/assets/images/icons/plus.svg +5 -0
  47. package/assets/images/icons/power-off-bg.svg +24 -0
  48. package/assets/images/icons/power-off.svg +19 -0
  49. package/assets/images/icons/power-on.svg +19 -0
  50. package/assets/images/icons/qr.svg +20 -0
  51. package/assets/images/icons/question-circle.svg +14 -0
  52. package/assets/images/icons/refresh.svg +6 -0
  53. package/assets/images/icons/reject-proposal.svg +6 -0
  54. package/assets/images/icons/search.svg +12 -0
  55. package/assets/images/icons/stars.svg +4 -0
  56. package/assets/images/icons/sun.svg +3 -0
  57. package/assets/images/icons/transfer.svg +5 -0
  58. package/assets/images/icons/trash-2.svg +8 -0
  59. package/assets/images/icons/upgrade.svg +4 -0
  60. package/assets/images/icons/wave.svg +214 -0
  61. package/assets/images/icons/x.svg +5 -0
  62. package/components/ActionLogo.vue +42 -0
  63. package/components/ActionMetadata.vue +88 -0
  64. package/components/Address.vue +74 -0
  65. package/components/AuthorityAvatar.vue +39 -0
  66. package/components/ChainLogo.vue +18 -563
  67. package/components/CopyClipboard.vue +42 -0
  68. package/components/metadata/Bridge.vue +58 -0
  69. package/components/metadata/CrossTransfer.vue +76 -0
  70. package/components/metadata/GasTopup.vue +38 -0
  71. package/components/metadata/Permit2.vue +41 -0
  72. package/components/metadata/Signers.vue +19 -0
  73. package/components/metadata/Swap.vue +66 -0
  74. package/components/metadata/Transfer.vue +49 -0
  75. package/components.d.ts +13 -0
  76. package/contracts/Forwarder.ts +856 -2
  77. package/contracts/MultisigAgnosticForwarder.ts +1423 -0
  78. package/contracts/MultisigForwarder.ts +859 -0
  79. package/contracts/factories/Forwarder__factory.ts +816 -16
  80. package/contracts/factories/MultisigAgnosticForwarder__factory.ts +2135 -0
  81. package/contracts/factories/MultisigForwarder__factory.ts +721 -0
  82. package/contracts/factories/index.ts +2 -0
  83. package/contracts/index.ts +4 -0
  84. package/eslint.config.mjs +34 -0
  85. package/nuxt.config.ts +27 -2
  86. package/package.json +17 -12
  87. package/server/utils/index.ts +4 -4
  88. package/utils/avocado.ts +18 -16
  89. package/utils/bignumber.ts +60 -29
  90. package/utils/formatter.ts +63 -26
  91. package/utils/helper.ts +39 -28
  92. package/utils/metadata.ts +582 -251
  93. package/utils/network.ts +591 -173
  94. package/utils/services.ts +19 -0
  95. package/utils/utils.d.ts +147 -98
@@ -6,9 +6,13 @@ export type { BalanceResolver } from "./BalanceResolver";
6
6
  export type { Erc20 } from "./Erc20";
7
7
  export type { Forwarder } from "./Forwarder";
8
8
  export type { GaslessWallet } from "./GaslessWallet";
9
+ export type { MultisigAgnosticForwarder } from "./MultisigAgnosticForwarder";
10
+ export type { MultisigForwarder } from "./MultisigForwarder";
9
11
  export * as factories from "./factories";
10
12
  export { AvoFactoryProxy__factory } from "./factories/AvoFactoryProxy__factory";
11
13
  export { BalanceResolver__factory } from "./factories/BalanceResolver__factory";
12
14
  export { Erc20__factory } from "./factories/Erc20__factory";
13
15
  export { Forwarder__factory } from "./factories/Forwarder__factory";
14
16
  export { GaslessWallet__factory } from "./factories/GaslessWallet__factory";
17
+ export { MultisigAgnosticForwarder__factory } from "./factories/MultisigAgnosticForwarder__factory";
18
+ export { MultisigForwarder__factory } from "./factories/MultisigForwarder__factory";
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+ import antfu from '@antfu/eslint-config'
3
+ import withNuxt from './.nuxt/eslint.config.mjs'
4
+
5
+ export default withNuxt(
6
+ antfu({
7
+ ignores: [
8
+ '*.png',
9
+ '*.ico',
10
+ '*.toml',
11
+ '*.yml',
12
+ '.github/',
13
+ 'deployments/',
14
+ '*.patch',
15
+ '*.txt',
16
+ 'Dockerfile',
17
+ 'public/',
18
+ 'contracts/',
19
+ 'yarn.lock',
20
+ ],
21
+ yaml: false,
22
+ rules: {
23
+ 'style/max-statements-per-line': 'off',
24
+ 'max-statements-per-line': 'off',
25
+ '@stylistic/max-statements-per-line': 'off',
26
+ 'vue/return-in-computed-property': 'off',
27
+ 'no-console': 'off',
28
+ 'ts/ban-ts-comment': 'off',
29
+ 'vue/prop-name-casing': 'off',
30
+ 'node/prefer-global/process': 'off',
31
+ 'eqeqeq': 'off',
32
+ },
33
+ }),
34
+ )
package/nuxt.config.ts CHANGED
@@ -1,4 +1,29 @@
1
1
  // https://nuxt.com/docs/api/configuration/nuxt-config
2
+ // import ViteComponents from "unplugin-vue-components/vite";
3
+
2
4
  export default defineNuxtConfig({
3
- modules: ["@nuxtjs/tailwindcss"],
4
- });
5
+ modules: ['@nuxtjs/tailwindcss', 'nuxt-svgo', '@vueuse/nuxt', '@nuxt/eslint'],
6
+
7
+ svgo: {
8
+ defaultImport: 'component',
9
+ autoImportPath: './assets/images/icons',
10
+ svgoConfig: {
11
+ plugins: ['prefixIds'],
12
+ },
13
+ },
14
+
15
+ // vite: {
16
+ // plugins: [
17
+ // ViteComponents({
18
+ // dts: true,
19
+ // }),
20
+ // ],
21
+ // },
22
+ eslint: {
23
+ config: {
24
+ standalone: false,
25
+ },
26
+ },
27
+
28
+ compatibilityDate: '2024-09-18',
29
+ })
package/package.json CHANGED
@@ -1,27 +1,32 @@
1
1
  {
2
2
  "name": "@instadapp/avocado-base",
3
- "version": "0.0.0-dev.f24809a",
4
3
  "type": "module",
4
+ "version": "0.0.0-dev.f307ae7",
5
5
  "main": "./nuxt.config.ts",
6
6
  "types": "global.d.ts",
7
+ "engines": {
8
+ "node": ">=v20.16.0"
9
+ },
7
10
  "scripts": {
8
11
  "build": "nuxt build",
9
12
  "dev": "nuxt dev",
10
13
  "generate": "nuxt generate",
11
14
  "preview": "nuxt preview",
12
- "generate:contracts": "rimraf contracts && typechain --target=ethers-v5 'abi/*.json' --out-dir 'contracts'"
13
- },
14
- "devDependencies": {
15
- "@instadapp/avocado": "^0.1.10",
16
- "@instadapp/avocado-dev": "npm:@instadapp/avocado@dev",
17
- "@nuxtjs/tailwindcss": "^6.6.5",
18
- "@typechain/ethers-v5": "^10.2.0",
19
- "nuxt": "^3.3.3",
20
- "rimraf": "^3.0.2",
21
- "typechain": "^8.1.1"
15
+ "typecheck": "nuxi typecheck"
22
16
  },
23
17
  "dependencies": {
18
+ "@antfu/eslint-config": "^3.6.2",
19
+ "@vueuse/nuxt": "^10.2.0",
24
20
  "bignumber.js": "^9.1.1",
25
- "ethers": "^5.7.2"
21
+ "ethers": "^5.7.2",
22
+ "viem": "^2.21.54",
23
+ "xxhashjs": "^0.2.2"
24
+ },
25
+ "devDependencies": {
26
+ "@nuxt/eslint": "^0.5.7",
27
+ "@nuxtjs/tailwindcss": "^6.12.1",
28
+ "nuxt": "3.13.2",
29
+ "nuxt-svgo": "^4.0.6",
30
+ "vue-tippy": "^6.0.0"
26
31
  }
27
32
  }
@@ -1,4 +1,4 @@
1
- export * from "../../utils/avocado";
2
- export * from "../../utils/network";
3
- export * from "../../utils/bignumber";
4
- export * from "../../utils/formatter";
1
+ export * from '../../utils/avocado'
2
+ export * from '../../utils/bignumber'
3
+ export * from '../../utils/formatter'
4
+ export * from '../../utils/network'
package/utils/avocado.ts CHANGED
@@ -1,22 +1,24 @@
1
- export const AVO_PROD_CHAIN_ID = 634;
2
- export const AVO_PROD_CHAIN_NAME = "Avocado";
1
+ export const AVO_PROD_CHAIN_ID = 634
2
+ export const AVO_PROD_CHAIN_NAME = 'Avocado'
3
3
 
4
- export const AVO_STAGING_CHAIN_ID = 63400;
5
- export const AVO_STAGING_CHAIN_NAME = "Avocado Testnet";
4
+ export const AVO_STAGING_CHAIN_ID = 63400
5
+ export const AVO_STAGING_CHAIN_NAME = 'Avocado Testnet'
6
6
 
7
- export const AVO_PROD_EXPLORER_URL = "https://avoscan.co";
8
- export const AVO_STAGING_EXPLORER_URL = "https://explorer.avocado.instad.app";
7
+ export const AVO_PROD_EXPLORER_URL = 'https://avoscan.co'
8
+ export const AVO_STAGING_EXPLORER_URL = 'https://explorer.avocado.instad.app'
9
9
 
10
- export const AVO_PROD_FORWARDER_ADDR =
11
- "0x375F6B0CD12b34Dc28e34C26853a37012C24dDE5";
12
- export const AVO_STAGING_FORWARDER_ADDR =
13
- "0x8CDaAC0371a443985c6Faf07938dDAa7A5818674";
10
+ export const AVO_PROD_FORWARDER_ADDR
11
+ = '0x375F6B0CD12b34Dc28e34C26853a37012C24dDE5'
12
+ export const AVO_STAGING_FORWARDER_ADDR
13
+ = '0x8CDaAC0371a443985c6Faf07938dDAa7A5818674'
14
14
 
15
- export const AVO_PROD_DEPOSIT_ADDRESS =
16
- "0xE8385fB3A5F15dED06EB5E20E5A81BF43115eb8E";
17
- export const AVO_STAGING_DEPOSIT_ADDRESS =
18
- "0x853e991d800Dfd6bC1F83AED3310e859482323dc";
15
+ export const AVO_PROD_DEPOSIT_ADDRESS
16
+ = '0xE8385fB3A5F15dED06EB5E20E5A81BF43115eb8E'
17
+ export const AVO_STAGING_DEPOSIT_ADDRESS
18
+ = '0x853e991d800Dfd6bC1F83AED3310e859482323dc'
19
19
 
20
- export const AVO_PROD_RPC_URL = "https://rpc.avocado.instadapp.io";
20
+ export const AVO_PROD_RPC_URL = 'https://rpc.avocado.instadapp.io'
21
21
 
22
- export const AVO_STAGING_RPC_URL = "https://rpc.avocado.instad.app";
22
+ export const AVO_STAGING_RPC_URL = 'https://rpc.avocado.instad.app'
23
+
24
+ export const blockQueryURL = 'https://blockquery.instadapp.io'
@@ -1,31 +1,62 @@
1
- import { BigNumber } from "bignumber.js";
2
- import { BigNumber as BN } from "ethers";
1
+ import { BigNumber } from 'bignumber.js'
2
+ import { BigNumber as BN } from 'ethers'
3
3
 
4
- export const toBN = (value: BigNumber.Value | BN) =>
5
- new BigNumber(BN.isBigNumber(value) ? value.toString() : value);
6
- export const isZero = (value: BigNumber.Value | BN) => toBN(value).isZero();
7
- export const times = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
8
- toBN(a).times(toBN(b));
9
- export const minus = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
10
- toBN(a).minus(toBN(b));
11
- export const plus = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
12
- toBN(a).plus(toBN(b));
13
- export const lte = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
14
- toBN(a).lte(toBN(b));
15
- export const gte = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
16
- toBN(a).gte(toBN(b));
17
- export const div = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
18
- toBN(a).div(toBN(b));
19
- export const lt = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
20
- toBN(a).lt(toBN(b));
21
- export const gt = (a: BigNumber.Value | BN, b: BigNumber.Value | BN) =>
22
- toBN(a).gt(toBN(b));
23
- export const ensureValue = (value: any) => {
24
- if (!value) return toBN("0");
25
- if (toBN(value).isNaN()) return toBN("0");
4
+ type CombinedBigNumber = BigNumber | string | number
26
5
 
27
- return toBN(value);
28
- };
29
- export const max = (...args: BigNumber.Value[]) => {
30
- return BigNumber.max(...args);
31
- };
6
+ export function toBN(value: BigNumber.Value | BN) {
7
+ return new BigNumber(BN.isBigNumber(value) ? value.toString() : value)
8
+ }
9
+ export const isZero = (value: BigNumber.Value | BN) => toBN(value).isZero()
10
+ export function times(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
11
+ return toBN(a).times(toBN(b))
12
+ }
13
+ export function minus(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
14
+ return toBN(a).minus(toBN(b))
15
+ }
16
+ export function plus(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
17
+ return toBN(a).plus(toBN(b))
18
+ }
19
+ export function lte(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
20
+ return toBN(a).lte(toBN(b))
21
+ }
22
+ export function gte(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
23
+ return toBN(a).gte(toBN(b))
24
+ }
25
+ export function div(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
26
+ return toBN(a).div(toBN(b))
27
+ }
28
+ export function lt(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
29
+ return toBN(a).lt(toBN(b))
30
+ }
31
+ export function gt(a: BigNumber.Value | BN, b: BigNumber.Value | BN) {
32
+ return toBN(a).gt(toBN(b))
33
+ }
34
+ export function ensureValue(value: any) {
35
+ if (!value)
36
+ return toBN('0')
37
+ if (toBN(value).isNaN())
38
+ return toBN('0')
39
+
40
+ return toBN(value)
41
+ }
42
+ export function max(...args: BigNumber.Value[]) {
43
+ return BigNumber.max(...args)
44
+ }
45
+
46
+ export function pow(value: CombinedBigNumber, exponent: string | number) {
47
+ return toBN(value).pow(toBN(exponent))
48
+ }
49
+
50
+ export function toWei(val: CombinedBigNumber, decimals: number): string {
51
+ const num = toBN(val)
52
+ const multiplier = pow(10, decimals)
53
+ return times(num, multiplier).toFixed(0)
54
+ }
55
+
56
+ export function fromWei(val: CombinedBigNumber, decimal = 18) {
57
+ return toBN(val).div(new BigNumber(10).pow(decimal))
58
+ }
59
+
60
+ export function abs(value: CombinedBigNumber) {
61
+ return toBN(value).abs()
62
+ }
@@ -1,51 +1,88 @@
1
1
  export function formatPercent(
2
- value: number,
2
+ value?: number | string,
3
3
  fractionDigits = 2,
4
- maxValue = null
4
+ maxValue = null,
5
5
  ) {
6
- if (isZero(value)) return "0.00%";
6
+ if (!value || isZero(value))
7
+ return '0.00%'
7
8
 
8
- if (maxValue && gt(times(value, "100"), maxValue)) return `>${maxValue}%`;
9
+ const valueAsNumber = toBN(value).toNumber()
9
10
 
10
- const formatter = new Intl.NumberFormat("en-US", {
11
- style: "percent",
11
+ if (maxValue && gt(times(valueAsNumber, '100'), maxValue))
12
+ return `>${maxValue}%`
13
+
14
+ const formatter = new Intl.NumberFormat('en-US', {
15
+ style: 'percent',
12
16
  minimumFractionDigits: fractionDigits,
13
17
  maximumFractionDigits: fractionDigits,
14
- });
18
+ })
15
19
 
16
- return formatter.format(value);
20
+ return formatter.format(valueAsNumber)
17
21
  }
18
22
 
19
- export function shortenHash(hash: string, length: number = 4) {
20
- if (!hash) return;
21
- if (hash.length < 12) return hash;
22
- const beginningChars = hash.startsWith("0x") ? length + 2 : length;
23
- const shortened =
24
- hash.substr(0, beginningChars) + "..." + hash.substr(-length);
25
- return shortened;
23
+ export function shortenHash(hash: string | `0x${string}`, length: number = 4) {
24
+ if (!hash)
25
+ return
26
+ if (hash.length < 12)
27
+ return hash
28
+ const beginningChars = hash.startsWith('0x') ? length + 2 : length
29
+ const shortened
30
+ = `${hash.substr(0, beginningChars)}...${hash.substr(-length)}`
31
+ return shortened
26
32
  }
27
33
 
28
34
  export function formatUsd(value: any, fractionDigits = 2) {
29
- const formatter = new Intl.NumberFormat("en-US", {
30
- style: "currency",
31
- currency: "USD",
35
+ const formatter = new Intl.NumberFormat('en-US', {
36
+ style: 'currency',
37
+ currency: 'USD',
32
38
  minimumFractionDigits: fractionDigits,
33
39
  maximumFractionDigits: fractionDigits,
34
- });
40
+ })
35
41
 
36
- return formatter.format(value);
42
+ return formatter.format(value)
37
43
  }
38
44
 
39
45
  export function signedNumber(numb: string | number) {
40
- return new Intl.NumberFormat("en-US", {
41
- signDisplay: "exceptZero",
42
- }).format(toBN(numb).toNumber());
46
+ return new Intl.NumberFormat('en-US', {
47
+ signDisplay: 'exceptZero',
48
+ }).format(toBN(numb).toNumber())
43
49
  }
44
50
 
45
- export function formatDecimal(value: string | number, decimalPlaces = 5) {
51
+ export function formatDecimal(value: string | number, fractionDigits?: number) {
46
52
  if (!value) {
47
- value = "0";
53
+ value = '0'
54
+ }
55
+ if (lt(value, '0.0001') && gt(value, '0')) {
56
+ return '< 0.0001'
48
57
  }
58
+ else {
59
+ const num = toBN(value)
60
+ let decimals
61
+
62
+ if (num.lt(1)) {
63
+ decimals = 4
64
+ }
65
+ else if (num.lt(10)) {
66
+ decimals = 6
67
+ }
68
+ else if (num.lt(100)) {
69
+ decimals = 4
70
+ }
71
+ else if (num.lt(1000)) {
72
+ decimals = 3
73
+ }
74
+ else if (num.lt(10000)) {
75
+ decimals = 2
76
+ }
77
+ else if (num.lt(100000)) {
78
+ decimals = 1
79
+ }
80
+ else {
81
+ decimals = 0
82
+ }
49
83
 
50
- return toBN(value).decimalPlaces(decimalPlaces).toFormat();
84
+ const formattedNumber = num.toFixed(fractionDigits || decimals)
85
+
86
+ return toBN(formattedNumber).toFormat()
87
+ }
51
88
  }
package/utils/helper.ts CHANGED
@@ -1,54 +1,65 @@
1
- export const indexSorter = (aIndex: number, bIndex: number) => {
1
+ export function indexSorter(aIndex: number, bIndex: number) {
2
2
  if (aIndex === -1 && bIndex === -1) {
3
- return 0; // fallback to other sorting criteria
4
- } else if (aIndex === -1) {
5
- return 1; // b comes first if a is not in the priority list
6
- } else if (bIndex === -1) {
7
- return -1; // a comes first if b is not in the priority list
8
- } else {
9
- return aIndex - bIndex; // sort by the index in the priority list
3
+ return 0 // fallback to other sorting criteria
10
4
  }
11
- };
5
+ else if (aIndex === -1) {
6
+ return 1 // b comes first if a is not in the priority list
7
+ }
8
+ else if (bIndex === -1) {
9
+ return -1 // a comes first if b is not in the priority list
10
+ }
11
+ else {
12
+ return aIndex - bIndex // sort by the index in the priority list
13
+ }
14
+ }
12
15
 
13
16
  export function sortByMany<T>(
14
17
  items: T[],
15
- callback: ((a: T, b: T) => number)[]
18
+ callback: ((a: T, b: T) => number)[],
16
19
  ) {
17
- return items.sort(function (a, b) {
18
- var result = 0;
19
- for (var i = 0; i < callback.length; i++) {
20
- var func = callback[i];
21
- result = func(a, b);
20
+ return items.sort((a, b) => {
21
+ let result = 0
22
+ for (let i = 0; i < callback.length; i++) {
23
+ const func = callback[i]
24
+ result = func(a, b)
22
25
  if (result !== 0) {
23
- break;
26
+ break
24
27
  }
25
28
  }
26
- return result;
27
- });
29
+ return result
30
+ })
28
31
  }
29
32
 
30
33
  export function cloneDeep<T>(value: T): T {
31
- return JSON.parse(JSON.stringify(value));
34
+ return JSON.parse(JSON.stringify(value))
32
35
  }
33
36
 
34
37
  export function filterArray(array: any, filters: any) {
35
- const filterKeys = Object.keys(filters);
38
+ const filterKeys = Object.keys(filters)
36
39
  return array.filter((item: any) => {
37
40
  // validates all filter criteria
38
41
  return filterKeys.every((key) => {
39
42
  // ignores non-function predicates
40
- if (typeof filters[key] !== "function") return true;
41
- return filters[key](item[key], item);
42
- });
43
- });
43
+ if (typeof filters[key] !== 'function')
44
+ return true
45
+ return filters[key](item[key], item)
46
+ })
47
+ })
44
48
  }
45
49
 
46
50
  export function onImageError(this: HTMLImageElement) {
47
- const parentElement = this.parentElement;
48
- this.onerror = null;
49
- this.remove();
51
+ const parentElement = this.parentElement
52
+ this.onerror = null
53
+ this.remove()
50
54
 
51
55
  if (parentElement) {
52
- parentElement.classList.add("bg-gray-300");
56
+ parentElement.classList.add('bg-gray-300')
53
57
  }
54
58
  }
59
+
60
+ export function formatMultipleAddresses(addresses: string[], shorten = true) {
61
+ const formatter = new Intl.ListFormat('en', { style: 'long', type: 'conjunction' })
62
+ const formattedString = formatter.format(addresses.map(i => shorten ? shortenHash(i) || '' : i))
63
+
64
+ return formattedString
65
+ }