eco-solver 0.0.1-security → 1.5.2
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.
Potentially problematic release.
This version of eco-solver might be problematic. Click here for more details.
- package/.eslintignore +8 -0
- package/.eslintrc.js +24 -0
- package/.github/workflows/ci.yaml +38 -0
- package/.nvmrc +1 -0
- package/.prettierignore +3 -0
- package/.prettierrc +8 -0
- package/Dockerfile +11 -0
- package/LICENSE +21 -0
- package/README.md +29 -5
- package/config/default.ts +135 -0
- package/config/development.ts +95 -0
- package/config/preproduction.ts +17 -0
- package/config/production.ts +17 -0
- package/config/staging.ts +17 -0
- package/config/test.ts +7 -0
- package/index.js +43 -0
- package/jest.config.ts +14 -0
- package/nest-cli.json +8 -0
- package/package.json +117 -6
- package/src/api/api.module.ts +27 -0
- package/src/api/balance.controller.ts +41 -0
- package/src/api/quote.controller.ts +54 -0
- package/src/api/tests/balance.controller.spec.ts +113 -0
- package/src/api/tests/quote.controller.spec.ts +83 -0
- package/src/app.module.ts +74 -0
- package/src/balance/balance.module.ts +14 -0
- package/src/balance/balance.service.ts +230 -0
- package/src/balance/balance.ws.service.ts +104 -0
- package/src/balance/types.ts +16 -0
- package/src/bullmq/bullmq.helper.ts +41 -0
- package/src/bullmq/processors/eth-ws.processor.ts +47 -0
- package/src/bullmq/processors/inbox.processor.ts +55 -0
- package/src/bullmq/processors/interval.processor.ts +54 -0
- package/src/bullmq/processors/processor.module.ts +14 -0
- package/src/bullmq/processors/signer.processor.ts +41 -0
- package/src/bullmq/processors/solve-intent.processor.ts +73 -0
- package/src/bullmq/processors/tests/solve-intent.processor.spec.ts +3 -0
- package/src/bullmq/utils/queue.ts +22 -0
- package/src/chain-monitor/chain-monitor.module.ts +12 -0
- package/src/chain-monitor/chain-sync.service.ts +134 -0
- package/src/chain-monitor/tests/chain-sync.service.spec.ts +190 -0
- package/src/commander/.eslintrc.js +6 -0
- package/src/commander/balance/balance-command.module.ts +12 -0
- package/src/commander/balance/balance.command.ts +73 -0
- package/src/commander/command-main.ts +15 -0
- package/src/commander/commander-app.module.ts +31 -0
- package/src/commander/eco-config.command.ts +20 -0
- package/src/commander/safe/safe-command.module.ts +11 -0
- package/src/commander/safe/safe.command.ts +70 -0
- package/src/commander/transfer/client.command.ts +24 -0
- package/src/commander/transfer/transfer-command.module.ts +26 -0
- package/src/commander/transfer/transfer.command.ts +138 -0
- package/src/commander/utils.ts +8 -0
- package/src/common/chains/definitions/arbitrum.ts +12 -0
- package/src/common/chains/definitions/base.ts +21 -0
- package/src/common/chains/definitions/eco.ts +54 -0
- package/src/common/chains/definitions/ethereum.ts +22 -0
- package/src/common/chains/definitions/helix.ts +53 -0
- package/src/common/chains/definitions/mantle.ts +12 -0
- package/src/common/chains/definitions/optimism.ts +22 -0
- package/src/common/chains/definitions/polygon.ts +12 -0
- package/src/common/chains/supported.ts +26 -0
- package/src/common/chains/transport.ts +19 -0
- package/src/common/errors/eco-error.ts +155 -0
- package/src/common/events/constants.ts +3 -0
- package/src/common/events/viem.ts +22 -0
- package/src/common/logging/eco-log-message.ts +74 -0
- package/src/common/redis/constants.ts +55 -0
- package/src/common/redis/redis-connection-utils.ts +106 -0
- package/src/common/routes/constants.ts +3 -0
- package/src/common/utils/objects.ts +34 -0
- package/src/common/utils/strings.ts +49 -0
- package/src/common/utils/tests/objects.spec.ts +23 -0
- package/src/common/utils/tests/strings.spec.ts +22 -0
- package/src/common/viem/contracts.ts +25 -0
- package/src/common/viem/tests/utils.spec.ts +115 -0
- package/src/common/viem/utils.ts +78 -0
- package/src/contracts/ERC20.contract.ts +389 -0
- package/src/contracts/EntryPoint.V6.contract.ts +1309 -0
- package/src/contracts/KernelAccount.abi.ts +87 -0
- package/src/contracts/OwnableExecutor.abi.ts +128 -0
- package/src/contracts/SimpleAccount.contract.ts +524 -0
- package/src/contracts/inbox.ts +8 -0
- package/src/contracts/index.ts +9 -0
- package/src/contracts/intent-source.ts +55 -0
- package/src/contracts/interfaces/index.ts +1 -0
- package/src/contracts/interfaces/prover.interface.ts +22 -0
- package/src/contracts/prover.ts +9 -0
- package/src/contracts/tests/erc20.contract.spec.ts +59 -0
- package/src/contracts/utils.ts +31 -0
- package/src/decoder/decoder.interface.ts +3 -0
- package/src/decoder/tests/utils.spec.ts +36 -0
- package/src/decoder/utils.ts +24 -0
- package/src/decorators/cacheable.decorator.ts +48 -0
- package/src/eco-configs/aws-config.service.ts +75 -0
- package/src/eco-configs/eco-config.module.ts +44 -0
- package/src/eco-configs/eco-config.service.ts +220 -0
- package/src/eco-configs/eco-config.types.ts +278 -0
- package/src/eco-configs/interfaces/config-source.interface.ts +3 -0
- package/src/eco-configs/tests/aws-config.service.spec.ts +52 -0
- package/src/eco-configs/tests/eco-config.service.spec.ts +137 -0
- package/src/eco-configs/tests/utils.spec.ts +84 -0
- package/src/eco-configs/utils.ts +49 -0
- package/src/fee/fee.module.ts +10 -0
- package/src/fee/fee.service.ts +467 -0
- package/src/fee/tests/fee.service.spec.ts +909 -0
- package/src/fee/tests/utils.spec.ts +49 -0
- package/src/fee/types.ts +44 -0
- package/src/fee/utils.ts +23 -0
- package/src/flags/flags.module.ts +10 -0
- package/src/flags/flags.service.ts +112 -0
- package/src/flags/tests/flags.service.spec.ts +68 -0
- package/src/flags/utils.ts +22 -0
- package/src/health/constants.ts +1 -0
- package/src/health/health.controller.ts +23 -0
- package/src/health/health.module.ts +25 -0
- package/src/health/health.service.ts +40 -0
- package/src/health/indicators/balance.indicator.ts +196 -0
- package/src/health/indicators/eco-redis.indicator.ts +23 -0
- package/src/health/indicators/git-commit.indicator.ts +67 -0
- package/src/health/indicators/mongodb.indicator.ts +11 -0
- package/src/health/indicators/permission.indicator.ts +64 -0
- package/src/intent/create-intent.service.ts +129 -0
- package/src/intent/feasable-intent.service.ts +80 -0
- package/src/intent/fulfill-intent.service.ts +318 -0
- package/src/intent/intent.controller.ts +199 -0
- package/src/intent/intent.module.ts +49 -0
- package/src/intent/schemas/intent-call-data.schema.ts +16 -0
- package/src/intent/schemas/intent-data.schema.ts +114 -0
- package/src/intent/schemas/intent-source.schema.ts +33 -0
- package/src/intent/schemas/intent-token-amount.schema.ts +14 -0
- package/src/intent/schemas/reward-data.schema.ts +48 -0
- package/src/intent/schemas/route-data.schema.ts +52 -0
- package/src/intent/schemas/watch-event.schema.ts +32 -0
- package/src/intent/tests/create-intent.service.spec.ts +215 -0
- package/src/intent/tests/feasable-intent.service.spec.ts +155 -0
- package/src/intent/tests/fulfill-intent.service.spec.ts +564 -0
- package/src/intent/tests/utils-intent.service.spec.ts +308 -0
- package/src/intent/tests/utils.spec.ts +62 -0
- package/src/intent/tests/validate-intent.service.spec.ts +297 -0
- package/src/intent/tests/validation.service.spec.ts +337 -0
- package/src/intent/utils-intent.service.ts +168 -0
- package/src/intent/utils.ts +37 -0
- package/src/intent/validate-intent.service.ts +176 -0
- package/src/intent/validation.sevice.ts +223 -0
- package/src/interceptors/big-int.interceptor.ts +30 -0
- package/src/intervals/interval.module.ts +18 -0
- package/src/intervals/retry-infeasable-intents.service.ts +89 -0
- package/src/intervals/tests/retry-infeasable-intents.service.spec.ts +167 -0
- package/src/kms/errors.ts +0 -0
- package/src/kms/kms.module.ts +12 -0
- package/src/kms/kms.service.ts +65 -0
- package/src/kms/tests/kms.service.spec.ts +60 -0
- package/src/liquidity-manager/jobs/check-balances-cron.job.ts +229 -0
- package/src/liquidity-manager/jobs/liquidity-manager.job.ts +52 -0
- package/src/liquidity-manager/jobs/rebalance.job.ts +61 -0
- package/src/liquidity-manager/liquidity-manager.module.ts +29 -0
- package/src/liquidity-manager/processors/base.processor.ts +117 -0
- package/src/liquidity-manager/processors/eco-protocol-intents.processor.ts +34 -0
- package/src/liquidity-manager/processors/grouped-jobs.processor.ts +103 -0
- package/src/liquidity-manager/queues/liquidity-manager.queue.ts +48 -0
- package/src/liquidity-manager/schemas/rebalance-token.schema.ts +32 -0
- package/src/liquidity-manager/schemas/rebalance.schema.ts +32 -0
- package/src/liquidity-manager/services/liquidity-manager.service.ts +188 -0
- package/src/liquidity-manager/services/liquidity-provider.service.ts +25 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.spec.ts +125 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/lifi-provider.service.ts +117 -0
- package/src/liquidity-manager/services/liquidity-providers/LiFi/utils/get-transaction-hashes.ts +16 -0
- package/src/liquidity-manager/tests/liquidity-manager.service.spec.ts +142 -0
- package/src/liquidity-manager/types/token-state.enum.ts +5 -0
- package/src/liquidity-manager/types/types.d.ts +52 -0
- package/src/liquidity-manager/utils/address.ts +5 -0
- package/src/liquidity-manager/utils/math.ts +9 -0
- package/src/liquidity-manager/utils/serialize.spec.ts +24 -0
- package/src/liquidity-manager/utils/serialize.ts +47 -0
- package/src/liquidity-manager/utils/token.ts +91 -0
- package/src/main.ts +63 -0
- package/src/nest-redlock/nest-redlock.config.ts +14 -0
- package/src/nest-redlock/nest-redlock.interface.ts +5 -0
- package/src/nest-redlock/nest-redlock.module.ts +64 -0
- package/src/nest-redlock/nest-redlock.service.ts +59 -0
- package/src/prover/proof.service.ts +184 -0
- package/src/prover/prover.module.ts +10 -0
- package/src/prover/tests/proof.service.spec.ts +154 -0
- package/src/quote/dto/quote.intent.data.dto.ts +35 -0
- package/src/quote/dto/quote.reward.data.dto.ts +67 -0
- package/src/quote/dto/quote.route.data.dto.ts +71 -0
- package/src/quote/dto/types.ts +18 -0
- package/src/quote/errors.ts +215 -0
- package/src/quote/quote.module.ts +17 -0
- package/src/quote/quote.service.ts +299 -0
- package/src/quote/schemas/quote-call.schema.ts +16 -0
- package/src/quote/schemas/quote-intent.schema.ts +27 -0
- package/src/quote/schemas/quote-reward.schema.ts +24 -0
- package/src/quote/schemas/quote-route.schema.ts +30 -0
- package/src/quote/schemas/quote-token.schema.ts +14 -0
- package/src/quote/tests/quote.service.spec.ts +444 -0
- package/src/sign/atomic-signer.service.ts +24 -0
- package/src/sign/atomic.nonce.service.ts +114 -0
- package/src/sign/kms-account/kmsToAccount.ts +73 -0
- package/src/sign/kms-account/signKms.ts +30 -0
- package/src/sign/kms-account/signKmsTransaction.ts +37 -0
- package/src/sign/kms-account/signKmsTypedData.ts +21 -0
- package/src/sign/nonce.service.ts +89 -0
- package/src/sign/schemas/nonce.schema.ts +36 -0
- package/src/sign/sign.controller.ts +52 -0
- package/src/sign/sign.helper.ts +23 -0
- package/src/sign/sign.module.ts +27 -0
- package/src/sign/signer-kms.service.ts +27 -0
- package/src/sign/signer.service.ts +26 -0
- package/src/solver/filters/tests/valid-smart-wallet.service.spec.ts +87 -0
- package/src/solver/filters/valid-smart-wallet.service.ts +58 -0
- package/src/solver/solver.module.ts +10 -0
- package/src/transaction/multichain-public-client.service.ts +15 -0
- package/src/transaction/smart-wallets/kernel/actions/encodeData.kernel.ts +57 -0
- package/src/transaction/smart-wallets/kernel/create-kernel-client-v2.account.ts +183 -0
- package/src/transaction/smart-wallets/kernel/create.kernel.account.ts +270 -0
- package/src/transaction/smart-wallets/kernel/index.ts +2 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client-v2.service.ts +90 -0
- package/src/transaction/smart-wallets/kernel/kernel-account-client.service.ts +107 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.client.ts +105 -0
- package/src/transaction/smart-wallets/kernel/kernel-account.config.ts +34 -0
- package/src/transaction/smart-wallets/simple-account/create.simple.account.ts +19 -0
- package/src/transaction/smart-wallets/simple-account/index.ts +2 -0
- package/src/transaction/smart-wallets/simple-account/simple-account-client.service.ts +42 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.client.ts +83 -0
- package/src/transaction/smart-wallets/simple-account/simple-account.config.ts +5 -0
- package/src/transaction/smart-wallets/smart-wallet.types.ts +38 -0
- package/src/transaction/smart-wallets/utils.ts +14 -0
- package/src/transaction/transaction.module.ts +25 -0
- package/src/transaction/viem_multichain_client.service.ts +100 -0
- package/src/transforms/viem-address.decorator.ts +14 -0
- package/src/utils/bigint.ts +44 -0
- package/src/utils/types.ts +18 -0
- package/src/watch/intent/tests/watch-create-intent.service.spec.ts +257 -0
- package/src/watch/intent/tests/watch-fulfillment.service.spec.ts +141 -0
- package/src/watch/intent/watch-create-intent.service.ts +106 -0
- package/src/watch/intent/watch-event.service.ts +133 -0
- package/src/watch/intent/watch-fulfillment.service.ts +115 -0
- package/src/watch/watch.module.ts +13 -0
- package/test/app.e2e-spec.ts +21 -0
- package/test/jest-e2e.json +9 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +29 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
import { signKms } from '@/sign/kms-account/signKms'
|
2
|
+
import { signKmsTransaction } from '@/sign/kms-account/signKmsTransaction'
|
3
|
+
import { signKmsTypedData } from '@/sign/kms-account/signKmsTypedData'
|
4
|
+
import { Signer } from '@web3-kms-signer/core'
|
5
|
+
import { KMSWallets } from '@web3-kms-signer/kms-wallets'
|
6
|
+
import {
|
7
|
+
CustomSource,
|
8
|
+
getAddress,
|
9
|
+
hashMessage,
|
10
|
+
LocalAccount,
|
11
|
+
NonceManager,
|
12
|
+
Prettify,
|
13
|
+
toHex,
|
14
|
+
} from 'viem'
|
15
|
+
import { toAccount } from 'viem/accounts'
|
16
|
+
|
17
|
+
export type KmsToAccountOptions = {
|
18
|
+
nonceManager?: NonceManager | undefined
|
19
|
+
keyID: string
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* @description Creates an Account from a KMS signer.
|
24
|
+
*
|
25
|
+
* @returns A Private Key Account.
|
26
|
+
*/
|
27
|
+
export async function kmsToAccount(
|
28
|
+
signer: Signer,
|
29
|
+
wallets: KMSWallets,
|
30
|
+
options: KmsToAccountOptions,
|
31
|
+
): Promise<KmsAccount> {
|
32
|
+
const { nonceManager, keyID } = options
|
33
|
+
const publicKey = toHex(await wallets.getPublickey(keyID))
|
34
|
+
const addressHex = getAddress(await wallets.getAddressHex(keyID))
|
35
|
+
const addressBuffer = await wallets.getAddress(keyID)
|
36
|
+
|
37
|
+
const account = toAccount({
|
38
|
+
address: addressHex,
|
39
|
+
nonceManager,
|
40
|
+
async sign({ hash }) {
|
41
|
+
return await signKms({ hash, signer, keyID, addressBuffer, to: 'hex' })
|
42
|
+
},
|
43
|
+
async signMessage({ message }) {
|
44
|
+
return await signKms({ hash: hashMessage(message), signer, keyID, addressBuffer, to: 'hex' })
|
45
|
+
},
|
46
|
+
async signTransaction(transaction, { serializer } = {}) {
|
47
|
+
return await signKmsTransaction({
|
48
|
+
transaction,
|
49
|
+
serializer,
|
50
|
+
config: { signer, keyID, addressBuffer },
|
51
|
+
})
|
52
|
+
},
|
53
|
+
async signTypedData(typedData) {
|
54
|
+
return await signKmsTypedData({
|
55
|
+
...typedData,
|
56
|
+
config: { signer, keyID, addressBuffer },
|
57
|
+
} as any)
|
58
|
+
},
|
59
|
+
})
|
60
|
+
|
61
|
+
return {
|
62
|
+
...account,
|
63
|
+
publicKey,
|
64
|
+
source: 'kms',
|
65
|
+
} as KmsAccount
|
66
|
+
}
|
67
|
+
|
68
|
+
export type KmsAccount = Prettify<
|
69
|
+
LocalAccount<'kms'> & {
|
70
|
+
// TODO(v3): This will be redundant.
|
71
|
+
sign: NonNullable<CustomSource['sign']>
|
72
|
+
}
|
73
|
+
>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { Signer } from '@web3-kms-signer/core'
|
2
|
+
import { Hex, parseSignature } from 'viem'
|
3
|
+
import { SignReturnType } from 'viem/accounts'
|
4
|
+
|
5
|
+
export type To = 'object' | 'bytes' | 'hex'
|
6
|
+
|
7
|
+
export type KmsSignParameters<to extends To = 'object'> = {
|
8
|
+
hash: Hex
|
9
|
+
signer: Signer
|
10
|
+
keyID: string
|
11
|
+
addressBuffer: Buffer
|
12
|
+
to?: to | To | undefined
|
13
|
+
}
|
14
|
+
/**
|
15
|
+
* @description Signs a hash using a KMS signer.
|
16
|
+
*
|
17
|
+
* @returns A signature.
|
18
|
+
*/
|
19
|
+
export async function signKms<to extends To = 'object'>(
|
20
|
+
config: KmsSignParameters<to>,
|
21
|
+
): Promise<SignReturnType<to>> {
|
22
|
+
const { hash, signer, keyID, addressBuffer, to = 'object' } = config
|
23
|
+
const hexSig = (await signer.signDigest({ keyId: keyID, address: addressBuffer }, hash)) as Hex
|
24
|
+
return (() => {
|
25
|
+
if (to === 'bytes' || to === 'hex') {
|
26
|
+
return hexSig
|
27
|
+
}
|
28
|
+
return parseSignature(hexSig)
|
29
|
+
})() as SignReturnType<to>
|
30
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { signKms, KmsSignParameters } from '@/sign/kms-account/signKms'
|
2
|
+
import {
|
3
|
+
keccak256,
|
4
|
+
serializeTransaction,
|
5
|
+
SerializeTransactionFn,
|
6
|
+
TransactionSerializable,
|
7
|
+
} from 'viem'
|
8
|
+
import { SignTransactionParameters, SignTransactionReturnType } from 'viem/accounts'
|
9
|
+
|
10
|
+
export async function signKmsTransaction<
|
11
|
+
serializer extends
|
12
|
+
SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>,
|
13
|
+
transaction extends Parameters<serializer>[0] = Parameters<serializer>[0],
|
14
|
+
>(
|
15
|
+
parameters: Omit<SignTransactionParameters<serializer, transaction>, 'privateKey'> & {
|
16
|
+
config: Omit<KmsSignParameters, 'hash'>
|
17
|
+
},
|
18
|
+
): Promise<SignTransactionReturnType<serializer, transaction>> {
|
19
|
+
const { transaction, serializer = serializeTransaction, config } = parameters
|
20
|
+
|
21
|
+
const signableTransaction = (() => {
|
22
|
+
// For EIP-4844 Transactions, we want to sign the transaction payload body (tx_payload_body) without the sidecars (ie. without the network wrapper).
|
23
|
+
// See: https://github.com/ethereum/EIPs/blob/e00f4daa66bd56e2dbd5f1d36d09fd613811a48b/EIPS/eip-4844.md#networking
|
24
|
+
if (transaction.type === 'eip4844')
|
25
|
+
return {
|
26
|
+
...transaction,
|
27
|
+
sidecars: false,
|
28
|
+
}
|
29
|
+
return transaction
|
30
|
+
})()
|
31
|
+
const signature = await signKms({
|
32
|
+
...config,
|
33
|
+
hash: keccak256(serializer(signableTransaction)),
|
34
|
+
to: 'object',
|
35
|
+
})
|
36
|
+
return serializer(transaction, signature) as SignTransactionReturnType<serializer, transaction>
|
37
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { KmsSignParameters, signKms } from '@/sign/kms-account/signKms'
|
2
|
+
import { hashTypedData, SignTypedDataReturnType, TypedData } from 'viem'
|
3
|
+
import { SignTypedDataParameters } from 'viem/accounts'
|
4
|
+
|
5
|
+
export async function signKmsTypedData<
|
6
|
+
const typedData extends TypedData | Record<string, unknown>,
|
7
|
+
primaryType extends keyof typedData | 'EIP712Domain',
|
8
|
+
>(
|
9
|
+
parameters: Omit<SignTypedDataParameters<typedData, primaryType>, 'privateKey'> & {
|
10
|
+
config: Omit<KmsSignParameters, 'hash'>
|
11
|
+
},
|
12
|
+
): Promise<SignTypedDataReturnType> {
|
13
|
+
const { config, ...typedData } = parameters as unknown as SignTypedDataParameters & {
|
14
|
+
config: Omit<KmsSignParameters, 'hash'>
|
15
|
+
}
|
16
|
+
return await signKms({
|
17
|
+
hash: hashTypedData(typedData),
|
18
|
+
...config,
|
19
|
+
to: 'hex',
|
20
|
+
})
|
21
|
+
}
|
@@ -0,0 +1,89 @@
|
|
1
|
+
import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common'
|
2
|
+
import { InjectModel } from '@nestjs/mongoose'
|
3
|
+
import { Model } from 'mongoose'
|
4
|
+
import { Nonce } from './schemas/nonce.schema'
|
5
|
+
import { JobsOptions, Queue } from 'bullmq'
|
6
|
+
import { QUEUES } from '../common/redis/constants'
|
7
|
+
import { InjectQueue } from '@nestjs/bullmq'
|
8
|
+
import { EcoConfigService } from '../eco-configs/eco-config.service'
|
9
|
+
import { entries } from 'lodash'
|
10
|
+
import { AtomicKeyClientParams, AtomicNonceService } from './atomic.nonce.service'
|
11
|
+
import { createPublicClient, extractChain, Hex, sha256 } from 'viem'
|
12
|
+
import { SignerService } from './signer.service'
|
13
|
+
import { getTransport } from '../common/chains/transport'
|
14
|
+
import { ChainsSupported } from '../common/chains/supported'
|
15
|
+
|
16
|
+
/**
|
17
|
+
* TODO this class needs to be assigned to an EAO, a userOp gets its nonce throught the alchemy sdk
|
18
|
+
* which pulls its fromt the rpc bundler
|
19
|
+
*/
|
20
|
+
@Injectable()
|
21
|
+
export class NonceService extends AtomicNonceService<Nonce> implements OnApplicationBootstrap {
|
22
|
+
protected logger = new Logger(NonceService.name)
|
23
|
+
private intentJobConfig: JobsOptions
|
24
|
+
|
25
|
+
constructor(
|
26
|
+
@InjectModel(Nonce.name) private nonceModel: Model<Nonce>,
|
27
|
+
@InjectQueue(QUEUES.SIGNER.queue) private readonly signerQueue: Queue,
|
28
|
+
private readonly signerService: SignerService,
|
29
|
+
private readonly ecoConfigService: EcoConfigService,
|
30
|
+
) {
|
31
|
+
super(nonceModel)
|
32
|
+
}
|
33
|
+
async onApplicationBootstrap() {
|
34
|
+
this.intentJobConfig = this.ecoConfigService.getRedis().jobs.intentJobConfig
|
35
|
+
this.syncQueue()
|
36
|
+
}
|
37
|
+
|
38
|
+
async syncQueue() {
|
39
|
+
const { should, hash } = await this.shouldSync()
|
40
|
+
if (should) {
|
41
|
+
await this.signerQueue.add(
|
42
|
+
QUEUES.SIGNER.jobs.nonce_sync,
|
43
|
+
{},
|
44
|
+
{
|
45
|
+
jobId: hash,
|
46
|
+
...this.intentJobConfig,
|
47
|
+
},
|
48
|
+
)
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
protected override async getSyncParams(): Promise<AtomicKeyClientParams[]> {
|
53
|
+
const address = this.signerService.getAccount().address
|
54
|
+
const apiKey = this.ecoConfigService.getAlchemy().apiKey
|
55
|
+
const paramsAsync = entries(this.ecoConfigService.getSolvers()).map(async ([chainIdString]) => {
|
56
|
+
const chainID = parseInt(chainIdString)
|
57
|
+
const chain = extractChain({
|
58
|
+
chains: ChainsSupported,
|
59
|
+
id: chainID,
|
60
|
+
})
|
61
|
+
const client = createPublicClient({
|
62
|
+
chain,
|
63
|
+
transport: getTransport(chain, apiKey),
|
64
|
+
} as any)
|
65
|
+
return { address, client } as AtomicKeyClientParams
|
66
|
+
})
|
67
|
+
|
68
|
+
return await Promise.all(paramsAsync)
|
69
|
+
}
|
70
|
+
|
71
|
+
async getLastSynceAt(): Promise<Date> {
|
72
|
+
const meta = await this.nonceModel
|
73
|
+
.findOne({ updatedAt: { $exists: true } })
|
74
|
+
.sort({ updatedAt: -1 })
|
75
|
+
.exec()
|
76
|
+
if (!meta) {
|
77
|
+
return new Date(0)
|
78
|
+
}
|
79
|
+
return meta.updatedAt
|
80
|
+
}
|
81
|
+
|
82
|
+
async shouldSync(): Promise<{ should: boolean; hash: string }> {
|
83
|
+
const lastSyncAt = await this.getLastSynceAt()
|
84
|
+
const should =
|
85
|
+
Date.now() - lastSyncAt.getTime() > this.ecoConfigService.getEth().nonce.update_interval_ms
|
86
|
+
const input = `0x${lastSyncAt.toISOString()}` as Hex
|
87
|
+
return { should, hash: sha256(input) }
|
88
|
+
}
|
89
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
|
2
|
+
import { now } from 'mongoose'
|
3
|
+
import { AtomicKeyParams } from '../atomic.nonce.service'
|
4
|
+
import { Hex } from 'viem'
|
5
|
+
import { getAtomicNonceVals } from '../sign.helper'
|
6
|
+
|
7
|
+
@Schema({ timestamps: true })
|
8
|
+
export class Nonce {
|
9
|
+
@Prop({ required: true, unique: true })
|
10
|
+
key: string
|
11
|
+
|
12
|
+
@Prop({ required: true, default: 0 })
|
13
|
+
nonce: number
|
14
|
+
|
15
|
+
@Prop({ required: true })
|
16
|
+
chainID: number
|
17
|
+
|
18
|
+
@Prop({ required: true })
|
19
|
+
address: Hex
|
20
|
+
|
21
|
+
@Prop({ required: true, default: now() })
|
22
|
+
createdAt: Date
|
23
|
+
|
24
|
+
@Prop({ required: true, default: now() })
|
25
|
+
updatedAt: Date
|
26
|
+
|
27
|
+
toString(): string {
|
28
|
+
return `${this.key}:${this.nonce}`
|
29
|
+
}
|
30
|
+
|
31
|
+
getAtomicNonceVals(): AtomicKeyParams {
|
32
|
+
return getAtomicNonceVals(this.key)
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
export const NonceSchema = SchemaFactory.createForClass(Nonce)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { Controller, Get } from '@nestjs/common'
|
2
|
+
import { Logger } from '@nestjs/common'
|
3
|
+
import { SignerService } from './signer.service'
|
4
|
+
|
5
|
+
@Controller('sign')
|
6
|
+
export class SignController {
|
7
|
+
private logger = new Logger(SignController.name)
|
8
|
+
constructor(
|
9
|
+
// private readonly aa: MultichainSmartAccountService,
|
10
|
+
private readonly signer: SignerService,
|
11
|
+
) {}
|
12
|
+
@Get()
|
13
|
+
async fake() {
|
14
|
+
await this.fakeSign()
|
15
|
+
|
16
|
+
return
|
17
|
+
}
|
18
|
+
|
19
|
+
async fakeSign() {
|
20
|
+
// const smartAccountClient = await this.aa.getClient(84532)
|
21
|
+
// let ans = await smartAccountClient.account.getImplementationAddress()
|
22
|
+
// console.log(ans, smartAccountClient.account.address)
|
23
|
+
// await smartAccountClient.signUserOperation({
|
24
|
+
// // @ts-ignore
|
25
|
+
// uoStruct: this.getUo().flat(),
|
26
|
+
// account: this.atomicSigner.getSigner() as any,
|
27
|
+
// })
|
28
|
+
// // @ts-ignore
|
29
|
+
// const uo = await smartAccountClient.sendUserOperation({
|
30
|
+
// uo: this.getUo().flat(),
|
31
|
+
// })
|
32
|
+
// const receipt = await smartAccountClient.waitForUserOperationTransaction(uo)
|
33
|
+
// console.log(receipt)
|
34
|
+
// ans = await smartAccountClient.account.getNonce()
|
35
|
+
// console.log(ans, smartAccountClient.account.address)
|
36
|
+
}
|
37
|
+
|
38
|
+
// getUo(){
|
39
|
+
// const transferSolverAmount = encodeFunctionData({
|
40
|
+
// abi: erc20Abi,
|
41
|
+
// functionName: 'transfer',
|
42
|
+
// args: ['0x3A322Ff8ef24592e5e50D2EB4E630cDA87Bd83A6' as Hex, BigInt(10)],
|
43
|
+
// })
|
44
|
+
|
45
|
+
// return [
|
46
|
+
// {
|
47
|
+
// target: '0xd3F4Bef596a04e2be4fbeB17Dd70f02F717c5a6c' as Hex,
|
48
|
+
// data: transferSolverAmount,
|
49
|
+
// },
|
50
|
+
// ]
|
51
|
+
// }
|
52
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { Hex, NonceManagerSource, PrivateKeyAccount } from 'viem'
|
2
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
3
|
+
import { createNonceManager } from 'viem/nonce'
|
4
|
+
import { AtomicKeyParams } from './atomic.nonce.service'
|
5
|
+
|
6
|
+
export function privateKeyAndNonceToAccountSigner(
|
7
|
+
atomicNonceSource: NonceManagerSource,
|
8
|
+
privateKey: Hex,
|
9
|
+
): PrivateKeyAccount {
|
10
|
+
const nonceManager = createNonceManager({
|
11
|
+
source: atomicNonceSource,
|
12
|
+
})
|
13
|
+
return privateKeyToAccount(privateKey, { nonceManager })
|
14
|
+
}
|
15
|
+
|
16
|
+
export function getAtomicNonceKey(params: AtomicKeyParams) {
|
17
|
+
return `${params.address}.${params.chainId}`
|
18
|
+
}
|
19
|
+
|
20
|
+
export function getAtomicNonceVals(key: string): AtomicKeyParams {
|
21
|
+
const [address, chainId] = key.split('.')
|
22
|
+
return { address: address as Hex, chainId: parseInt(chainId) }
|
23
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { Module } from '@nestjs/common'
|
2
|
+
import { MongooseModule } from '@nestjs/mongoose'
|
3
|
+
import { Nonce, NonceSchema } from './schemas/nonce.schema'
|
4
|
+
import { initBullMQ } from '../bullmq/bullmq.helper'
|
5
|
+
import { QUEUES } from '../common/redis/constants'
|
6
|
+
import { SignerService } from './signer.service'
|
7
|
+
import { AtomicSignerService } from './atomic-signer.service'
|
8
|
+
import { NonceService } from './nonce.service'
|
9
|
+
import { SignerKmsService } from '@/sign/signer-kms.service'
|
10
|
+
import { KmsModule } from '@/kms/kms.module'
|
11
|
+
|
12
|
+
@Module({
|
13
|
+
imports: [
|
14
|
+
KmsModule,
|
15
|
+
MongooseModule.forFeature([{ name: Nonce.name, schema: NonceSchema }]),
|
16
|
+
initBullMQ(QUEUES.SIGNER),
|
17
|
+
],
|
18
|
+
providers: [SignerService, SignerKmsService, NonceService, AtomicSignerService],
|
19
|
+
exports: [
|
20
|
+
AtomicSignerService,
|
21
|
+
SignerService,
|
22
|
+
SignerKmsService,
|
23
|
+
NonceService,
|
24
|
+
MongooseModule, //add SignModule to the rest of the modules that import intents
|
25
|
+
],
|
26
|
+
})
|
27
|
+
export class SignModule {}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { KmsService } from '@/kms/kms.service'
|
2
|
+
import { KmsAccount, kmsToAccount } from '@/sign/kms-account/kmsToAccount'
|
3
|
+
import { Injectable, OnModuleInit } from '@nestjs/common'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* A signer service that creates a {@link KmsAccount} from a KMS signer.
|
7
|
+
* Uses the {@link KmsService} to get the KMS signer from aws.
|
8
|
+
*/
|
9
|
+
@Injectable()
|
10
|
+
export class SignerKmsService implements OnModuleInit {
|
11
|
+
private account: KmsAccount
|
12
|
+
constructor(readonly kmsService: KmsService) {}
|
13
|
+
|
14
|
+
async onModuleInit() {
|
15
|
+
this.account = await this.buildAccount()
|
16
|
+
}
|
17
|
+
|
18
|
+
getAccount() {
|
19
|
+
return this.account
|
20
|
+
}
|
21
|
+
|
22
|
+
protected async buildAccount(): Promise<KmsAccount> {
|
23
|
+
return await kmsToAccount(this.kmsService.signer, this.kmsService.wallets, {
|
24
|
+
keyID: this.kmsService.getKmsKeyId(),
|
25
|
+
})
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { Injectable, OnModuleInit } from '@nestjs/common'
|
2
|
+
import { EcoConfigService } from '../eco-configs/eco-config.service'
|
3
|
+
import { Hex, PrivateKeyAccount } from 'viem'
|
4
|
+
import { privateKeyToAccount } from 'viem/accounts'
|
5
|
+
|
6
|
+
@Injectable()
|
7
|
+
export class SignerService implements OnModuleInit {
|
8
|
+
private account: PrivateKeyAccount
|
9
|
+
constructor(readonly ecoConfigService: EcoConfigService) {}
|
10
|
+
|
11
|
+
async onModuleInit() {
|
12
|
+
this.account = this.buildAccount()
|
13
|
+
}
|
14
|
+
|
15
|
+
getAccount() {
|
16
|
+
return this.account
|
17
|
+
}
|
18
|
+
|
19
|
+
protected buildAccount(): PrivateKeyAccount {
|
20
|
+
return privateKeyToAccount(this.getPrivateKey())
|
21
|
+
}
|
22
|
+
|
23
|
+
protected getPrivateKey(): Hex {
|
24
|
+
return this.ecoConfigService.getEth().simpleAccount.signerPrivateKey
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import { createMock, DeepMocked } from '@golevelup/ts-jest'
|
2
|
+
import { ValidSmartWalletService } from '../valid-smart-wallet.service'
|
3
|
+
import { MultichainPublicClientService } from '../../../transaction/multichain-public-client.service'
|
4
|
+
import { EcoConfigService } from '../../../eco-configs/eco-config.service'
|
5
|
+
import { Test, TestingModule } from '@nestjs/testing'
|
6
|
+
|
7
|
+
describe('ValidSmartWalletService Tests', () => {
|
8
|
+
let validWalletService: ValidSmartWalletService
|
9
|
+
let publicClientService: DeepMocked<MultichainPublicClientService>
|
10
|
+
let ecoConfigService: DeepMocked<EcoConfigService>
|
11
|
+
|
12
|
+
beforeEach(async () => {
|
13
|
+
const validMod: TestingModule = await Test.createTestingModule({
|
14
|
+
providers: [
|
15
|
+
ValidSmartWalletService,
|
16
|
+
{
|
17
|
+
provide: MultichainPublicClientService,
|
18
|
+
useValue: createMock<MultichainPublicClientService>(),
|
19
|
+
},
|
20
|
+
{ provide: EcoConfigService, useValue: createMock<EcoConfigService>() },
|
21
|
+
],
|
22
|
+
}).compile()
|
23
|
+
|
24
|
+
validWalletService = validMod.get(ValidSmartWalletService)
|
25
|
+
publicClientService = validMod.get(MultichainPublicClientService)
|
26
|
+
ecoConfigService = validMod.get(EcoConfigService)
|
27
|
+
})
|
28
|
+
|
29
|
+
afterEach(async () => {
|
30
|
+
// restore the spy created with spyOn
|
31
|
+
jest.restoreAllMocks()
|
32
|
+
})
|
33
|
+
const entryPoint = '0x123'
|
34
|
+
const factory = '0x456'
|
35
|
+
|
36
|
+
describe('on startup', () => {
|
37
|
+
it('should initialize the entry point and factory addresses', async () => {
|
38
|
+
const contracts = {
|
39
|
+
entryPoint: { contractAddress: entryPoint },
|
40
|
+
simpleAccountFactory: { contractAddress: factory },
|
41
|
+
}
|
42
|
+
ecoConfigService.getEth = jest.fn().mockReturnValue({ simpleAccount: { contracts } })
|
43
|
+
|
44
|
+
validWalletService.onModuleInit()
|
45
|
+
|
46
|
+
expect(validWalletService['entryPointAddress']).toEqual(entryPoint)
|
47
|
+
expect(validWalletService['factoryAddress']).toEqual(factory)
|
48
|
+
})
|
49
|
+
})
|
50
|
+
|
51
|
+
describe('on validate smart wallet', () => {
|
52
|
+
beforeEach(() => {
|
53
|
+
validWalletService['entryPointAddress'] = entryPoint
|
54
|
+
validWalletService['factoryAddress'] = factory
|
55
|
+
})
|
56
|
+
|
57
|
+
it('should return false if there are no deploy events for a SA address', async () => {
|
58
|
+
publicClientService.getClient = jest.fn().mockImplementation(async (chainID) => {
|
59
|
+
return {
|
60
|
+
getContractEvents: jest.fn().mockReturnValue([]),
|
61
|
+
}
|
62
|
+
})
|
63
|
+
const result = await validWalletService.validateSmartWallet('0x789', 1n)
|
64
|
+
expect(result).toEqual(false)
|
65
|
+
})
|
66
|
+
|
67
|
+
it('should return false if the SA address is from another factory', async () => {
|
68
|
+
publicClientService.getClient = jest.fn().mockImplementation(async (chainID) => {
|
69
|
+
return {
|
70
|
+
getContractEvents: jest.fn().mockReturnValue([{ args: { factory: '0xabc' } }]),
|
71
|
+
}
|
72
|
+
})
|
73
|
+
const result = await validWalletService.validateSmartWallet('0x789', 1n)
|
74
|
+
expect(result).toEqual(false)
|
75
|
+
})
|
76
|
+
|
77
|
+
it('should return true if the SA is from our factory', async () => {
|
78
|
+
publicClientService.getClient = jest.fn().mockImplementation(async (chainID) => {
|
79
|
+
return {
|
80
|
+
getContractEvents: jest.fn().mockReturnValue([{ args: { factory: factory } }]),
|
81
|
+
}
|
82
|
+
})
|
83
|
+
const result = await validWalletService.validateSmartWallet('0x789', 1n)
|
84
|
+
expect(result).toEqual(true)
|
85
|
+
})
|
86
|
+
})
|
87
|
+
})
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
|
2
|
+
import { MultichainPublicClientService } from '../../transaction/multichain-public-client.service'
|
3
|
+
import { EcoConfigService } from '../../eco-configs/eco-config.service'
|
4
|
+
import { Hex } from 'viem'
|
5
|
+
import { EntryPointAbi_v6 } from '../../contracts/EntryPoint.V6.contract'
|
6
|
+
import { EcoLogMessage } from '../../common/logging/eco-log-message'
|
7
|
+
|
8
|
+
@Injectable()
|
9
|
+
export class ValidSmartWalletService implements OnModuleInit {
|
10
|
+
private logger = new Logger(ValidSmartWalletService.name)
|
11
|
+
|
12
|
+
private entryPointAddress: Hex
|
13
|
+
private factoryAddress: Hex
|
14
|
+
constructor(
|
15
|
+
private readonly publicClient: MultichainPublicClientService,
|
16
|
+
private readonly ecoConfigService: EcoConfigService,
|
17
|
+
) {}
|
18
|
+
|
19
|
+
onModuleInit() {
|
20
|
+
const contracts = this.ecoConfigService.getEth().simpleAccount.contracts
|
21
|
+
this.entryPointAddress = contracts.entryPoint.contractAddress
|
22
|
+
this.factoryAddress = contracts.simpleAccountFactory.contractAddress
|
23
|
+
}
|
24
|
+
/**
|
25
|
+
* Validates that the smart wallet account that posts and creates an IntentCreated event on chain
|
26
|
+
* for the IntentSource contract, is from the correct smart wallet factory.
|
27
|
+
*
|
28
|
+
* @param smartWalletAddress the address of the smart wallet to validate
|
29
|
+
* @param chainID the chain id of the transaction the event is from
|
30
|
+
*/
|
31
|
+
async validateSmartWallet(smartWalletAddress: Hex, chainID: bigint): Promise<boolean> {
|
32
|
+
const client = await this.publicClient.getClient(Number(chainID))
|
33
|
+
try {
|
34
|
+
const deployedEvents = await client.getContractEvents({
|
35
|
+
address: this.entryPointAddress,
|
36
|
+
abi: EntryPointAbi_v6,
|
37
|
+
eventName: 'AccountDeployed',
|
38
|
+
args: { sender: smartWalletAddress },
|
39
|
+
fromBlock: 0n,
|
40
|
+
toBlock: 'latest',
|
41
|
+
})
|
42
|
+
//should be only one event, but comes as an array
|
43
|
+
return (
|
44
|
+
deployedEvents && deployedEvents.some((event) => event.args.factory === this.factoryAddress)
|
45
|
+
)
|
46
|
+
} catch (error) {
|
47
|
+
this.logger.error(
|
48
|
+
EcoLogMessage.fromDefault({
|
49
|
+
message: `RPC: getContractEvents error`,
|
50
|
+
properties: {
|
51
|
+
error,
|
52
|
+
},
|
53
|
+
}),
|
54
|
+
)
|
55
|
+
return false
|
56
|
+
}
|
57
|
+
}
|
58
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { Module } from '@nestjs/common'
|
2
|
+
import { ValidSmartWalletService } from './filters/valid-smart-wallet.service'
|
3
|
+
import { TransactionModule } from '../transaction/transaction.module'
|
4
|
+
|
5
|
+
@Module({
|
6
|
+
imports: [TransactionModule],
|
7
|
+
providers: [ValidSmartWalletService],
|
8
|
+
exports: [ValidSmartWalletService],
|
9
|
+
})
|
10
|
+
export class SolverModule {}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Injectable } from '@nestjs/common'
|
2
|
+
import { createPublicClient, PublicClient, PublicClientConfig } from 'viem'
|
3
|
+
import { ViemMultichainClientService } from './viem_multichain_client.service'
|
4
|
+
|
5
|
+
@Injectable()
|
6
|
+
export class MultichainPublicClientService extends ViemMultichainClientService<
|
7
|
+
PublicClient,
|
8
|
+
PublicClientConfig
|
9
|
+
> {
|
10
|
+
protected override async createInstanceClient(
|
11
|
+
configs: PublicClientConfig,
|
12
|
+
): Promise<PublicClient> {
|
13
|
+
return createPublicClient(configs)
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import { encode7579Calls } from 'permissionless'
|
2
|
+
import { KernelVersion } from 'permissionless/accounts'
|
3
|
+
import { type Address, type Hex, encodeFunctionData } from 'viem'
|
4
|
+
import { isKernelV2 } from '../kernel-account.config'
|
5
|
+
import { KernelExecuteAbi } from '../../../../contracts'
|
6
|
+
|
7
|
+
export const encodeKernelExecuteCallData = ({
|
8
|
+
kernelVersion,
|
9
|
+
calls,
|
10
|
+
}: {
|
11
|
+
calls: readonly {
|
12
|
+
to: Address
|
13
|
+
value?: bigint | undefined
|
14
|
+
data?: Hex | undefined
|
15
|
+
}[]
|
16
|
+
kernelVersion: KernelVersion<'0.6' | '0.7'>
|
17
|
+
}) => {
|
18
|
+
if (isKernelV2(kernelVersion)) {
|
19
|
+
if (calls.length > 1) {
|
20
|
+
// Encode a batched call
|
21
|
+
return encodeFunctionData({
|
22
|
+
abi: KernelExecuteAbi,
|
23
|
+
functionName: 'executeBatch',
|
24
|
+
args: [
|
25
|
+
calls.map((tx) => ({
|
26
|
+
to: tx.to,
|
27
|
+
value: tx.value ?? 0n,
|
28
|
+
data: tx.data ?? '0x',
|
29
|
+
})),
|
30
|
+
],
|
31
|
+
})
|
32
|
+
}
|
33
|
+
|
34
|
+
const call = calls.length === 0 ? undefined : calls[0]
|
35
|
+
|
36
|
+
if (!call) {
|
37
|
+
throw new Error('No calls to encode')
|
38
|
+
}
|
39
|
+
|
40
|
+
// Encode a simple call
|
41
|
+
return encodeFunctionData({
|
42
|
+
abi: KernelExecuteAbi,
|
43
|
+
functionName: 'execute',
|
44
|
+
args: [call.to, call.value ?? 0n, call.data ?? '0x', 0],
|
45
|
+
})
|
46
|
+
}
|
47
|
+
|
48
|
+
return encode7579Calls({
|
49
|
+
mode: {
|
50
|
+
type: calls.length > 1 ? 'batchcall' : 'call',
|
51
|
+
revertOnError: false,
|
52
|
+
selector: '0x',
|
53
|
+
context: '0x',
|
54
|
+
},
|
55
|
+
callData: calls,
|
56
|
+
})
|
57
|
+
}
|