@opendatalabs/vana-sdk 0.1.0-alpha.7ee7635 → 0.1.0-alpha.80df35f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/waitForTransactionEvents.test.d.ts +1 -0
- package/dist/browser.d.ts +4 -2
- package/dist/chains/definitions.cjs +9 -6
- package/dist/chains/definitions.cjs.map +1 -1
- package/dist/chains/definitions.d.ts +9 -11
- package/dist/chains/definitions.js +9 -6
- package/dist/chains/definitions.js.map +1 -1
- package/dist/chains/index.d.ts +5 -2
- package/dist/chains.browser.d.ts +8 -2
- package/dist/chains.d.ts +8 -2
- package/dist/chains.node.d.ts +8 -2
- package/dist/config/addresses.d.ts +8 -45
- package/dist/config/chains.d.ts +9 -13
- package/dist/config/default-services.cjs +60 -0
- package/dist/config/default-services.cjs.map +1 -0
- package/dist/config/default-services.d.ts +46 -0
- package/dist/config/default-services.js +33 -0
- package/dist/config/default-services.js.map +1 -0
- package/dist/config/default-services.test.d.ts +1 -0
- package/dist/config/features.d.ts +1 -3
- package/dist/config/tests/addresses.test.d.ts +1 -0
- package/dist/contracts/contractController.cjs +3 -3
- package/dist/contracts/contractController.cjs.map +1 -1
- package/dist/contracts/contractController.d.ts +11 -49
- package/dist/contracts/contractController.js +4 -7
- package/dist/contracts/contractController.js.map +1 -1
- package/dist/contracts/tests/contractController.test.d.ts +1 -0
- package/dist/controllers/__tests__/schemas-edge-cases.test.d.ts +1 -0
- package/dist/controllers/base.cjs +83 -0
- package/dist/controllers/base.cjs.map +1 -0
- package/dist/controllers/base.d.ts +84 -0
- package/dist/controllers/base.js +59 -0
- package/dist/controllers/base.js.map +1 -0
- package/dist/controllers/data-error-handling.test.d.ts +1 -0
- package/dist/controllers/data.cjs +338 -107
- package/dist/controllers/data.cjs.map +1 -1
- package/dist/controllers/data.d.ts +145 -46
- package/dist/controllers/data.js +338 -107
- package/dist/controllers/data.js.map +1 -1
- package/dist/controllers/permissions.cjs +162 -223
- package/dist/controllers/permissions.cjs.map +1 -1
- package/dist/controllers/permissions.d.ts +24 -78
- package/dist/controllers/permissions.js +162 -223
- package/dist/controllers/permissions.js.map +1 -1
- package/dist/controllers/protocol.cjs +15 -11
- package/dist/controllers/protocol.cjs.map +1 -1
- package/dist/controllers/protocol.d.ts +7 -56
- package/dist/controllers/protocol.js +15 -14
- package/dist/controllers/protocol.js.map +1 -1
- package/dist/controllers/schemas.cjs +29 -36
- package/dist/controllers/schemas.cjs.map +1 -1
- package/dist/controllers/schemas.d.ts +8 -23
- package/dist/controllers/schemas.js +29 -36
- package/dist/controllers/schemas.js.map +1 -1
- package/dist/controllers/server-additional.test.d.ts +1 -0
- package/dist/controllers/server.cjs +15 -10
- package/dist/controllers/server.cjs.map +1 -1
- package/dist/controllers/server.d.ts +7 -20
- package/dist/controllers/server.js +15 -10
- package/dist/controllers/server.js.map +1 -1
- package/dist/core/apiClient.cjs +15 -12
- package/dist/core/apiClient.cjs.map +1 -1
- package/dist/core/apiClient.d.ts +5 -9
- package/dist/core/apiClient.js +19 -19
- package/dist/core/apiClient.js.map +1 -1
- package/dist/core/client.cjs +7 -7
- package/dist/core/client.cjs.map +1 -1
- package/dist/core/client.d.ts +6 -9
- package/dist/core/client.js +7 -7
- package/dist/core/client.js.map +1 -1
- package/dist/core/core.test.d.ts +1 -0
- package/dist/core/generics.cjs +11 -9
- package/dist/core/generics.cjs.map +1 -1
- package/dist/core/generics.d.ts +9 -13
- package/dist/core/generics.js +22 -29
- package/dist/core/generics.js.map +1 -1
- package/dist/core/tests/apiClient.test.d.ts +1 -0
- package/dist/core/tests/client.test.d.ts +1 -0
- package/dist/core/tests/generics.test.d.ts +1 -0
- package/dist/core.cjs +82 -34
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +21 -73
- package/dist/core.js +105 -60
- package/dist/core.js.map +1 -1
- package/dist/crypto/ecies/__tests__/base.test.d.ts +4 -0
- package/dist/crypto/ecies/__tests__/compatibility.test.d.ts +8 -0
- package/dist/crypto/ecies/__tests__/constants.test.d.ts +4 -0
- package/dist/crypto/ecies/__tests__/native-parity.test.d.ts +7 -0
- package/dist/crypto/ecies/__tests__/normalization.test.d.ts +1 -0
- package/dist/crypto/ecies/__tests__/test-vectors.d.ts +2 -4
- package/dist/crypto/ecies/base.cjs +4 -3
- package/dist/crypto/ecies/base.cjs.map +1 -1
- package/dist/crypto/ecies/base.d.ts +2 -5
- package/dist/crypto/ecies/base.js +12 -15
- package/dist/crypto/ecies/base.js.map +1 -1
- package/dist/crypto/ecies/browser.cjs +2 -1
- package/dist/crypto/ecies/browser.cjs.map +1 -1
- package/dist/crypto/ecies/browser.d.ts +2 -7
- package/dist/crypto/ecies/browser.js +2 -1
- package/dist/crypto/ecies/browser.js.map +1 -1
- package/dist/crypto/ecies/constants.d.ts +7 -9
- package/dist/crypto/ecies/index.d.ts +8 -1
- package/dist/crypto/ecies/interface.cjs +4 -5
- package/dist/crypto/ecies/interface.cjs.map +1 -1
- package/dist/crypto/ecies/interface.d.ts +9 -11
- package/dist/crypto/ecies/interface.js +4 -5
- package/dist/crypto/ecies/interface.js.map +1 -1
- package/dist/crypto/ecies/node.cjs +3 -2
- package/dist/crypto/ecies/node.cjs.map +1 -1
- package/dist/crypto/ecies/node.d.ts +2 -7
- package/dist/crypto/ecies/node.js +11 -16
- package/dist/crypto/ecies/node.js.map +1 -1
- package/dist/crypto/ecies/utils.cjs +2 -41
- package/dist/crypto/ecies/utils.cjs.map +1 -1
- package/dist/crypto/ecies/utils.d.ts +3 -40
- package/dist/crypto/ecies/utils.js +1 -35
- package/dist/crypto/ecies/utils.js.map +1 -1
- package/dist/crypto/services/WalletKeyEncryptionService.cjs +2 -2
- package/dist/crypto/services/WalletKeyEncryptionService.cjs.map +1 -1
- package/dist/crypto/services/WalletKeyEncryptionService.d.ts +3 -7
- package/dist/crypto/services/WalletKeyEncryptionService.js +5 -9
- package/dist/crypto/services/WalletKeyEncryptionService.js.map +1 -1
- package/dist/crypto/services/WalletKeyEncryptionService.test.d.ts +1 -0
- package/dist/diagnostics.d.ts +1 -3
- package/dist/diagnostics.test.d.ts +1 -0
- package/dist/errors.cjs +16 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +53 -15
- package/dist/errors.js +18 -6
- package/dist/errors.js.map +1 -1
- package/dist/generated/abi/ComputeEngineImplementation.d.ts +2 -3
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.cjs.map +1 -1
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.d.ts +2 -3
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.js.map +1 -1
- package/dist/generated/abi/DATFactoryImplementation.d.ts +2 -3
- package/dist/generated/abi/DATImplementation.d.ts +2 -3
- package/dist/generated/abi/DATPausableImplementation.d.ts +2 -3
- package/dist/generated/abi/DATVotesImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPPerformanceImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRegistryImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRegistryTreasuryImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRewardDeployerImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRewardDeployerTreasuryImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRewardSwapImplementation.d.ts +2 -3
- package/dist/generated/abi/DLPRootImplementation.d.ts +1 -3
- package/dist/generated/abi/DLPTreasuryImplementation.d.ts +2 -3
- package/dist/generated/abi/DataLiquidityPoolImplementation.d.ts +1 -3
- package/dist/generated/abi/DataPortabilityGranteesImplementation.d.ts +2 -3
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.ts +2 -3
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.js.map +1 -1
- package/dist/generated/abi/DataPortabilityServersImplementation.cjs.map +1 -1
- package/dist/generated/abi/DataPortabilityServersImplementation.d.ts +2 -3
- package/dist/generated/abi/DataPortabilityServersImplementation.js.map +1 -1
- package/dist/generated/abi/DataRefinerRegistryImplementation.d.ts +2 -3
- package/dist/generated/abi/DataRegistryImplementation.d.ts +2 -3
- package/dist/generated/abi/QueryEngineImplementation.d.ts +2 -3
- package/dist/generated/abi/SwapHelperImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolDedicatedGpuImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolDedicatedStandardImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolEphemeralStandardImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolPersistentGpuImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolPersistentStandardImplementation.d.ts +2 -3
- package/dist/generated/abi/TeePoolPhalaImplementation.d.ts +2 -3
- package/dist/generated/abi/VanaEpochImplementation.d.ts +2 -3
- package/dist/generated/abi/VanaPoolEntityImplementation.d.ts +2 -3
- package/dist/generated/abi/VanaPoolStakingImplementation.d.ts +2 -3
- package/dist/generated/abi/VanaPoolTreasuryImplementation.d.ts +2 -3
- package/dist/generated/abi/index.d.ts +37 -39
- package/dist/generated/event-types.d.ts +9 -10
- package/dist/generated/eventRegistry.d.ts +3 -7
- package/dist/generated/server/server-exports.d.ts +19 -21
- package/dist/generated/server/server.cjs.map +1 -1
- package/dist/generated/server/server.d.ts +113 -87
- package/dist/generated/subgraph.d.ts +329 -332
- package/dist/index.browser.d.ts +47 -96
- package/dist/index.browser.js +12 -0
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/index.node.cjs +9 -0
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.d.ts +181 -87
- package/dist/index.node.js +10 -0
- package/dist/index.node.js.map +1 -1
- package/dist/node.d.ts +4 -2
- package/dist/platform/browser-only.d.ts +5 -8
- package/dist/platform/browser-only.test.d.ts +1 -0
- package/dist/platform/browser-safe.d.ts +6 -9
- package/dist/platform/browser-safe.test.d.ts +1 -0
- package/dist/platform/browser.cjs +7 -6
- package/dist/platform/browser.cjs.map +1 -1
- package/dist/platform/browser.d.ts +3 -6
- package/dist/platform/browser.js +19 -27
- package/dist/platform/browser.js.map +1 -1
- package/dist/platform/browser.test.d.ts +1 -0
- package/dist/platform/index.d.ts +11 -5
- package/dist/platform/interface.d.ts +6 -8
- package/dist/platform/node.d.ts +3 -7
- package/dist/platform/node.js +12 -19
- package/dist/platform/node.js.map +1 -1
- package/dist/platform/ports/openpgp-port.cjs +74 -0
- package/dist/platform/ports/openpgp-port.cjs.map +1 -0
- package/dist/platform/ports/openpgp-port.d.ts +13 -0
- package/dist/platform/ports/openpgp-port.js +59 -0
- package/dist/platform/ports/openpgp-port.js.map +1 -0
- package/dist/platform/ports/pgp-port.cjs +17 -0
- package/dist/platform/ports/pgp-port.cjs.map +1 -0
- package/dist/platform/ports/pgp-port.d.ts +35 -0
- package/dist/platform/ports/pgp-port.js +1 -0
- package/dist/platform/ports/pgp-port.js.map +1 -0
- package/dist/platform/shared/error-utils.d.ts +2 -4
- package/dist/platform/shared/pgp-utils.cjs +2 -2
- package/dist/platform/shared/pgp-utils.cjs.map +1 -1
- package/dist/platform/shared/pgp-utils.d.ts +3 -5
- package/dist/platform/shared/pgp-utils.js +2 -2
- package/dist/platform/shared/pgp-utils.js.map +1 -1
- package/dist/platform/shared/stream-utils.d.ts +1 -3
- package/dist/platform/utils.d.ts +6 -10
- package/dist/platform/utils.test.d.ts +1 -0
- package/dist/platform.browser.d.ts +9 -4
- package/dist/platform.d.ts +11 -5
- package/dist/platform.node.d.ts +10 -5
- package/dist/server/handler.cjs.map +1 -1
- package/dist/server/handler.d.ts +8 -227
- package/dist/server/handler.js.map +1 -1
- package/dist/storage/index.d.ts +56 -10
- package/dist/storage/manager.cjs +2 -2
- package/dist/storage/manager.cjs.map +1 -1
- package/dist/storage/manager.d.ts +2 -5
- package/dist/storage/manager.js +5 -12
- package/dist/storage/manager.js.map +1 -1
- package/dist/storage/providers/callback-storage.cjs +3 -3
- package/dist/storage/providers/callback-storage.cjs.map +1 -1
- package/dist/storage/providers/callback-storage.d.ts +3 -9
- package/dist/storage/providers/callback-storage.js +3 -3
- package/dist/storage/providers/callback-storage.js.map +1 -1
- package/dist/storage/providers/google-drive.cjs +2 -2
- package/dist/storage/providers/google-drive.cjs.map +1 -1
- package/dist/storage/providers/google-drive.d.ts +3 -7
- package/dist/storage/providers/google-drive.js +4 -7
- package/dist/storage/providers/google-drive.js.map +1 -1
- package/dist/storage/providers/google-drive.test.d.ts +1 -0
- package/dist/storage/providers/ipfs.cjs +5 -5
- package/dist/storage/providers/ipfs.cjs.map +1 -1
- package/dist/storage/providers/ipfs.d.ts +3 -6
- package/dist/storage/providers/ipfs.js +7 -10
- package/dist/storage/providers/ipfs.js.map +1 -1
- package/dist/storage/providers/pinata.cjs +6 -6
- package/dist/storage/providers/pinata.cjs.map +1 -1
- package/dist/storage/providers/pinata.d.ts +5 -8
- package/dist/storage/providers/pinata.js +8 -11
- package/dist/storage/providers/pinata.js.map +1 -1
- package/dist/storage/tests/callbackStorage.test.d.ts +1 -0
- package/dist/storage/tests/googleDriveStorage.test.d.ts +1 -0
- package/dist/storage/tests/ipfsStorage.test.d.ts +1 -0
- package/dist/storage/tests/pinataStorage.test.d.ts +1 -0
- package/dist/storage/tests/storageManager.test.d.ts +1 -0
- package/dist/tests/abi.test.d.ts +1 -0
- package/dist/tests/chains-definitions.test.d.ts +1 -0
- package/dist/tests/core-encryption.test.d.ts +1 -0
- package/dist/tests/core-extended.test.d.ts +1 -0
- package/dist/tests/core-generics-coverage.test.d.ts +1 -0
- package/dist/tests/coverage-boost.test.d.ts +1 -0
- package/dist/tests/crypto-cross-platform-compatibility.test.d.ts +1 -0
- package/dist/tests/data-addfile-permissions-schema.test.d.ts +1 -0
- package/dist/tests/data-additional-methods.test.d.ts +1 -0
- package/dist/tests/data-controller-edge-cases.test.d.ts +1 -0
- package/dist/tests/data-ipfs-gateways.test.d.ts +1 -0
- package/dist/tests/data-relayer.test.d.ts +1 -0
- package/dist/tests/data-schema-validation.test.d.ts +1 -0
- package/dist/tests/data-simple-methods.test.d.ts +1 -0
- package/dist/tests/data.test.d.ts +1 -0
- package/dist/tests/demo-integration.test.d.ts +1 -0
- package/dist/tests/demo-trusted-server-integration.test.d.ts +1 -0
- package/dist/tests/download-relayer.test.d.ts +1 -0
- package/dist/tests/dual-mode-permissions.test.d.ts +1 -0
- package/dist/tests/dual-mode-trusted-servers.test.d.ts +1 -0
- package/dist/tests/encryption-correct-implementation.test.d.ts +1 -0
- package/dist/tests/encryption-coverage.test.d.ts +1 -0
- package/dist/tests/encryption-edge-cases.test.d.ts +1 -0
- package/dist/tests/encryption-utils-updated.test.d.ts +1 -0
- package/dist/tests/errors-coverage.test.d.ts +1 -0
- package/dist/tests/errors.test.d.ts +1 -0
- package/dist/tests/factories/mockFactory.d.ts +316 -0
- package/dist/tests/fakes/FakeStorageManager.d.ts +200 -0
- package/dist/tests/fakes/FakeStorageManager.test.d.ts +1 -0
- package/dist/tests/fakes/FakeWaitForTransactionEvents.d.ts +170 -0
- package/dist/tests/fakes/FakeWaitForTransactionEvents.test.d.ts +1 -0
- package/dist/tests/fakes/fake-pgp-port.d.ts +13 -0
- package/dist/tests/grantValidation-edge-cases.test.d.ts +1 -0
- package/dist/tests/grantValidation-unreachable-branch.test.d.ts +1 -0
- package/dist/tests/helper-methods.test.d.ts +1 -0
- package/dist/tests/helpers/platformTestHelpers.d.ts +106 -0
- package/dist/tests/helpers/typedMocks.d.ts +64 -0
- package/dist/tests/index-browser.test.d.ts +1 -0
- package/dist/tests/index-node.test.d.ts +1 -0
- package/dist/tests/index.test.d.ts +1 -0
- package/dist/tests/mocks/platformAdapter.d.ts +12 -0
- package/dist/tests/new-permissions-methods.test.d.ts +1 -0
- package/dist/tests/no-buffer-browser.test.d.ts +1 -0
- package/dist/tests/permissions-grantee.test.d.ts +1 -0
- package/dist/tests/permissions-schema-validation.test.d.ts +1 -0
- package/dist/tests/permissions-server-files.test.d.ts +1 -0
- package/dist/tests/permissions-trust-servers.test.d.ts +1 -0
- package/dist/tests/permissions.test.d.ts +1 -0
- package/dist/tests/personal.test.d.ts +1 -0
- package/dist/tests/platform-browser.test.d.ts +1 -0
- package/dist/tests/platform-crypto-expanded.test.d.ts +1 -0
- package/dist/tests/platform-crypto.test.d.ts +1 -0
- package/dist/tests/platform-index.test.d.ts +1 -0
- package/dist/tests/platform-node.test.d.ts +1 -0
- package/dist/tests/platform-shared-utils.test.d.ts +1 -0
- package/dist/tests/platform-updated.test.d.ts +1 -0
- package/dist/tests/protocol-additional-methods.test.d.ts +1 -0
- package/dist/tests/protocol.test.d.ts +1 -0
- package/dist/tests/read-only-mode.test.d.ts +1 -0
- package/dist/tests/schemas.test.d.ts +1 -0
- package/dist/tests/server-handler.test.d.ts +1 -0
- package/dist/tests/setup.d.ts +7 -0
- package/dist/tests/signatureFormatter.test.d.ts +1 -0
- package/dist/tests/trusted-server-queries.test.d.ts +1 -0
- package/dist/tests/typedDataConverter.test.d.ts +1 -0
- package/dist/tests/types-contracts.test.d.ts +1 -0
- package/dist/tests/types-data.test.d.ts +1 -0
- package/dist/tests/types-external-apis.test.d.ts +1 -0
- package/dist/tests/types-generics.test.d.ts +1 -0
- package/dist/tests/types-permissions.test.d.ts +1 -0
- package/dist/tests/types-upload-params.test.d.ts +1 -0
- package/dist/tests/types.test.d.ts +1 -0
- package/dist/tests/utils-formatters.test.d.ts +1 -0
- package/dist/tests/utils-grantFiles-edge-cases.test.d.ts +1 -0
- package/dist/tests/utils-grantFiles-validation.test.d.ts +1 -0
- package/dist/tests/utils-grantFiles.test.d.ts +1 -0
- package/dist/tests/utils-grantValidation-consolidated.test.d.ts +1 -0
- package/dist/tests/utils-grants.test.d.ts +1 -0
- package/dist/tests/utils-ipfs-additional.test.d.ts +1 -0
- package/dist/tests/utils-ipfs.test.d.ts +4 -0
- package/dist/tests/utils-schemaValidation.test.d.ts +1 -0
- package/dist/tests/vana.test.d.ts +1 -0
- package/dist/tests/wallet-crypto-compatibility.test.d.ts +1 -0
- package/dist/types/blockchain.cjs.map +1 -1
- package/dist/types/blockchain.d.ts +13 -8
- package/dist/types/chains-additional.test.d.ts +1 -0
- package/dist/types/chains.d.ts +6 -9
- package/dist/types/config.cjs +10 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.ts +161 -54
- package/dist/types/config.js +8 -0
- package/dist/types/config.js.map +1 -1
- package/dist/types/contracts.cjs.map +1 -1
- package/dist/types/contracts.d.ts +8 -11
- package/dist/types/controller-context.cjs.map +1 -1
- package/dist/types/controller-context.d.ts +13 -20
- package/dist/types/data.cjs.map +1 -1
- package/dist/types/data.d.ts +107 -39
- package/dist/types/external-apis.d.ts +10 -12
- package/dist/types/generics.d.ts +35 -38
- package/dist/types/index.cjs +5 -4
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.ts +20 -22
- package/dist/types/index.js +9 -2
- package/dist/types/index.js.map +1 -1
- package/dist/types/operations.cjs +2 -2
- package/dist/types/operations.cjs.map +1 -1
- package/dist/types/operations.d.ts +13 -17
- package/dist/types/operations.js +2 -2
- package/dist/types/operations.js.map +1 -1
- package/dist/types/permissions.d.ts +55 -58
- package/dist/types/personal.cjs.map +1 -1
- package/dist/types/personal.d.ts +6 -8
- package/dist/types/relayer.d.ts +15 -18
- package/dist/types/storage.d.ts +6 -8
- package/dist/types/storage.js +2 -5
- package/dist/types/storage.js.map +1 -1
- package/dist/types/transactionResults.d.ts +16 -18
- package/dist/types/utils.d.ts +21 -24
- package/dist/types.d.ts +4 -28
- package/dist/utils/__tests__/parseTransaction.test.d.ts +1 -0
- package/dist/utils/__tests__/pojo-serialization.test.d.ts +1 -0
- package/dist/utils/__tests__/signatureCache.test.d.ts +1 -0
- package/dist/utils/__tests__/transaction-edge-cases.test.d.ts +1 -0
- package/dist/utils/__tests__/transactionHelpers.test.d.ts +1 -0
- package/dist/utils/__tests__/urlResolver.test.d.ts +4 -0
- package/dist/utils/blockchain/registry.cjs +2 -2
- package/dist/utils/blockchain/registry.cjs.map +1 -1
- package/dist/utils/blockchain/registry.d.ts +6 -8
- package/dist/utils/blockchain/registry.js +2 -2
- package/dist/utils/blockchain/registry.js.map +1 -1
- package/dist/utils/blockchain/registry.test.d.ts +1 -0
- package/dist/utils/crypto-utils.cjs +0 -12
- package/dist/utils/crypto-utils.cjs.map +1 -1
- package/dist/utils/crypto-utils.d.ts +9 -27
- package/dist/utils/crypto-utils.js +0 -11
- package/dist/utils/crypto-utils.js.map +1 -1
- package/dist/utils/crypto-utils.test.d.ts +1 -0
- package/dist/utils/download.cjs +3 -3
- package/dist/utils/download.cjs.map +1 -1
- package/dist/utils/download.d.ts +13 -14
- package/dist/utils/download.js +2 -2
- package/dist/utils/download.js.map +1 -1
- package/dist/utils/encoding.cjs +1 -1
- package/dist/utils/encoding.cjs.map +1 -1
- package/dist/utils/encoding.d.ts +4 -6
- package/dist/utils/encoding.js +1 -1
- package/dist/utils/encoding.js.map +1 -1
- package/dist/utils/encoding.test.d.ts +1 -0
- package/dist/utils/encryption.cjs +16 -10
- package/dist/utils/encryption.cjs.map +1 -1
- package/dist/utils/encryption.d.ts +13 -17
- package/dist/utils/encryption.js +16 -10
- package/dist/utils/encryption.js.map +1 -1
- package/dist/utils/formatters.cjs +4 -2
- package/dist/utils/formatters.cjs.map +1 -1
- package/dist/utils/formatters.d.ts +4 -6
- package/dist/utils/formatters.js +4 -2
- package/dist/utils/formatters.js.map +1 -1
- package/dist/utils/grantFiles.cjs +7 -4
- package/dist/utils/grantFiles.cjs.map +1 -1
- package/dist/utils/grantFiles.d.ts +6 -10
- package/dist/utils/grantFiles.js +7 -4
- package/dist/utils/grantFiles.js.map +1 -1
- package/dist/utils/grantValidation.cjs +1 -1
- package/dist/utils/grantValidation.cjs.map +1 -1
- package/dist/utils/grantValidation.d.ts +14 -17
- package/dist/utils/grantValidation.js +1 -1
- package/dist/utils/grantValidation.js.map +1 -1
- package/dist/utils/grants.cjs +1 -1
- package/dist/utils/grants.cjs.map +1 -1
- package/dist/utils/grants.d.ts +10 -13
- package/dist/utils/grants.js +1 -1
- package/dist/utils/grants.js.map +1 -1
- package/dist/utils/ipfs.d.ts +8 -10
- package/dist/utils/lazy-import.cjs +4 -6
- package/dist/utils/lazy-import.cjs.map +1 -1
- package/dist/utils/lazy-import.d.ts +1 -3
- package/dist/utils/lazy-import.js +4 -6
- package/dist/utils/lazy-import.js.map +1 -1
- package/dist/utils/multicall.cjs +4 -2
- package/dist/utils/multicall.cjs.map +1 -1
- package/dist/utils/multicall.d.ts +5 -8
- package/dist/utils/multicall.js +4 -2
- package/dist/utils/multicall.js.map +1 -1
- package/dist/utils/parseTransactionPojo.cjs.map +1 -1
- package/dist/utils/parseTransactionPojo.d.ts +4 -10
- package/dist/utils/parseTransactionPojo.js.map +1 -1
- package/dist/utils/schemaValidation.cjs +5 -5
- package/dist/utils/schemaValidation.cjs.map +1 -1
- package/dist/utils/schemaValidation.d.ts +8 -12
- package/dist/utils/schemaValidation.js +7 -10
- package/dist/utils/schemaValidation.js.map +1 -1
- package/dist/utils/signatureCache.cjs +1 -2
- package/dist/utils/signatureCache.cjs.map +1 -1
- package/dist/utils/signatureCache.d.ts +4 -7
- package/dist/utils/signatureCache.js +4 -8
- package/dist/utils/signatureCache.js.map +1 -1
- package/dist/utils/signatureFormatter.cjs +6 -9
- package/dist/utils/signatureFormatter.cjs.map +1 -1
- package/dist/utils/signatureFormatter.d.ts +2 -5
- package/dist/utils/signatureFormatter.js +6 -9
- package/dist/utils/signatureFormatter.js.map +1 -1
- package/dist/utils/tests/multicall.test.d.ts +1 -0
- package/dist/utils/transactionHelpers.cjs.map +1 -1
- package/dist/utils/transactionHelpers.d.ts +5 -11
- package/dist/utils/transactionHelpers.js.map +1 -1
- package/dist/utils/typeGuards.cjs +109 -0
- package/dist/utils/typeGuards.cjs.map +1 -0
- package/dist/utils/typeGuards.d.ts +138 -0
- package/dist/utils/typeGuards.js +74 -0
- package/dist/utils/typeGuards.js.map +1 -0
- package/dist/utils/typedDataConverter.d.ts +3 -6
- package/dist/utils/urlResolver.cjs +1 -1
- package/dist/utils/urlResolver.cjs.map +1 -1
- package/dist/utils/urlResolver.d.ts +2 -4
- package/dist/utils/urlResolver.js +2 -2
- package/dist/utils/urlResolver.js.map +1 -1
- package/dist/utils/wallet.cjs +62 -0
- package/dist/utils/wallet.cjs.map +1 -0
- package/dist/utils/wallet.d.ts +32 -0
- package/dist/utils/wallet.js +36 -0
- package/dist/utils/wallet.js.map +1 -0
- package/dist/utils/withEvents.cjs.map +1 -1
- package/dist/utils/withEvents.d.ts +5 -12
- package/dist/utils/withEvents.js.map +1 -1
- package/package.json +22 -16
- package/dist/browser.d.cts +0 -2
- package/dist/chains/definitions.d.cts +0 -53
- package/dist/chains/index.d.cts +0 -2
- package/dist/chains.browser.cjs +0 -37
- package/dist/chains.browser.cjs.map +0 -1
- package/dist/chains.browser.d.cts +0 -2
- package/dist/chains.d.cts +0 -2
- package/dist/chains.node.d.cts +0 -2
- package/dist/config/addresses.d.cts +0 -401
- package/dist/config/chains.d.cts +0 -85
- package/dist/config/features.d.cts +0 -64
- package/dist/contracts/contractController.d.cts +0 -117
- package/dist/controllers/data.d.cts +0 -915
- package/dist/controllers/permissions.d.cts +0 -1383
- package/dist/controllers/protocol.d.cts +0 -188
- package/dist/controllers/schemas.d.cts +0 -260
- package/dist/controllers/server.d.cts +0 -230
- package/dist/core/apiClient.d.cts +0 -165
- package/dist/core/client.d.cts +0 -92
- package/dist/core/generics.d.cts +0 -120
- package/dist/core.d.cts +0 -493
- package/dist/crypto/ecies/__tests__/test-vectors.d.cts +0 -40
- package/dist/crypto/ecies/base.d.cts +0 -143
- package/dist/crypto/ecies/browser.d.cts +0 -48
- package/dist/crypto/ecies/constants.d.cts +0 -122
- package/dist/crypto/ecies/index.d.cts +0 -1
- package/dist/crypto/ecies/interface.d.cts +0 -176
- package/dist/crypto/ecies/node.d.cts +0 -50
- package/dist/crypto/ecies/test-vectors/eccrypto-vectors.d.cts +0 -76
- package/dist/crypto/ecies/test-vectors/eccrypto-vectors.d.ts +0 -76
- package/dist/crypto/ecies/utils.d.cts +0 -67
- package/dist/crypto/services/WalletKeyEncryptionService.d.cts +0 -92
- package/dist/diagnostics.d.cts +0 -26
- package/dist/errors.d.cts +0 -350
- package/dist/generated/abi/ComputeEngineImplementation.d.cts +0 -996
- package/dist/generated/abi/ComputeInstructionRegistryImplementation.d.cts +0 -545
- package/dist/generated/abi/DATFactoryImplementation.d.cts +0 -661
- package/dist/generated/abi/DATImplementation.d.cts +0 -693
- package/dist/generated/abi/DATPausableImplementation.d.cts +0 -1145
- package/dist/generated/abi/DATVotesImplementation.d.cts +0 -1095
- package/dist/generated/abi/DLPPerformanceImplementation.d.cts +0 -883
- package/dist/generated/abi/DLPRegistryImplementation.d.cts +0 -1123
- package/dist/generated/abi/DLPRegistryTreasuryImplementation.d.cts +0 -452
- package/dist/generated/abi/DLPRewardDeployerImplementation.d.cts +0 -714
- package/dist/generated/abi/DLPRewardDeployerTreasuryImplementation.d.cts +0 -452
- package/dist/generated/abi/DLPRewardSwapImplementation.d.cts +0 -706
- package/dist/generated/abi/DLPRootImplementation.d.cts +0 -1248
- package/dist/generated/abi/DLPTreasuryImplementation.d.cts +0 -452
- package/dist/generated/abi/DataLiquidityPoolImplementation.d.cts +0 -737
- package/dist/generated/abi/DataPortabilityGranteesImplementation.d.cts +0 -661
- package/dist/generated/abi/DataPortabilityPermissionsImplementation.d.cts +0 -989
- package/dist/generated/abi/DataPortabilityServersImplementation.d.cts +0 -1086
- package/dist/generated/abi/DataRefinerRegistryImplementation.d.cts +0 -737
- package/dist/generated/abi/DataRegistryImplementation.d.cts +0 -1014
- package/dist/generated/abi/QueryEngineImplementation.d.cts +0 -1001
- package/dist/generated/abi/SwapHelperImplementation.d.cts +0 -764
- package/dist/generated/abi/TeePoolDedicatedGpuImplementation.d.cts +0 -701
- package/dist/generated/abi/TeePoolDedicatedStandardImplementation.d.cts +0 -701
- package/dist/generated/abi/TeePoolEphemeralStandardImplementation.d.cts +0 -701
- package/dist/generated/abi/TeePoolImplementation.d.cts +0 -993
- package/dist/generated/abi/TeePoolPersistentGpuImplementation.d.cts +0 -701
- package/dist/generated/abi/TeePoolPersistentStandardImplementation.d.cts +0 -701
- package/dist/generated/abi/TeePoolPhalaImplementation.d.cts +0 -993
- package/dist/generated/abi/VanaEpochImplementation.d.cts +0 -900
- package/dist/generated/abi/VanaPoolEntityImplementation.d.cts +0 -934
- package/dist/generated/abi/VanaPoolStakingImplementation.d.cts +0 -693
- package/dist/generated/abi/VanaPoolTreasuryImplementation.d.cts +0 -394
- package/dist/generated/abi/index.d.cts +0 -26547
- package/dist/generated/event-types.d.cts +0 -855
- package/dist/generated/eventRegistry.d.cts +0 -18
- package/dist/generated/server/server-exports.d.cts +0 -21
- package/dist/generated/server/server.d.cts +0 -512
- package/dist/generated/subgraph.d.cts +0 -5981
- package/dist/index.browser.cjs +0 -151
- package/dist/index.browser.cjs.map +0 -1
- package/dist/index.browser.d.cts +0 -201
- package/dist/index.d.cts +0 -2
- package/dist/index.node.d.cts +0 -87
- package/dist/node.d.cts +0 -2
- package/dist/platform/browser-only.d.cts +0 -25
- package/dist/platform/browser-safe.d.cts +0 -32
- package/dist/platform/browser.d.cts +0 -74
- package/dist/platform/index.d.cts +0 -5
- package/dist/platform/interface.d.cts +0 -218
- package/dist/platform/node.d.cts +0 -27
- package/dist/platform/shared/error-utils.d.cts +0 -25
- package/dist/platform/shared/pgp-utils.d.cts +0 -61
- package/dist/platform/shared/stream-utils.d.cts +0 -16
- package/dist/platform/utils.d.cts +0 -53
- package/dist/platform.browser.cjs +0 -41
- package/dist/platform.browser.cjs.map +0 -1
- package/dist/platform.browser.d.cts +0 -4
- package/dist/platform.d.cts +0 -5
- package/dist/platform.node.d.cts +0 -5
- package/dist/schemas/dataSchema.schema.d.cts +0 -88
- package/dist/schemas/dataSchema.schema.d.ts +0 -88
- package/dist/schemas/grantFile.schema.d.cts +0 -57
- package/dist/schemas/grantFile.schema.d.ts +0 -57
- package/dist/server/handler.d.cts +0 -306
- package/dist/storage/index.d.cts +0 -10
- package/dist/storage/manager.d.cts +0 -150
- package/dist/storage/providers/callback-storage.d.cts +0 -100
- package/dist/storage/providers/google-drive.d.cts +0 -156
- package/dist/storage/providers/ipfs.d.cts +0 -163
- package/dist/storage/providers/pinata.d.cts +0 -173
- package/dist/types/blockchain.d.cts +0 -52
- package/dist/types/chains.d.cts +0 -34
- package/dist/types/config.d.cts +0 -726
- package/dist/types/contracts.d.cts +0 -68
- package/dist/types/controller-context.d.cts +0 -71
- package/dist/types/data.d.cts +0 -694
- package/dist/types/eccrypto-js.d.d.cts +0 -13
- package/dist/types/eccrypto-js.d.d.ts +0 -13
- package/dist/types/external-apis.d.cts +0 -186
- package/dist/types/generics.d.cts +0 -450
- package/dist/types/index.d.cts +0 -22
- package/dist/types/operations.d.cts +0 -116
- package/dist/types/permissions.d.cts +0 -957
- package/dist/types/personal.d.cts +0 -40
- package/dist/types/relayer.d.cts +0 -284
- package/dist/types/storage.d.cts +0 -131
- package/dist/types/transactionResults.d.cts +0 -195
- package/dist/types/utils.d.cts +0 -819
- package/dist/types.d.cts +0 -54
- package/dist/utils/blockchain/registry.d.cts +0 -34
- package/dist/utils/crypto-utils.d.cts +0 -118
- package/dist/utils/download.d.cts +0 -41
- package/dist/utils/encoding.d.cts +0 -54
- package/dist/utils/encryption.d.cts +0 -275
- package/dist/utils/formatters.d.cts +0 -120
- package/dist/utils/grantFiles.d.cts +0 -186
- package/dist/utils/grantValidation.d.cts +0 -150
- package/dist/utils/grants.d.cts +0 -70
- package/dist/utils/ipfs.d.cts +0 -90
- package/dist/utils/lazy-import.d.cts +0 -20
- package/dist/utils/multicall.d.cts +0 -129
- package/dist/utils/parseTransactionPojo.d.cts +0 -37
- package/dist/utils/schemaValidation.d.cts +0 -172
- package/dist/utils/signatureCache.d.cts +0 -134
- package/dist/utils/signatureFormatter.d.cts +0 -39
- package/dist/utils/transactionHelpers.d.cts +0 -86
- package/dist/utils/typedDataConverter.d.cts +0 -13
- package/dist/utils/urlResolver.d.cts +0 -40
- package/dist/utils/withEvents.d.cts +0 -63
package/dist/utils/grants.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { Address } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { GrantFile, GrantPermissionParams } from "../types/permissions";
|
|
4
3
|
/**
|
|
5
4
|
* High-level utilities for working with grants in the Vana SDK
|
|
6
5
|
*/
|
|
@@ -10,7 +9,7 @@ import { GrantPermissionParams, GrantFile } from '../types/permissions.js';
|
|
|
10
9
|
* @param params - The permission parameters to create and validate the grant from
|
|
11
10
|
* @returns The validated grant file object
|
|
12
11
|
*/
|
|
13
|
-
declare function createValidatedGrant(params: GrantPermissionParams): GrantFile;
|
|
12
|
+
export declare function createValidatedGrant(params: GrantPermissionParams): GrantFile;
|
|
14
13
|
/**
|
|
15
14
|
* Creates a grant file and stores it in IPFS
|
|
16
15
|
*
|
|
@@ -18,7 +17,7 @@ declare function createValidatedGrant(params: GrantPermissionParams): GrantFile;
|
|
|
18
17
|
* @param relayerUrl - The URL of the relayer service for IPFS storage
|
|
19
18
|
* @returns Promise resolving to an object containing the grant file and its IPFS URL
|
|
20
19
|
*/
|
|
21
|
-
declare function createAndStoreGrant(params: GrantPermissionParams, relayerUrl: string): Promise<{
|
|
20
|
+
export declare function createAndStoreGrant(params: GrantPermissionParams, relayerUrl: string): Promise<{
|
|
22
21
|
grantFile: GrantFile;
|
|
23
22
|
grantUrl: string;
|
|
24
23
|
}>;
|
|
@@ -29,18 +28,18 @@ declare function createAndStoreGrant(params: GrantPermissionParams, relayerUrl:
|
|
|
29
28
|
* @param relayerUrl - Optional URL of the relayer service
|
|
30
29
|
* @returns Promise resolving to the validated grant file
|
|
31
30
|
*/
|
|
32
|
-
declare function retrieveAndValidateGrant(grantUrl: string, relayerUrl?: string): Promise<GrantFile>;
|
|
31
|
+
export declare function retrieveAndValidateGrant(grantUrl: string, relayerUrl?: string): Promise<GrantFile>;
|
|
33
32
|
/**
|
|
34
33
|
* Checks if a grant allows access for a specific request
|
|
35
34
|
*
|
|
36
35
|
* @param grantUrl - The IPFS URL of the grant file to check
|
|
37
36
|
* @param requestingAddress - The address making the access request
|
|
38
37
|
* @param operation - The operation being requested
|
|
39
|
-
* @param
|
|
38
|
+
* @param _fileIds - Array of file IDs being accessed (currently unused but part of interface)
|
|
40
39
|
* @param relayerUrl - Optional URL of the relayer service
|
|
41
40
|
* @returns Promise resolving to access result with allowed status, reason, and grant file
|
|
42
41
|
*/
|
|
43
|
-
declare function checkGrantAccess(grantUrl: string, requestingAddress: Address, operation: string,
|
|
42
|
+
export declare function checkGrantAccess(grantUrl: string, requestingAddress: Address, operation: string, _fileIds: number[], relayerUrl?: string): Promise<{
|
|
44
43
|
allowed: boolean;
|
|
45
44
|
reason?: string;
|
|
46
45
|
grantFile?: GrantFile;
|
|
@@ -51,20 +50,18 @@ declare function checkGrantAccess(grantUrl: string, requestingAddress: Address,
|
|
|
51
50
|
* @param grantFile - The grant file to check for expiration
|
|
52
51
|
* @returns True if the grant has expired, false otherwise
|
|
53
52
|
*/
|
|
54
|
-
declare function isGrantExpired(grantFile: GrantFile): boolean;
|
|
53
|
+
export declare function isGrantExpired(grantFile: GrantFile): boolean;
|
|
55
54
|
/**
|
|
56
55
|
* Utility to get the time remaining before grant expires (in seconds)
|
|
57
56
|
*
|
|
58
57
|
* @param grantFile - The grant file to check time remaining for
|
|
59
58
|
* @returns Number of seconds remaining, or null if no expiration is set
|
|
60
59
|
*/
|
|
61
|
-
declare function getGrantTimeRemaining(grantFile: GrantFile): number | null;
|
|
60
|
+
export declare function getGrantTimeRemaining(grantFile: GrantFile): number | null;
|
|
62
61
|
/**
|
|
63
62
|
* Creates a human-readable summary of a grant
|
|
64
63
|
*
|
|
65
64
|
* @param grantFile - The grant file to create a summary for
|
|
66
65
|
* @returns A human-readable string describing the grant
|
|
67
66
|
*/
|
|
68
|
-
declare function summarizeGrant(grantFile: GrantFile): string;
|
|
69
|
-
|
|
70
|
-
export { checkGrantAccess, createAndStoreGrant, createValidatedGrant, getGrantTimeRemaining, isGrantExpired, retrieveAndValidateGrant, summarizeGrant };
|
|
67
|
+
export declare function summarizeGrant(grantFile: GrantFile): string;
|
package/dist/utils/grants.js
CHANGED
|
@@ -29,7 +29,7 @@ async function retrieveAndValidateGrant(grantUrl, relayerUrl) {
|
|
|
29
29
|
const grantFile = await retrieveGrantFile(grantUrl, relayerUrl);
|
|
30
30
|
return grantFile;
|
|
31
31
|
}
|
|
32
|
-
async function checkGrantAccess(grantUrl, requestingAddress, operation,
|
|
32
|
+
async function checkGrantAccess(grantUrl, requestingAddress, operation, _fileIds, relayerUrl) {
|
|
33
33
|
try {
|
|
34
34
|
const grantFile = await retrieveAndValidateGrant(grantUrl, relayerUrl);
|
|
35
35
|
validateGrant(grantFile, {
|
package/dist/utils/grants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/grants.ts"],"sourcesContent":["import { Address } from \"viem\";\nimport type { GrantFile, GrantPermissionParams } from \"../types/permissions\";\nimport {\n createGrantFile,\n storeGrantFile,\n retrieveGrantFile,\n} from \"./grantFiles\";\nimport { validateGrant, GrantValidationError } from \"./grantValidation\";\n\n/**\n * High-level utilities for working with grants in the Vana SDK\n */\n\n/**\n * Creates and validates a grant file from permission parameters\n *\n * @param params - The permission parameters to create and validate the grant from\n * @returns The validated grant file object\n */\nexport function createValidatedGrant(params: GrantPermissionParams): GrantFile {\n const grantFile = createGrantFile(params);\n\n // Validate the created grant file\n try {\n validateGrant(grantFile, {\n schema: true,\n grantee: params.grantee,\n operation: params.operation,\n });\n } catch (error) {\n throw new GrantValidationError(\n `Created grant file failed validation: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n { grantFile, params },\n );\n }\n\n return grantFile;\n}\n\n/**\n * Creates a grant file and stores it in IPFS\n *\n * @param params - The permission parameters to create the grant from\n * @param relayerUrl - The URL of the relayer service for IPFS storage\n * @returns Promise resolving to an object containing the grant file and its IPFS URL\n */\nexport async function createAndStoreGrant(\n params: GrantPermissionParams,\n relayerUrl: string,\n): Promise<{ grantFile: GrantFile; grantUrl: string }> {\n const grantFile = createValidatedGrant(params);\n const grantUrl = await storeGrantFile(grantFile, relayerUrl);\n\n return { grantFile, grantUrl };\n}\n\n/**\n * Retrieves and validates a grant file from IPFS\n *\n * @param grantUrl - The IPFS URL of the grant file to retrieve\n * @param relayerUrl - Optional URL of the relayer service\n * @returns Promise resolving to the validated grant file\n */\nexport async function retrieveAndValidateGrant(\n grantUrl: string,\n relayerUrl?: string,\n): Promise<GrantFile> {\n const grantFile = await retrieveGrantFile(grantUrl, relayerUrl);\n\n // Additional validation can be added here if needed\n return grantFile;\n}\n\n/**\n * Checks if a grant allows access for a specific request\n *\n * @param grantUrl - The IPFS URL of the grant file to check\n * @param requestingAddress - The address making the access request\n * @param operation - The operation being requested\n * @param
|
|
1
|
+
{"version":3,"sources":["../../src/utils/grants.ts"],"sourcesContent":["import type { Address } from \"viem\";\nimport type { GrantFile, GrantPermissionParams } from \"../types/permissions\";\nimport {\n createGrantFile,\n storeGrantFile,\n retrieveGrantFile,\n} from \"./grantFiles\";\nimport { validateGrant, GrantValidationError } from \"./grantValidation\";\n\n/**\n * High-level utilities for working with grants in the Vana SDK\n */\n\n/**\n * Creates and validates a grant file from permission parameters\n *\n * @param params - The permission parameters to create and validate the grant from\n * @returns The validated grant file object\n */\nexport function createValidatedGrant(params: GrantPermissionParams): GrantFile {\n const grantFile = createGrantFile(params);\n\n // Validate the created grant file\n try {\n validateGrant(grantFile, {\n schema: true,\n grantee: params.grantee,\n operation: params.operation,\n });\n } catch (error) {\n throw new GrantValidationError(\n `Created grant file failed validation: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n { grantFile, params },\n );\n }\n\n return grantFile;\n}\n\n/**\n * Creates a grant file and stores it in IPFS\n *\n * @param params - The permission parameters to create the grant from\n * @param relayerUrl - The URL of the relayer service for IPFS storage\n * @returns Promise resolving to an object containing the grant file and its IPFS URL\n */\nexport async function createAndStoreGrant(\n params: GrantPermissionParams,\n relayerUrl: string,\n): Promise<{ grantFile: GrantFile; grantUrl: string }> {\n const grantFile = createValidatedGrant(params);\n const grantUrl = await storeGrantFile(grantFile, relayerUrl);\n\n return { grantFile, grantUrl };\n}\n\n/**\n * Retrieves and validates a grant file from IPFS\n *\n * @param grantUrl - The IPFS URL of the grant file to retrieve\n * @param relayerUrl - Optional URL of the relayer service\n * @returns Promise resolving to the validated grant file\n */\nexport async function retrieveAndValidateGrant(\n grantUrl: string,\n relayerUrl?: string,\n): Promise<GrantFile> {\n const grantFile = await retrieveGrantFile(grantUrl, relayerUrl);\n\n // Additional validation can be added here if needed\n return grantFile;\n}\n\n/**\n * Checks if a grant allows access for a specific request\n *\n * @param grantUrl - The IPFS URL of the grant file to check\n * @param requestingAddress - The address making the access request\n * @param operation - The operation being requested\n * @param _fileIds - Array of file IDs being accessed (currently unused but part of interface)\n * @param relayerUrl - Optional URL of the relayer service\n * @returns Promise resolving to access result with allowed status, reason, and grant file\n */\nexport async function checkGrantAccess(\n grantUrl: string,\n requestingAddress: Address,\n operation: string,\n _fileIds: number[],\n relayerUrl?: string,\n): Promise<{ allowed: boolean; reason?: string; grantFile?: GrantFile }> {\n try {\n const grantFile = await retrieveAndValidateGrant(grantUrl, relayerUrl);\n\n // Validate the grant for the request\n validateGrant(grantFile, {\n schema: true,\n grantee: requestingAddress,\n operation,\n });\n\n return { allowed: true, grantFile };\n } catch (error) {\n if (error instanceof GrantValidationError) {\n return {\n allowed: false,\n reason: error.message,\n };\n }\n\n return {\n allowed: false,\n reason: `Grant access check failed: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n };\n }\n}\n\n/**\n * Utility to check if a grant has expired\n *\n * @param grantFile - The grant file to check for expiration\n * @returns True if the grant has expired, false otherwise\n */\nexport function isGrantExpired(grantFile: GrantFile): boolean {\n if (!grantFile.expires) {\n return false; // No expiration set\n }\n\n const now = Math.floor(Date.now() / 1000);\n return now > grantFile.expires;\n}\n\n/**\n * Utility to get the time remaining before grant expires (in seconds)\n *\n * @param grantFile - The grant file to check time remaining for\n * @returns Number of seconds remaining, or null if no expiration is set\n */\nexport function getGrantTimeRemaining(grantFile: GrantFile): number | null {\n if (!grantFile.expires) {\n return null; // No expiration set\n }\n\n const now = Math.floor(Date.now() / 1000);\n const remaining = grantFile.expires - now;\n return Math.max(0, remaining);\n}\n\n/**\n * Creates a human-readable summary of a grant\n *\n * @param grantFile - The grant file to create a summary for\n * @returns A human-readable string describing the grant\n */\nexport function summarizeGrant(grantFile: GrantFile): string {\n const expiration = grantFile.expires\n ? new Date(grantFile.expires * 1000).toISOString()\n : \"No expiration\";\n\n return `Grant for ${grantFile.grantee} to perform \"${grantFile.operation}\" (expires: ${expiration})`;\n}\n"],"mappings":"AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,eAAe,4BAA4B;AAY7C,SAAS,qBAAqB,QAA0C;AAC7E,QAAM,YAAY,gBAAgB,MAAM;AAGxC,MAAI;AACF,kBAAc,WAAW;AAAA,MACvB,QAAQ;AAAA,MACR,SAAS,OAAO;AAAA,MAChB,WAAW,OAAO;AAAA,IACpB,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,yCAAyC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACjG,EAAE,WAAW,OAAO;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,oBACpB,QACA,YACqD;AACrD,QAAM,YAAY,qBAAqB,MAAM;AAC7C,QAAM,WAAW,MAAM,eAAe,WAAW,UAAU;AAE3D,SAAO,EAAE,WAAW,SAAS;AAC/B;AASA,eAAsB,yBACpB,UACA,YACoB;AACpB,QAAM,YAAY,MAAM,kBAAkB,UAAU,UAAU;AAG9D,SAAO;AACT;AAYA,eAAsB,iBACpB,UACA,mBACA,WACA,UACA,YACuE;AACvE,MAAI;AACF,UAAM,YAAY,MAAM,yBAAyB,UAAU,UAAU;AAGrE,kBAAc,WAAW;AAAA,MACvB,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,IACF,CAAC;AAED,WAAO,EAAE,SAAS,MAAM,UAAU;AAAA,EACpC,SAAS,OAAO;AACd,QAAI,iBAAiB,sBAAsB;AACzC,aAAO;AAAA,QACL,SAAS;AAAA,QACT,QAAQ,MAAM;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ,8BAA8B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IAChG;AAAA,EACF;AACF;AAQO,SAAS,eAAe,WAA+B;AAC5D,MAAI,CAAC,UAAU,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,SAAO,MAAM,UAAU;AACzB;AAQO,SAAS,sBAAsB,WAAqC;AACzE,MAAI,CAAC,UAAU,SAAS;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,QAAM,YAAY,UAAU,UAAU;AACtC,SAAO,KAAK,IAAI,GAAG,SAAS;AAC9B;AAQO,SAAS,eAAe,WAA8B;AAC3D,QAAM,aAAa,UAAU,UACzB,IAAI,KAAK,UAAU,UAAU,GAAI,EAAE,YAAY,IAC/C;AAEJ,SAAO,aAAa,UAAU,OAAO,gBAAgB,UAAU,SAAS,eAAe,UAAU;AACnG;","names":[]}
|
package/dist/utils/ipfs.d.ts
CHANGED
|
@@ -7,18 +7,18 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* Default IPFS gateway URL
|
|
9
9
|
*/
|
|
10
|
-
declare const DEFAULT_IPFS_GATEWAY = "https://dweb.link/ipfs/";
|
|
10
|
+
export declare const DEFAULT_IPFS_GATEWAY = "https://dweb.link/ipfs/";
|
|
11
11
|
/**
|
|
12
12
|
* Alternative IPFS gateways for fallback - ordered by reliability and rate limits
|
|
13
13
|
*/
|
|
14
|
-
declare const IPFS_GATEWAYS: readonly ["https://dweb.link/ipfs/", "https://ipfs.io/ipfs/", "https://cloudflare-ipfs.com/ipfs/", "https://gateway.pinata.cloud/ipfs/", "https://ipfs.filebase.io/ipfs/"];
|
|
14
|
+
export declare const IPFS_GATEWAYS: readonly ["https://dweb.link/ipfs/", "https://ipfs.io/ipfs/", "https://cloudflare-ipfs.com/ipfs/", "https://gateway.pinata.cloud/ipfs/", "https://ipfs.filebase.io/ipfs/"];
|
|
15
15
|
/**
|
|
16
16
|
* Check if a URL is an IPFS URL (starts with ipfs://)
|
|
17
17
|
*
|
|
18
18
|
* @param url - The URL to check
|
|
19
19
|
* @returns True if the URL is an IPFS URL
|
|
20
20
|
*/
|
|
21
|
-
declare function isIpfsUrl(url: string): boolean;
|
|
21
|
+
export declare function isIpfsUrl(url: string): boolean;
|
|
22
22
|
/**
|
|
23
23
|
* Convert an IPFS URL to an HTTP gateway URL
|
|
24
24
|
*
|
|
@@ -34,7 +34,7 @@ declare function isIpfsUrl(url: string): boolean;
|
|
|
34
34
|
* // Returns: "https://gateway.pinata.cloud/ipfs/QmHash123"
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
declare function convertIpfsUrl(url: string, gateway?: string): string;
|
|
37
|
+
export declare function convertIpfsUrl(url: string, gateway?: string): string;
|
|
38
38
|
/**
|
|
39
39
|
* Extract IPFS hash from various URL formats
|
|
40
40
|
*
|
|
@@ -55,21 +55,21 @@ declare function convertIpfsUrl(url: string, gateway?: string): string;
|
|
|
55
55
|
* extractIpfsHash("ipfs://QmHash/subdirectory") // Returns: null (subdirectories not supported)
|
|
56
56
|
* ```
|
|
57
57
|
*/
|
|
58
|
-
declare function extractIpfsHash(url: string): string | null;
|
|
58
|
+
export declare function extractIpfsHash(url: string): string | null;
|
|
59
59
|
/**
|
|
60
60
|
* Get multiple gateway URLs for an IPFS hash (useful for fallback)
|
|
61
61
|
*
|
|
62
62
|
* @param hash - The IPFS hash
|
|
63
63
|
* @returns Array of gateway URLs
|
|
64
64
|
*/
|
|
65
|
-
declare function getGatewayUrls(hash: string): string[];
|
|
65
|
+
export declare function getGatewayUrls(hash: string): string[];
|
|
66
66
|
/**
|
|
67
67
|
* Convert an IPFS URL to multiple gateway URLs for fallback
|
|
68
68
|
*
|
|
69
69
|
* @param url - The IPFS URL
|
|
70
70
|
* @returns Array of gateway URLs or original URL if not IPFS
|
|
71
71
|
*/
|
|
72
|
-
declare function convertIpfsUrlWithFallbacks(url: string): string[];
|
|
72
|
+
export declare function convertIpfsUrlWithFallbacks(url: string): string[];
|
|
73
73
|
/**
|
|
74
74
|
* Fetch content from IPFS with automatic gateway fallbacks
|
|
75
75
|
*
|
|
@@ -85,6 +85,4 @@ declare function convertIpfsUrlWithFallbacks(url: string): string[];
|
|
|
85
85
|
* @returns Promise resolving to Response object
|
|
86
86
|
* @throws Error if all gateways fail
|
|
87
87
|
*/
|
|
88
|
-
declare function fetchWithFallbacks(url: string, options?: RequestInit): Promise<Response>;
|
|
89
|
-
|
|
90
|
-
export { DEFAULT_IPFS_GATEWAY, IPFS_GATEWAYS, convertIpfsUrl, convertIpfsUrlWithFallbacks, extractIpfsHash, fetchWithFallbacks, getGatewayUrls, isIpfsUrl };
|
|
88
|
+
export declare function fetchWithFallbacks(url: string, options?: RequestInit): Promise<Response>;
|
|
@@ -24,12 +24,10 @@ module.exports = __toCommonJS(lazy_import_exports);
|
|
|
24
24
|
function lazyImport(importFn) {
|
|
25
25
|
let cached = null;
|
|
26
26
|
return () => {
|
|
27
|
-
|
|
28
|
-
cached =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
}
|
|
27
|
+
cached ??= importFn().catch((err) => {
|
|
28
|
+
cached = null;
|
|
29
|
+
throw new Error("Failed to load module", { cause: err });
|
|
30
|
+
});
|
|
33
31
|
return cached;
|
|
34
32
|
};
|
|
35
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/lazy-import.ts"],"sourcesContent":["/**\n * Utility for lazy-loading modules to avoid Turbopack TDZ issues\n *\n * WARNING: This is a workaround for Turbopack's strict module initialization.\n * Dependencies that access globals during init must be dynamically imported.\n */\n\n/**\n * Creates a lazy import function that caches the promise (not the module)\n * to avoid race conditions on concurrent first calls\n *\n * @param importFn - Function that returns a dynamic import promise\n * @returns Function that returns the cached import promise\n *\n * @example\n * const getOpenPGP = lazyImport(() => import('openpgp'));\n * const openpgp = await getOpenPGP();\n */\nexport function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T> {\n let cached: Promise<T> | null = null;\n\n return () => {\n
|
|
1
|
+
{"version":3,"sources":["../../src/utils/lazy-import.ts"],"sourcesContent":["/**\n * Utility for lazy-loading modules to avoid Turbopack TDZ issues\n *\n * WARNING: This is a workaround for Turbopack's strict module initialization.\n * Dependencies that access globals during init must be dynamically imported.\n */\n\n/**\n * Creates a lazy import function that caches the promise (not the module)\n * to avoid race conditions on concurrent first calls\n *\n * @param importFn - Function that returns a dynamic import promise\n * @returns Function that returns the cached import promise\n *\n * @example\n * const getOpenPGP = lazyImport(() => import('openpgp'));\n * const openpgp = await getOpenPGP();\n */\nexport function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T> {\n let cached: Promise<T> | null = null;\n\n return () => {\n cached ??= importFn().catch((err) => {\n // Clear cache on error so next attempt can retry\n cached = null;\n throw new Error(\"Failed to load module\", { cause: err });\n });\n return cached;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBO,SAAS,WAAc,UAA8C;AAC1E,MAAI,SAA4B;AAEhC,SAAO,MAAM;AACX,eAAW,SAAS,EAAE,MAAM,CAAC,QAAQ;AAEnC,eAAS;AACT,YAAM,IAAI,MAAM,yBAAyB,EAAE,OAAO,IAAI,CAAC;AAAA,IACzD,CAAC;AACD,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -15,6 +15,4 @@
|
|
|
15
15
|
* const getOpenPGP = lazyImport(() => import('openpgp'));
|
|
16
16
|
* const openpgp = await getOpenPGP();
|
|
17
17
|
*/
|
|
18
|
-
declare function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T>;
|
|
19
|
-
|
|
20
|
-
export { lazyImport };
|
|
18
|
+
export declare function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T>;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
function lazyImport(importFn) {
|
|
2
2
|
let cached = null;
|
|
3
3
|
return () => {
|
|
4
|
-
|
|
5
|
-
cached =
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
});
|
|
9
|
-
}
|
|
4
|
+
cached ??= importFn().catch((err) => {
|
|
5
|
+
cached = null;
|
|
6
|
+
throw new Error("Failed to load module", { cause: err });
|
|
7
|
+
});
|
|
10
8
|
return cached;
|
|
11
9
|
};
|
|
12
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/lazy-import.ts"],"sourcesContent":["/**\n * Utility for lazy-loading modules to avoid Turbopack TDZ issues\n *\n * WARNING: This is a workaround for Turbopack's strict module initialization.\n * Dependencies that access globals during init must be dynamically imported.\n */\n\n/**\n * Creates a lazy import function that caches the promise (not the module)\n * to avoid race conditions on concurrent first calls\n *\n * @param importFn - Function that returns a dynamic import promise\n * @returns Function that returns the cached import promise\n *\n * @example\n * const getOpenPGP = lazyImport(() => import('openpgp'));\n * const openpgp = await getOpenPGP();\n */\nexport function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T> {\n let cached: Promise<T> | null = null;\n\n return () => {\n
|
|
1
|
+
{"version":3,"sources":["../../src/utils/lazy-import.ts"],"sourcesContent":["/**\n * Utility for lazy-loading modules to avoid Turbopack TDZ issues\n *\n * WARNING: This is a workaround for Turbopack's strict module initialization.\n * Dependencies that access globals during init must be dynamically imported.\n */\n\n/**\n * Creates a lazy import function that caches the promise (not the module)\n * to avoid race conditions on concurrent first calls\n *\n * @param importFn - Function that returns a dynamic import promise\n * @returns Function that returns the cached import promise\n *\n * @example\n * const getOpenPGP = lazyImport(() => import('openpgp'));\n * const openpgp = await getOpenPGP();\n */\nexport function lazyImport<T>(importFn: () => Promise<T>): () => Promise<T> {\n let cached: Promise<T> | null = null;\n\n return () => {\n cached ??= importFn().catch((err) => {\n // Clear cache on error so next attempt can retry\n cached = null;\n throw new Error(\"Failed to load module\", { cause: err });\n });\n return cached;\n };\n}\n"],"mappings":"AAkBO,SAAS,WAAc,UAA8C;AAC1E,MAAI,SAA4B;AAEhC,SAAO,MAAM;AACX,eAAW,SAAS,EAAE,MAAM,CAAC,QAAQ;AAEnC,eAAS;AACT,YAAM,IAAI,MAAM,yBAAyB,EAAE,OAAO,IAAI,CAAC;AAAA,IACzD,CAAC;AACD,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/utils/multicall.cjs
CHANGED
|
@@ -38,7 +38,7 @@ const DEFAULT_OPTIONS = {
|
|
|
38
38
|
};
|
|
39
39
|
async function gasAwareMulticall(client, parameters, options = {}) {
|
|
40
40
|
const chainId = await client.getChainId();
|
|
41
|
-
const multicall3Address = options.multicallAddress
|
|
41
|
+
const multicall3Address = options.multicallAddress ?? (0, import_addresses.getUtilityAddress)(chainId, "Multicall3");
|
|
42
42
|
const opts = {
|
|
43
43
|
...DEFAULT_OPTIONS,
|
|
44
44
|
...options,
|
|
@@ -116,7 +116,9 @@ async function createBatches(client, contracts, options) {
|
|
|
116
116
|
lastEstimatedGas = 0n;
|
|
117
117
|
} else {
|
|
118
118
|
if (!options.allowFailure) {
|
|
119
|
-
throw new Error(
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Gas estimation failed for call ${i}: ${String(error)}`
|
|
121
|
+
);
|
|
120
122
|
}
|
|
121
123
|
currentBatch = [];
|
|
122
124
|
currentBytes = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/multicall.ts"],"sourcesContent":["import type {\n Address,\n PublicClient,\n MulticallParameters,\n MulticallReturnType,\n EncodeFunctionDataParameters,\n Hex,\n Abi,\n} from \"viem\";\nimport { encodeFunctionData, size } from \"viem\";\nimport { getUtilityAddress } from \"../config/addresses\";\nimport type { VanaChainId } from \"../types\";\n\n/**\n * Type for a contract function configuration used in multicall\n */\nexport interface ContractFunctionConfig {\n address: Address;\n abi: Abi;\n functionName: string;\n args?: readonly unknown[];\n}\n\n/**\n * Configuration options for gas-aware multicall batching.\n *\n * @remarks\n * These options control how the multicall utility splits large batches\n * to stay within gas and calldata limits. The defaults are conservative\n * to ensure compatibility across different chains and RPC providers.\n */\nexport interface GasAwareMulticallOptions {\n /**\n * Maximum gas per batch. Defaults to 10M (conservative for most chains).\n *\n * @remarks\n * This should be set below the block gas limit of your target chain.\n * Common values:\n * - Vana mainnet: 30M (use 25M for safety)\n * - Vana moksha: 30M (use 25M for safety)\n * - Ethereum mainnet: 30M (use 25M for safety)\n * - Arbitrum: 32M (use 25M for safety)\n */\n maxGasPerBatch?: bigint;\n\n /**\n * Maximum calldata size per batch in bytes. Defaults to 100KB.\n *\n * @remarks\n * This is particularly important for L2 chains where calldata is expensive.\n * Some RPC providers also have limits on request size.\n */\n maxCalldataBytes?: number;\n\n /**\n * How often to checkpoint gas estimates. Defaults to every 32 calls or 8KB.\n *\n * @remarks\n * More frequent checkpoints give more accurate batching but require more\n * RPC calls for gas estimation. The default balances accuracy vs performance.\n */\n checkpointFrequency?: {\n /** Checkpoint after this many calls */\n calls: number;\n /** Checkpoint after this many bytes of calldata */\n bytes: number;\n };\n\n /**\n * Whether to allow partial batch failures. Defaults to false.\n *\n * @remarks\n * When true, individual call failures won't fail the entire batch.\n * This matches viem's multicall behavior with allowFailure option.\n */\n allowFailure?: boolean;\n\n /**\n * Optional multicall3 contract address override.\n *\n * @remarks\n * By default, uses the standard multicall3 address deployed on most chains:\n * 0xcA11bde05977b3631167028862bE2a173976CA11\n */\n multicallAddress?: Address;\n\n /**\n * Optional callback for tracking batching progress.\n *\n * @remarks\n * Useful for showing progress in UI or debugging batch performance.\n */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Internal configuration with defaults applied\n */\ninterface NormalizedOptions {\n maxGasPerBatch: bigint;\n maxCalldataBytes: number;\n checkpointFrequency: {\n calls: number;\n bytes: number;\n };\n allowFailure: boolean;\n multicallAddress: Address;\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Default configuration values\n */\nconst DEFAULT_OPTIONS: Omit<NormalizedOptions, \"multicallAddress\"> = {\n maxGasPerBatch: 10_000_000n, // 10M gas - conservative default\n maxCalldataBytes: 100_000, // 100KB - works with most RPC providers\n checkpointFrequency: {\n calls: 32,\n bytes: 8192, // 8KB\n },\n allowFailure: false,\n};\n\n/**\n * A gas-aware multicall function that automatically batches calls to stay within limits.\n *\n * @remarks\n * This function extends viem's multicall with intelligent batching based on:\n * - Actual gas costs (via periodic estimateGas calls)\n * - Calldata size limits\n * - Chain-specific constraints\n *\n * It uses a greedy algorithm with periodic checkpoints to efficiently determine\n * optimal batch sizes without making excessive RPC calls.\n *\n * @param client - The viem public client to use for RPC calls\n * @param parameters - The multicall parameters (same as viem's multicall)\n * @param options - Optional configuration for gas-aware batching\n * @returns The aggregated results from all batches\n *\n * @example\n * ```typescript\n * // Basic usage - drop-in replacement for viem's multicall\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: [\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address1] },\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address2] },\n * // ... hundreds more calls\n * ]\n * });\n *\n * // With custom limits for a specific chain\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: calls,\n * }, {\n * maxGasPerBatch: 25_000_000n, // 25M for mainnet\n * maxCalldataBytes: 128_000, // 128KB\n * onProgress: (done, total) => console.log(`Progress: ${done}/${total}`)\n * });\n * ```\n */\nexport async function gasAwareMulticall<\n TContracts extends readonly ContractFunctionConfig[],\n TAllowFailure extends boolean = false,\n>(\n client: PublicClient,\n parameters: MulticallParameters<TContracts, TAllowFailure>,\n options: GasAwareMulticallOptions = {},\n): Promise<MulticallReturnType<TContracts, TAllowFailure>> {\n // Get the chain-specific Multicall3 address\n const chainId = await client.getChainId();\n const multicall3Address =\n options.multicallAddress ||\n getUtilityAddress(chainId as VanaChainId, \"Multicall3\");\n\n // Normalize options with defaults\n const opts: NormalizedOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n multicallAddress: multicall3Address,\n checkpointFrequency: {\n ...DEFAULT_OPTIONS.checkpointFrequency,\n ...options.checkpointFrequency,\n },\n };\n\n // Override allowFailure if specified in parameters\n if (parameters.allowFailure !== undefined) {\n opts.allowFailure = parameters.allowFailure;\n }\n\n const { contracts } = parameters;\n if (!contracts || contracts.length === 0) {\n return [] as unknown as MulticallReturnType<TContracts, TAllowFailure>;\n }\n\n // Execute batching algorithm\n const batches = await createBatches(\n client,\n contracts as readonly ContractFunctionConfig[],\n opts,\n );\n\n // Execute all batches in parallel\n const batchResults = await Promise.all(\n batches.map((batch, index) => {\n // Report progress if callback provided\n if (opts.onProgress && index > 0) {\n const completed = batches\n .slice(0, index)\n .reduce((sum, b) => sum + b.length, 0);\n opts.onProgress(completed, contracts.length);\n }\n\n // Execute batch using viem's multicall\n return client.multicall({\n ...parameters,\n contracts: batch as typeof contracts,\n multicallAddress: opts.multicallAddress,\n allowFailure: opts.allowFailure,\n });\n }),\n );\n\n // Report final progress\n if (opts.onProgress) {\n opts.onProgress(contracts.length, contracts.length);\n }\n\n // Flatten results\n return batchResults.flat() as MulticallReturnType<TContracts, TAllowFailure>;\n}\n\n/**\n * Creates optimally-sized batches using greedy algorithm with checkpoints.\n *\n * @param client - The viem public client for making RPC calls\n * @param contracts - Array of contract function configurations to batch\n * @param options - Normalized batching options with limits and settings\n * @returns Array of optimally-sized contract function configuration batches\n */\nasync function createBatches(\n client: PublicClient,\n contracts: readonly ContractFunctionConfig[],\n options: NormalizedOptions,\n): Promise<ContractFunctionConfig[][]> {\n const batches: ContractFunctionConfig[][] = [];\n let currentBatch: ContractFunctionConfig[] = [];\n let currentBytes = 0;\n let lastCheckpointIndex = 0;\n let lastCheckpointBytes = 0;\n let lastEstimatedGas = 0n;\n\n for (let i = 0; i < contracts.length; i++) {\n const contract = contracts[i];\n\n // Calculate encoded size for this call\n const encoded = encodeContractCall(contract);\n const callBytes = size(encoded);\n\n // Check if we need a gas checkpoint\n const callsSinceCheckpoint = i - lastCheckpointIndex;\n const bytesSinceCheckpoint = currentBytes - lastCheckpointBytes;\n\n const needsCheckpoint =\n callsSinceCheckpoint >= options.checkpointFrequency.calls ||\n bytesSinceCheckpoint >= options.checkpointFrequency.bytes;\n\n // Perform checkpoint if needed\n if (needsCheckpoint && currentBatch.length > 0) {\n try {\n lastEstimatedGas = await estimateBatchGas(\n client,\n currentBatch,\n options.multicallAddress,\n );\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n } catch (error) {\n // If estimation fails, finalize current batch to be safe\n if (currentBatch.length > 1) {\n // Try with half the batch\n const halfBatch = currentBatch.slice(\n 0,\n Math.floor(currentBatch.length / 2),\n );\n batches.push(halfBatch);\n currentBatch = currentBatch.slice(halfBatch.length);\n currentBytes = calculateBatchSize(currentBatch);\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n lastEstimatedGas = 0n;\n } else {\n // Single call failed, skip it or throw based on allowFailure\n if (!options.allowFailure) {\n throw new Error(`Gas estimation failed for call ${i}: ${error}`);\n }\n currentBatch = [];\n currentBytes = 0;\n continue;\n }\n }\n }\n\n // Check if adding this call would exceed limits\n const wouldExceedCalldata =\n currentBytes + callBytes > options.maxCalldataBytes;\n const wouldExceedGas =\n lastEstimatedGas > 0n &&\n estimateNextGas(lastEstimatedGas, callsSinceCheckpoint + 1) >\n options.maxGasPerBatch;\n\n // If we would exceed limits, finalize current batch\n if ((wouldExceedCalldata || wouldExceedGas) && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBytes = 0;\n lastCheckpointIndex = i;\n lastCheckpointBytes = 0;\n lastEstimatedGas = 0n;\n }\n\n // Add call to current batch\n currentBatch.push(contract);\n currentBytes += callBytes;\n }\n\n // Add final batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n/**\n * Encodes a contract call to measure its calldata size.\n *\n * @param contract - The contract function configuration to encode\n * @returns Hex-encoded function data\n */\nfunction encodeContractCall(contract: ContractFunctionConfig): Hex {\n const { abi, functionName, args } = contract;\n\n return encodeFunctionData({\n abi,\n functionName,\n args,\n } as EncodeFunctionDataParameters);\n}\n\n/**\n * Calculates total encoded size of a batch.\n *\n * @param batch - Array of contract function configurations to measure\n * @returns Total size in bytes of all encoded calls in the batch\n */\nfunction calculateBatchSize(batch: ContractFunctionConfig[]): number {\n return batch.reduce((total, contract) => {\n const encoded = encodeContractCall(contract);\n return total + size(encoded);\n }, 0);\n}\n\n/**\n * Estimates gas for a batch of calls via multicall3.\n *\n * @param client - The viem public client for gas estimation\n * @param batch - Array of contract calls to estimate gas for\n * @param multicallAddress - The multicall3 contract address to use\n * @returns Estimated gas cost for executing the batch\n */\nasync function estimateBatchGas(\n client: PublicClient,\n batch: ContractFunctionConfig[],\n multicallAddress: Address,\n): Promise<bigint> {\n // Encode batch as multicall3 aggregate3 call\n const calls = batch.map((contract) => ({\n target: contract.address,\n allowFailure: false,\n callData: encodeContractCall(contract),\n }));\n\n // Estimate gas for the multicall\n const gas = await client.estimateGas({\n to: multicallAddress,\n data: encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [calls],\n }),\n });\n\n return gas;\n}\n\n/**\n * Extrapolates gas usage for calls added since last checkpoint.\n *\n * @remarks\n * Uses a conservative 1.1x multiplier for safety to account for gas usage variations.\n *\n * @param lastGas - The gas estimate from the last checkpoint\n * @param callsSinceCheckpoint - Number of calls added since the checkpoint\n * @returns Extrapolated gas estimate with safety margin\n */\nfunction estimateNextGas(\n lastGas: bigint,\n callsSinceCheckpoint: number,\n): bigint {\n if (callsSinceCheckpoint === 0) return lastGas;\n\n // Assume linear scaling with safety factor\n const avgGasPerCall = lastGas / BigInt(Math.max(1, callsSinceCheckpoint - 1));\n const estimatedGas = lastGas + avgGasPerCall;\n\n // Apply 10% safety margin\n return (estimatedGas * 110n) / 100n;\n}\n\n/**\n * Minimal multicall3 ABI for gas estimation\n */\nconst multicall3Abi = [\n {\n name: \"aggregate3\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"allowFailure\", type: \"bool\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n },\n] as const;\n\n/**\n * Utility function to analyze calls and predict optimal batch configuration\n *\n * @remarks\n * This function helps determine the best configuration for a specific set of calls\n * by analyzing their characteristics. Useful for optimizing repeated operations.\n *\n * @param contracts - The calls to analyze\n * @returns Suggested configuration based on call analysis\n */\nexport function analyzeCallsForOptimalConfig(\n contracts: readonly ContractFunctionConfig[],\n): Pick<GasAwareMulticallOptions, \"checkpointFrequency\" | \"maxCalldataBytes\"> {\n // Calculate average call size\n const totalBytes = contracts.reduce((sum, contract) => {\n const encoded = encodeContractCall(contract);\n return sum + size(encoded);\n }, 0);\n\n const avgBytesPerCall = totalBytes / contracts.length;\n\n // Suggest checkpoint frequency based on call density\n const checkpointFrequency = {\n calls: avgBytesPerCall > 500 ? 16 : 32, // More frequent for large calls\n bytes: avgBytesPerCall > 500 ? 4096 : 8192,\n };\n\n // Suggest calldata limit based on total size\n // For 1000 calls with small arrays, totalBytes will be much less than 500KB,\n // so use number of contracts as additional signal\n const maxCalldataBytes =\n totalBytes > 50_000 || contracts.length > 500 ? 128_000 : 100_000;\n\n return {\n checkpointFrequency,\n maxCalldataBytes,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/multicall.ts"],"sourcesContent":["import type {\n Address,\n PublicClient,\n MulticallParameters,\n MulticallReturnType,\n EncodeFunctionDataParameters,\n Hex,\n Abi,\n} from \"viem\";\nimport { encodeFunctionData, size } from \"viem\";\nimport { getUtilityAddress } from \"../config/addresses\";\nimport type { VanaChainId } from \"../types\";\n\n/**\n * Type for a contract function configuration used in multicall\n */\nexport interface ContractFunctionConfig {\n address: Address;\n abi: Abi;\n functionName: string;\n args?: readonly unknown[];\n}\n\n/**\n * Configuration options for gas-aware multicall batching.\n *\n * @remarks\n * These options control how the multicall utility splits large batches\n * to stay within gas and calldata limits. The defaults are conservative\n * to ensure compatibility across different chains and RPC providers.\n */\nexport interface GasAwareMulticallOptions {\n /**\n * Maximum gas per batch. Defaults to 10M (conservative for most chains).\n *\n * @remarks\n * This should be set below the block gas limit of your target chain.\n * Common values:\n * - Vana mainnet: 30M (use 25M for safety)\n * - Vana moksha: 30M (use 25M for safety)\n * - Ethereum mainnet: 30M (use 25M for safety)\n * - Arbitrum: 32M (use 25M for safety)\n */\n maxGasPerBatch?: bigint;\n\n /**\n * Maximum calldata size per batch in bytes. Defaults to 100KB.\n *\n * @remarks\n * This is particularly important for L2 chains where calldata is expensive.\n * Some RPC providers also have limits on request size.\n */\n maxCalldataBytes?: number;\n\n /**\n * How often to checkpoint gas estimates. Defaults to every 32 calls or 8KB.\n *\n * @remarks\n * More frequent checkpoints give more accurate batching but require more\n * RPC calls for gas estimation. The default balances accuracy vs performance.\n */\n checkpointFrequency?: {\n /** Checkpoint after this many calls */\n calls: number;\n /** Checkpoint after this many bytes of calldata */\n bytes: number;\n };\n\n /**\n * Whether to allow partial batch failures. Defaults to false.\n *\n * @remarks\n * When true, individual call failures won't fail the entire batch.\n * This matches viem's multicall behavior with allowFailure option.\n */\n allowFailure?: boolean;\n\n /**\n * Optional multicall3 contract address override.\n *\n * @remarks\n * By default, uses the standard multicall3 address deployed on most chains:\n * 0xcA11bde05977b3631167028862bE2a173976CA11\n */\n multicallAddress?: Address;\n\n /**\n * Optional callback for tracking batching progress.\n *\n * @remarks\n * Useful for showing progress in UI or debugging batch performance.\n */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Internal configuration with defaults applied\n */\ninterface NormalizedOptions {\n maxGasPerBatch: bigint;\n maxCalldataBytes: number;\n checkpointFrequency: {\n calls: number;\n bytes: number;\n };\n allowFailure: boolean;\n multicallAddress: Address;\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Default configuration values\n */\nconst DEFAULT_OPTIONS: Omit<NormalizedOptions, \"multicallAddress\"> = {\n maxGasPerBatch: 10_000_000n, // 10M gas - conservative default\n maxCalldataBytes: 100_000, // 100KB - works with most RPC providers\n checkpointFrequency: {\n calls: 32,\n bytes: 8192, // 8KB\n },\n allowFailure: false,\n};\n\n/**\n * A gas-aware multicall function that automatically batches calls to stay within limits.\n *\n * @remarks\n * This function extends viem's multicall with intelligent batching based on:\n * - Actual gas costs (via periodic estimateGas calls)\n * - Calldata size limits\n * - Chain-specific constraints\n *\n * It uses a greedy algorithm with periodic checkpoints to efficiently determine\n * optimal batch sizes without making excessive RPC calls.\n *\n * @param client - The viem public client to use for RPC calls\n * @param parameters - The multicall parameters (same as viem's multicall)\n * @param options - Optional configuration for gas-aware batching\n * @returns The aggregated results from all batches\n *\n * @example\n * ```typescript\n * // Basic usage - drop-in replacement for viem's multicall\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: [\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address1] },\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address2] },\n * // ... hundreds more calls\n * ]\n * });\n *\n * // With custom limits for a specific chain\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: calls,\n * }, {\n * maxGasPerBatch: 25_000_000n, // 25M for mainnet\n * maxCalldataBytes: 128_000, // 128KB\n * onProgress: (done, total) => console.log(`Progress: ${done}/${total}`)\n * });\n * ```\n */\nexport async function gasAwareMulticall<\n TContracts extends readonly ContractFunctionConfig[],\n TAllowFailure extends boolean = false,\n>(\n client: PublicClient,\n parameters: MulticallParameters<TContracts, TAllowFailure>,\n options: GasAwareMulticallOptions = {},\n): Promise<MulticallReturnType<TContracts, TAllowFailure>> {\n // Get the chain-specific Multicall3 address\n const chainId = await client.getChainId();\n const multicall3Address =\n options.multicallAddress ??\n getUtilityAddress(chainId as VanaChainId, \"Multicall3\");\n\n // Normalize options with defaults\n const opts: NormalizedOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n multicallAddress: multicall3Address,\n checkpointFrequency: {\n ...DEFAULT_OPTIONS.checkpointFrequency,\n ...options.checkpointFrequency,\n },\n };\n\n // Override allowFailure if specified in parameters\n if (parameters.allowFailure !== undefined) {\n opts.allowFailure = parameters.allowFailure;\n }\n\n const { contracts } = parameters;\n if (!contracts || contracts.length === 0) {\n // TODO(TYPES): Empty array needs to match complex generic return type.\n // Future improvement: Use conditional types to properly type empty results\n // based on TAllowFailure parameter. Consider creating utility type helper.\n return [] as unknown as MulticallReturnType<TContracts, TAllowFailure>;\n }\n\n // Execute batching algorithm\n const batches = await createBatches(\n client,\n contracts as readonly ContractFunctionConfig[],\n opts,\n );\n\n // Execute all batches in parallel\n const batchResults = await Promise.all(\n batches.map((batch, index) => {\n // Report progress if callback provided\n if (opts.onProgress && index > 0) {\n const completed = batches\n .slice(0, index)\n .reduce((sum, b) => sum + b.length, 0);\n opts.onProgress(completed, contracts.length);\n }\n\n // Execute batch using viem's multicall\n return client.multicall({\n ...parameters,\n contracts: batch as typeof contracts,\n multicallAddress: opts.multicallAddress,\n allowFailure: opts.allowFailure,\n });\n }),\n );\n\n // Report final progress\n if (opts.onProgress) {\n opts.onProgress(contracts.length, contracts.length);\n }\n\n // Flatten results\n return batchResults.flat() as MulticallReturnType<TContracts, TAllowFailure>;\n}\n\n/**\n * Creates optimally-sized batches using greedy algorithm with checkpoints.\n *\n * @param client - The viem public client for making RPC calls\n * @param contracts - Array of contract function configurations to batch\n * @param options - Normalized batching options with limits and settings\n * @returns Array of optimally-sized contract function configuration batches\n */\nasync function createBatches(\n client: PublicClient,\n contracts: readonly ContractFunctionConfig[],\n options: NormalizedOptions,\n): Promise<ContractFunctionConfig[][]> {\n const batches: ContractFunctionConfig[][] = [];\n let currentBatch: ContractFunctionConfig[] = [];\n let currentBytes = 0;\n let lastCheckpointIndex = 0;\n let lastCheckpointBytes = 0;\n let lastEstimatedGas = 0n;\n\n for (let i = 0; i < contracts.length; i++) {\n const contract = contracts[i];\n\n // Calculate encoded size for this call\n const encoded = encodeContractCall(contract);\n const callBytes = size(encoded);\n\n // Check if we need a gas checkpoint\n const callsSinceCheckpoint = i - lastCheckpointIndex;\n const bytesSinceCheckpoint = currentBytes - lastCheckpointBytes;\n\n const needsCheckpoint =\n callsSinceCheckpoint >= options.checkpointFrequency.calls ||\n bytesSinceCheckpoint >= options.checkpointFrequency.bytes;\n\n // Perform checkpoint if needed\n if (needsCheckpoint && currentBatch.length > 0) {\n try {\n lastEstimatedGas = await estimateBatchGas(\n client,\n currentBatch,\n options.multicallAddress,\n );\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n } catch (error) {\n // If estimation fails, finalize current batch to be safe\n if (currentBatch.length > 1) {\n // Try with half the batch\n const halfBatch = currentBatch.slice(\n 0,\n Math.floor(currentBatch.length / 2),\n );\n batches.push(halfBatch);\n currentBatch = currentBatch.slice(halfBatch.length);\n currentBytes = calculateBatchSize(currentBatch);\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n lastEstimatedGas = 0n;\n } else {\n // Single call failed, skip it or throw based on allowFailure\n if (!options.allowFailure) {\n throw new Error(\n `Gas estimation failed for call ${i}: ${String(error)}`,\n );\n }\n currentBatch = [];\n currentBytes = 0;\n continue;\n }\n }\n }\n\n // Check if adding this call would exceed limits\n const wouldExceedCalldata =\n currentBytes + callBytes > options.maxCalldataBytes;\n const wouldExceedGas =\n lastEstimatedGas > 0n &&\n estimateNextGas(lastEstimatedGas, callsSinceCheckpoint + 1) >\n options.maxGasPerBatch;\n\n // If we would exceed limits, finalize current batch\n if ((wouldExceedCalldata || wouldExceedGas) && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBytes = 0;\n lastCheckpointIndex = i;\n lastCheckpointBytes = 0;\n lastEstimatedGas = 0n;\n }\n\n // Add call to current batch\n currentBatch.push(contract);\n currentBytes += callBytes;\n }\n\n // Add final batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n/**\n * Encodes a contract call to measure its calldata size.\n *\n * @param contract - The contract function configuration to encode\n * @returns Hex-encoded function data\n */\nfunction encodeContractCall(contract: ContractFunctionConfig): Hex {\n const { abi, functionName, args } = contract;\n\n return encodeFunctionData({\n abi,\n functionName,\n args,\n } as EncodeFunctionDataParameters);\n}\n\n/**\n * Calculates total encoded size of a batch.\n *\n * @param batch - Array of contract function configurations to measure\n * @returns Total size in bytes of all encoded calls in the batch\n */\nfunction calculateBatchSize(batch: ContractFunctionConfig[]): number {\n return batch.reduce((total, contract) => {\n const encoded = encodeContractCall(contract);\n return total + size(encoded);\n }, 0);\n}\n\n/**\n * Estimates gas for a batch of calls via multicall3.\n *\n * @param client - The viem public client for gas estimation\n * @param batch - Array of contract calls to estimate gas for\n * @param multicallAddress - The multicall3 contract address to use\n * @returns Estimated gas cost for executing the batch\n */\nasync function estimateBatchGas(\n client: PublicClient,\n batch: ContractFunctionConfig[],\n multicallAddress: Address,\n): Promise<bigint> {\n // Encode batch as multicall3 aggregate3 call\n const calls = batch.map((contract) => ({\n target: contract.address,\n allowFailure: false,\n callData: encodeContractCall(contract),\n }));\n\n // Estimate gas for the multicall\n const gas = await client.estimateGas({\n to: multicallAddress,\n data: encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [calls],\n }),\n });\n\n return gas;\n}\n\n/**\n * Extrapolates gas usage for calls added since last checkpoint.\n *\n * @remarks\n * Uses a conservative 1.1x multiplier for safety to account for gas usage variations.\n *\n * @param lastGas - The gas estimate from the last checkpoint\n * @param callsSinceCheckpoint - Number of calls added since the checkpoint\n * @returns Extrapolated gas estimate with safety margin\n */\nfunction estimateNextGas(\n lastGas: bigint,\n callsSinceCheckpoint: number,\n): bigint {\n if (callsSinceCheckpoint === 0) return lastGas;\n\n // Assume linear scaling with safety factor\n const avgGasPerCall = lastGas / BigInt(Math.max(1, callsSinceCheckpoint - 1));\n const estimatedGas = lastGas + avgGasPerCall;\n\n // Apply 10% safety margin\n return (estimatedGas * 110n) / 100n;\n}\n\n/**\n * Minimal multicall3 ABI for gas estimation\n */\nconst multicall3Abi = [\n {\n name: \"aggregate3\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"allowFailure\", type: \"bool\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n },\n] as const;\n\n/**\n * Utility function to analyze calls and predict optimal batch configuration\n *\n * @remarks\n * This function helps determine the best configuration for a specific set of calls\n * by analyzing their characteristics. Useful for optimizing repeated operations.\n *\n * @param contracts - The calls to analyze\n * @returns Suggested configuration based on call analysis\n */\nexport function analyzeCallsForOptimalConfig(\n contracts: readonly ContractFunctionConfig[],\n): Pick<GasAwareMulticallOptions, \"checkpointFrequency\" | \"maxCalldataBytes\"> {\n // Calculate average call size\n const totalBytes = contracts.reduce((sum, contract) => {\n const encoded = encodeContractCall(contract);\n return sum + size(encoded);\n }, 0);\n\n const avgBytesPerCall = totalBytes / contracts.length;\n\n // Suggest checkpoint frequency based on call density\n const checkpointFrequency = {\n calls: avgBytesPerCall > 500 ? 16 : 32, // More frequent for large calls\n bytes: avgBytesPerCall > 500 ? 4096 : 8192,\n };\n\n // Suggest calldata limit based on total size\n // For 1000 calls with small arrays, totalBytes will be much less than 500KB,\n // so use number of contracts as additional signal\n const maxCalldataBytes =\n totalBytes > 50_000 || contracts.length > 500 ? 128_000 : 100_000;\n\n return {\n checkpointFrequency,\n maxCalldataBytes,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Address,
|
|
2
|
-
|
|
1
|
+
import type { Address, PublicClient, MulticallParameters, MulticallReturnType, Abi } from "viem";
|
|
3
2
|
/**
|
|
4
3
|
* Type for a contract function configuration used in multicall
|
|
5
4
|
*/
|
|
6
|
-
interface ContractFunctionConfig {
|
|
5
|
+
export interface ContractFunctionConfig {
|
|
7
6
|
address: Address;
|
|
8
7
|
abi: Abi;
|
|
9
8
|
functionName: string;
|
|
@@ -17,7 +16,7 @@ interface ContractFunctionConfig {
|
|
|
17
16
|
* to stay within gas and calldata limits. The defaults are conservative
|
|
18
17
|
* to ensure compatibility across different chains and RPC providers.
|
|
19
18
|
*/
|
|
20
|
-
interface GasAwareMulticallOptions {
|
|
19
|
+
export interface GasAwareMulticallOptions {
|
|
21
20
|
/**
|
|
22
21
|
* Maximum gas per batch. Defaults to 10M (conservative for most chains).
|
|
23
22
|
*
|
|
@@ -113,7 +112,7 @@ interface GasAwareMulticallOptions {
|
|
|
113
112
|
* });
|
|
114
113
|
* ```
|
|
115
114
|
*/
|
|
116
|
-
declare function gasAwareMulticall<TContracts extends readonly ContractFunctionConfig[], TAllowFailure extends boolean = false>(client: PublicClient, parameters: MulticallParameters<TContracts, TAllowFailure>, options?: GasAwareMulticallOptions): Promise<MulticallReturnType<TContracts, TAllowFailure>>;
|
|
115
|
+
export declare function gasAwareMulticall<TContracts extends readonly ContractFunctionConfig[], TAllowFailure extends boolean = false>(client: PublicClient, parameters: MulticallParameters<TContracts, TAllowFailure>, options?: GasAwareMulticallOptions): Promise<MulticallReturnType<TContracts, TAllowFailure>>;
|
|
117
116
|
/**
|
|
118
117
|
* Utility function to analyze calls and predict optimal batch configuration
|
|
119
118
|
*
|
|
@@ -124,6 +123,4 @@ declare function gasAwareMulticall<TContracts extends readonly ContractFunctionC
|
|
|
124
123
|
* @param contracts - The calls to analyze
|
|
125
124
|
* @returns Suggested configuration based on call analysis
|
|
126
125
|
*/
|
|
127
|
-
declare function analyzeCallsForOptimalConfig(contracts: readonly ContractFunctionConfig[]): Pick<GasAwareMulticallOptions, "checkpointFrequency" | "maxCalldataBytes">;
|
|
128
|
-
|
|
129
|
-
export { type ContractFunctionConfig, type GasAwareMulticallOptions, analyzeCallsForOptimalConfig, gasAwareMulticall };
|
|
126
|
+
export declare function analyzeCallsForOptimalConfig(contracts: readonly ContractFunctionConfig[]): Pick<GasAwareMulticallOptions, "checkpointFrequency" | "maxCalldataBytes">;
|
package/dist/utils/multicall.js
CHANGED
|
@@ -14,7 +14,7 @@ const DEFAULT_OPTIONS = {
|
|
|
14
14
|
};
|
|
15
15
|
async function gasAwareMulticall(client, parameters, options = {}) {
|
|
16
16
|
const chainId = await client.getChainId();
|
|
17
|
-
const multicall3Address = options.multicallAddress
|
|
17
|
+
const multicall3Address = options.multicallAddress ?? getUtilityAddress(chainId, "Multicall3");
|
|
18
18
|
const opts = {
|
|
19
19
|
...DEFAULT_OPTIONS,
|
|
20
20
|
...options,
|
|
@@ -92,7 +92,9 @@ async function createBatches(client, contracts, options) {
|
|
|
92
92
|
lastEstimatedGas = 0n;
|
|
93
93
|
} else {
|
|
94
94
|
if (!options.allowFailure) {
|
|
95
|
-
throw new Error(
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Gas estimation failed for call ${i}: ${String(error)}`
|
|
97
|
+
);
|
|
96
98
|
}
|
|
97
99
|
currentBatch = [];
|
|
98
100
|
currentBytes = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/multicall.ts"],"sourcesContent":["import type {\n Address,\n PublicClient,\n MulticallParameters,\n MulticallReturnType,\n EncodeFunctionDataParameters,\n Hex,\n Abi,\n} from \"viem\";\nimport { encodeFunctionData, size } from \"viem\";\nimport { getUtilityAddress } from \"../config/addresses\";\nimport type { VanaChainId } from \"../types\";\n\n/**\n * Type for a contract function configuration used in multicall\n */\nexport interface ContractFunctionConfig {\n address: Address;\n abi: Abi;\n functionName: string;\n args?: readonly unknown[];\n}\n\n/**\n * Configuration options for gas-aware multicall batching.\n *\n * @remarks\n * These options control how the multicall utility splits large batches\n * to stay within gas and calldata limits. The defaults are conservative\n * to ensure compatibility across different chains and RPC providers.\n */\nexport interface GasAwareMulticallOptions {\n /**\n * Maximum gas per batch. Defaults to 10M (conservative for most chains).\n *\n * @remarks\n * This should be set below the block gas limit of your target chain.\n * Common values:\n * - Vana mainnet: 30M (use 25M for safety)\n * - Vana moksha: 30M (use 25M for safety)\n * - Ethereum mainnet: 30M (use 25M for safety)\n * - Arbitrum: 32M (use 25M for safety)\n */\n maxGasPerBatch?: bigint;\n\n /**\n * Maximum calldata size per batch in bytes. Defaults to 100KB.\n *\n * @remarks\n * This is particularly important for L2 chains where calldata is expensive.\n * Some RPC providers also have limits on request size.\n */\n maxCalldataBytes?: number;\n\n /**\n * How often to checkpoint gas estimates. Defaults to every 32 calls or 8KB.\n *\n * @remarks\n * More frequent checkpoints give more accurate batching but require more\n * RPC calls for gas estimation. The default balances accuracy vs performance.\n */\n checkpointFrequency?: {\n /** Checkpoint after this many calls */\n calls: number;\n /** Checkpoint after this many bytes of calldata */\n bytes: number;\n };\n\n /**\n * Whether to allow partial batch failures. Defaults to false.\n *\n * @remarks\n * When true, individual call failures won't fail the entire batch.\n * This matches viem's multicall behavior with allowFailure option.\n */\n allowFailure?: boolean;\n\n /**\n * Optional multicall3 contract address override.\n *\n * @remarks\n * By default, uses the standard multicall3 address deployed on most chains:\n * 0xcA11bde05977b3631167028862bE2a173976CA11\n */\n multicallAddress?: Address;\n\n /**\n * Optional callback for tracking batching progress.\n *\n * @remarks\n * Useful for showing progress in UI or debugging batch performance.\n */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Internal configuration with defaults applied\n */\ninterface NormalizedOptions {\n maxGasPerBatch: bigint;\n maxCalldataBytes: number;\n checkpointFrequency: {\n calls: number;\n bytes: number;\n };\n allowFailure: boolean;\n multicallAddress: Address;\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Default configuration values\n */\nconst DEFAULT_OPTIONS: Omit<NormalizedOptions, \"multicallAddress\"> = {\n maxGasPerBatch: 10_000_000n, // 10M gas - conservative default\n maxCalldataBytes: 100_000, // 100KB - works with most RPC providers\n checkpointFrequency: {\n calls: 32,\n bytes: 8192, // 8KB\n },\n allowFailure: false,\n};\n\n/**\n * A gas-aware multicall function that automatically batches calls to stay within limits.\n *\n * @remarks\n * This function extends viem's multicall with intelligent batching based on:\n * - Actual gas costs (via periodic estimateGas calls)\n * - Calldata size limits\n * - Chain-specific constraints\n *\n * It uses a greedy algorithm with periodic checkpoints to efficiently determine\n * optimal batch sizes without making excessive RPC calls.\n *\n * @param client - The viem public client to use for RPC calls\n * @param parameters - The multicall parameters (same as viem's multicall)\n * @param options - Optional configuration for gas-aware batching\n * @returns The aggregated results from all batches\n *\n * @example\n * ```typescript\n * // Basic usage - drop-in replacement for viem's multicall\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: [\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address1] },\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address2] },\n * // ... hundreds more calls\n * ]\n * });\n *\n * // With custom limits for a specific chain\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: calls,\n * }, {\n * maxGasPerBatch: 25_000_000n, // 25M for mainnet\n * maxCalldataBytes: 128_000, // 128KB\n * onProgress: (done, total) => console.log(`Progress: ${done}/${total}`)\n * });\n * ```\n */\nexport async function gasAwareMulticall<\n TContracts extends readonly ContractFunctionConfig[],\n TAllowFailure extends boolean = false,\n>(\n client: PublicClient,\n parameters: MulticallParameters<TContracts, TAllowFailure>,\n options: GasAwareMulticallOptions = {},\n): Promise<MulticallReturnType<TContracts, TAllowFailure>> {\n // Get the chain-specific Multicall3 address\n const chainId = await client.getChainId();\n const multicall3Address =\n options.multicallAddress ||\n getUtilityAddress(chainId as VanaChainId, \"Multicall3\");\n\n // Normalize options with defaults\n const opts: NormalizedOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n multicallAddress: multicall3Address,\n checkpointFrequency: {\n ...DEFAULT_OPTIONS.checkpointFrequency,\n ...options.checkpointFrequency,\n },\n };\n\n // Override allowFailure if specified in parameters\n if (parameters.allowFailure !== undefined) {\n opts.allowFailure = parameters.allowFailure;\n }\n\n const { contracts } = parameters;\n if (!contracts || contracts.length === 0) {\n return [] as unknown as MulticallReturnType<TContracts, TAllowFailure>;\n }\n\n // Execute batching algorithm\n const batches = await createBatches(\n client,\n contracts as readonly ContractFunctionConfig[],\n opts,\n );\n\n // Execute all batches in parallel\n const batchResults = await Promise.all(\n batches.map((batch, index) => {\n // Report progress if callback provided\n if (opts.onProgress && index > 0) {\n const completed = batches\n .slice(0, index)\n .reduce((sum, b) => sum + b.length, 0);\n opts.onProgress(completed, contracts.length);\n }\n\n // Execute batch using viem's multicall\n return client.multicall({\n ...parameters,\n contracts: batch as typeof contracts,\n multicallAddress: opts.multicallAddress,\n allowFailure: opts.allowFailure,\n });\n }),\n );\n\n // Report final progress\n if (opts.onProgress) {\n opts.onProgress(contracts.length, contracts.length);\n }\n\n // Flatten results\n return batchResults.flat() as MulticallReturnType<TContracts, TAllowFailure>;\n}\n\n/**\n * Creates optimally-sized batches using greedy algorithm with checkpoints.\n *\n * @param client - The viem public client for making RPC calls\n * @param contracts - Array of contract function configurations to batch\n * @param options - Normalized batching options with limits and settings\n * @returns Array of optimally-sized contract function configuration batches\n */\nasync function createBatches(\n client: PublicClient,\n contracts: readonly ContractFunctionConfig[],\n options: NormalizedOptions,\n): Promise<ContractFunctionConfig[][]> {\n const batches: ContractFunctionConfig[][] = [];\n let currentBatch: ContractFunctionConfig[] = [];\n let currentBytes = 0;\n let lastCheckpointIndex = 0;\n let lastCheckpointBytes = 0;\n let lastEstimatedGas = 0n;\n\n for (let i = 0; i < contracts.length; i++) {\n const contract = contracts[i];\n\n // Calculate encoded size for this call\n const encoded = encodeContractCall(contract);\n const callBytes = size(encoded);\n\n // Check if we need a gas checkpoint\n const callsSinceCheckpoint = i - lastCheckpointIndex;\n const bytesSinceCheckpoint = currentBytes - lastCheckpointBytes;\n\n const needsCheckpoint =\n callsSinceCheckpoint >= options.checkpointFrequency.calls ||\n bytesSinceCheckpoint >= options.checkpointFrequency.bytes;\n\n // Perform checkpoint if needed\n if (needsCheckpoint && currentBatch.length > 0) {\n try {\n lastEstimatedGas = await estimateBatchGas(\n client,\n currentBatch,\n options.multicallAddress,\n );\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n } catch (error) {\n // If estimation fails, finalize current batch to be safe\n if (currentBatch.length > 1) {\n // Try with half the batch\n const halfBatch = currentBatch.slice(\n 0,\n Math.floor(currentBatch.length / 2),\n );\n batches.push(halfBatch);\n currentBatch = currentBatch.slice(halfBatch.length);\n currentBytes = calculateBatchSize(currentBatch);\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n lastEstimatedGas = 0n;\n } else {\n // Single call failed, skip it or throw based on allowFailure\n if (!options.allowFailure) {\n throw new Error(`Gas estimation failed for call ${i}: ${error}`);\n }\n currentBatch = [];\n currentBytes = 0;\n continue;\n }\n }\n }\n\n // Check if adding this call would exceed limits\n const wouldExceedCalldata =\n currentBytes + callBytes > options.maxCalldataBytes;\n const wouldExceedGas =\n lastEstimatedGas > 0n &&\n estimateNextGas(lastEstimatedGas, callsSinceCheckpoint + 1) >\n options.maxGasPerBatch;\n\n // If we would exceed limits, finalize current batch\n if ((wouldExceedCalldata || wouldExceedGas) && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBytes = 0;\n lastCheckpointIndex = i;\n lastCheckpointBytes = 0;\n lastEstimatedGas = 0n;\n }\n\n // Add call to current batch\n currentBatch.push(contract);\n currentBytes += callBytes;\n }\n\n // Add final batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n/**\n * Encodes a contract call to measure its calldata size.\n *\n * @param contract - The contract function configuration to encode\n * @returns Hex-encoded function data\n */\nfunction encodeContractCall(contract: ContractFunctionConfig): Hex {\n const { abi, functionName, args } = contract;\n\n return encodeFunctionData({\n abi,\n functionName,\n args,\n } as EncodeFunctionDataParameters);\n}\n\n/**\n * Calculates total encoded size of a batch.\n *\n * @param batch - Array of contract function configurations to measure\n * @returns Total size in bytes of all encoded calls in the batch\n */\nfunction calculateBatchSize(batch: ContractFunctionConfig[]): number {\n return batch.reduce((total, contract) => {\n const encoded = encodeContractCall(contract);\n return total + size(encoded);\n }, 0);\n}\n\n/**\n * Estimates gas for a batch of calls via multicall3.\n *\n * @param client - The viem public client for gas estimation\n * @param batch - Array of contract calls to estimate gas for\n * @param multicallAddress - The multicall3 contract address to use\n * @returns Estimated gas cost for executing the batch\n */\nasync function estimateBatchGas(\n client: PublicClient,\n batch: ContractFunctionConfig[],\n multicallAddress: Address,\n): Promise<bigint> {\n // Encode batch as multicall3 aggregate3 call\n const calls = batch.map((contract) => ({\n target: contract.address,\n allowFailure: false,\n callData: encodeContractCall(contract),\n }));\n\n // Estimate gas for the multicall\n const gas = await client.estimateGas({\n to: multicallAddress,\n data: encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [calls],\n }),\n });\n\n return gas;\n}\n\n/**\n * Extrapolates gas usage for calls added since last checkpoint.\n *\n * @remarks\n * Uses a conservative 1.1x multiplier for safety to account for gas usage variations.\n *\n * @param lastGas - The gas estimate from the last checkpoint\n * @param callsSinceCheckpoint - Number of calls added since the checkpoint\n * @returns Extrapolated gas estimate with safety margin\n */\nfunction estimateNextGas(\n lastGas: bigint,\n callsSinceCheckpoint: number,\n): bigint {\n if (callsSinceCheckpoint === 0) return lastGas;\n\n // Assume linear scaling with safety factor\n const avgGasPerCall = lastGas / BigInt(Math.max(1, callsSinceCheckpoint - 1));\n const estimatedGas = lastGas + avgGasPerCall;\n\n // Apply 10% safety margin\n return (estimatedGas * 110n) / 100n;\n}\n\n/**\n * Minimal multicall3 ABI for gas estimation\n */\nconst multicall3Abi = [\n {\n name: \"aggregate3\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"allowFailure\", type: \"bool\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n },\n] as const;\n\n/**\n * Utility function to analyze calls and predict optimal batch configuration\n *\n * @remarks\n * This function helps determine the best configuration for a specific set of calls\n * by analyzing their characteristics. Useful for optimizing repeated operations.\n *\n * @param contracts - The calls to analyze\n * @returns Suggested configuration based on call analysis\n */\nexport function analyzeCallsForOptimalConfig(\n contracts: readonly ContractFunctionConfig[],\n): Pick<GasAwareMulticallOptions, \"checkpointFrequency\" | \"maxCalldataBytes\"> {\n // Calculate average call size\n const totalBytes = contracts.reduce((sum, contract) => {\n const encoded = encodeContractCall(contract);\n return sum + size(encoded);\n }, 0);\n\n const avgBytesPerCall = totalBytes / contracts.length;\n\n // Suggest checkpoint frequency based on call density\n const checkpointFrequency = {\n calls: avgBytesPerCall > 500 ? 16 : 32, // More frequent for large calls\n bytes: avgBytesPerCall > 500 ? 4096 : 8192,\n };\n\n // Suggest calldata limit based on total size\n // For 1000 calls with small arrays, totalBytes will be much less than 500KB,\n // so use number of contracts as additional signal\n const maxCalldataBytes =\n totalBytes > 50_000 || contracts.length > 500 ? 128_000 : 100_000;\n\n return {\n checkpointFrequency,\n maxCalldataBytes,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/multicall.ts"],"sourcesContent":["import type {\n Address,\n PublicClient,\n MulticallParameters,\n MulticallReturnType,\n EncodeFunctionDataParameters,\n Hex,\n Abi,\n} from \"viem\";\nimport { encodeFunctionData, size } from \"viem\";\nimport { getUtilityAddress } from \"../config/addresses\";\nimport type { VanaChainId } from \"../types\";\n\n/**\n * Type for a contract function configuration used in multicall\n */\nexport interface ContractFunctionConfig {\n address: Address;\n abi: Abi;\n functionName: string;\n args?: readonly unknown[];\n}\n\n/**\n * Configuration options for gas-aware multicall batching.\n *\n * @remarks\n * These options control how the multicall utility splits large batches\n * to stay within gas and calldata limits. The defaults are conservative\n * to ensure compatibility across different chains and RPC providers.\n */\nexport interface GasAwareMulticallOptions {\n /**\n * Maximum gas per batch. Defaults to 10M (conservative for most chains).\n *\n * @remarks\n * This should be set below the block gas limit of your target chain.\n * Common values:\n * - Vana mainnet: 30M (use 25M for safety)\n * - Vana moksha: 30M (use 25M for safety)\n * - Ethereum mainnet: 30M (use 25M for safety)\n * - Arbitrum: 32M (use 25M for safety)\n */\n maxGasPerBatch?: bigint;\n\n /**\n * Maximum calldata size per batch in bytes. Defaults to 100KB.\n *\n * @remarks\n * This is particularly important for L2 chains where calldata is expensive.\n * Some RPC providers also have limits on request size.\n */\n maxCalldataBytes?: number;\n\n /**\n * How often to checkpoint gas estimates. Defaults to every 32 calls or 8KB.\n *\n * @remarks\n * More frequent checkpoints give more accurate batching but require more\n * RPC calls for gas estimation. The default balances accuracy vs performance.\n */\n checkpointFrequency?: {\n /** Checkpoint after this many calls */\n calls: number;\n /** Checkpoint after this many bytes of calldata */\n bytes: number;\n };\n\n /**\n * Whether to allow partial batch failures. Defaults to false.\n *\n * @remarks\n * When true, individual call failures won't fail the entire batch.\n * This matches viem's multicall behavior with allowFailure option.\n */\n allowFailure?: boolean;\n\n /**\n * Optional multicall3 contract address override.\n *\n * @remarks\n * By default, uses the standard multicall3 address deployed on most chains:\n * 0xcA11bde05977b3631167028862bE2a173976CA11\n */\n multicallAddress?: Address;\n\n /**\n * Optional callback for tracking batching progress.\n *\n * @remarks\n * Useful for showing progress in UI or debugging batch performance.\n */\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Internal configuration with defaults applied\n */\ninterface NormalizedOptions {\n maxGasPerBatch: bigint;\n maxCalldataBytes: number;\n checkpointFrequency: {\n calls: number;\n bytes: number;\n };\n allowFailure: boolean;\n multicallAddress: Address;\n onProgress?: (completed: number, total: number) => void;\n}\n\n/**\n * Default configuration values\n */\nconst DEFAULT_OPTIONS: Omit<NormalizedOptions, \"multicallAddress\"> = {\n maxGasPerBatch: 10_000_000n, // 10M gas - conservative default\n maxCalldataBytes: 100_000, // 100KB - works with most RPC providers\n checkpointFrequency: {\n calls: 32,\n bytes: 8192, // 8KB\n },\n allowFailure: false,\n};\n\n/**\n * A gas-aware multicall function that automatically batches calls to stay within limits.\n *\n * @remarks\n * This function extends viem's multicall with intelligent batching based on:\n * - Actual gas costs (via periodic estimateGas calls)\n * - Calldata size limits\n * - Chain-specific constraints\n *\n * It uses a greedy algorithm with periodic checkpoints to efficiently determine\n * optimal batch sizes without making excessive RPC calls.\n *\n * @param client - The viem public client to use for RPC calls\n * @param parameters - The multicall parameters (same as viem's multicall)\n * @param options - Optional configuration for gas-aware batching\n * @returns The aggregated results from all batches\n *\n * @example\n * ```typescript\n * // Basic usage - drop-in replacement for viem's multicall\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: [\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address1] },\n * { address: '0x...', abi: erc20Abi, functionName: 'balanceOf', args: [address2] },\n * // ... hundreds more calls\n * ]\n * });\n *\n * // With custom limits for a specific chain\n * const results = await gasAwareMulticall(publicClient, {\n * contracts: calls,\n * }, {\n * maxGasPerBatch: 25_000_000n, // 25M for mainnet\n * maxCalldataBytes: 128_000, // 128KB\n * onProgress: (done, total) => console.log(`Progress: ${done}/${total}`)\n * });\n * ```\n */\nexport async function gasAwareMulticall<\n TContracts extends readonly ContractFunctionConfig[],\n TAllowFailure extends boolean = false,\n>(\n client: PublicClient,\n parameters: MulticallParameters<TContracts, TAllowFailure>,\n options: GasAwareMulticallOptions = {},\n): Promise<MulticallReturnType<TContracts, TAllowFailure>> {\n // Get the chain-specific Multicall3 address\n const chainId = await client.getChainId();\n const multicall3Address =\n options.multicallAddress ??\n getUtilityAddress(chainId as VanaChainId, \"Multicall3\");\n\n // Normalize options with defaults\n const opts: NormalizedOptions = {\n ...DEFAULT_OPTIONS,\n ...options,\n multicallAddress: multicall3Address,\n checkpointFrequency: {\n ...DEFAULT_OPTIONS.checkpointFrequency,\n ...options.checkpointFrequency,\n },\n };\n\n // Override allowFailure if specified in parameters\n if (parameters.allowFailure !== undefined) {\n opts.allowFailure = parameters.allowFailure;\n }\n\n const { contracts } = parameters;\n if (!contracts || contracts.length === 0) {\n // TODO(TYPES): Empty array needs to match complex generic return type.\n // Future improvement: Use conditional types to properly type empty results\n // based on TAllowFailure parameter. Consider creating utility type helper.\n return [] as unknown as MulticallReturnType<TContracts, TAllowFailure>;\n }\n\n // Execute batching algorithm\n const batches = await createBatches(\n client,\n contracts as readonly ContractFunctionConfig[],\n opts,\n );\n\n // Execute all batches in parallel\n const batchResults = await Promise.all(\n batches.map((batch, index) => {\n // Report progress if callback provided\n if (opts.onProgress && index > 0) {\n const completed = batches\n .slice(0, index)\n .reduce((sum, b) => sum + b.length, 0);\n opts.onProgress(completed, contracts.length);\n }\n\n // Execute batch using viem's multicall\n return client.multicall({\n ...parameters,\n contracts: batch as typeof contracts,\n multicallAddress: opts.multicallAddress,\n allowFailure: opts.allowFailure,\n });\n }),\n );\n\n // Report final progress\n if (opts.onProgress) {\n opts.onProgress(contracts.length, contracts.length);\n }\n\n // Flatten results\n return batchResults.flat() as MulticallReturnType<TContracts, TAllowFailure>;\n}\n\n/**\n * Creates optimally-sized batches using greedy algorithm with checkpoints.\n *\n * @param client - The viem public client for making RPC calls\n * @param contracts - Array of contract function configurations to batch\n * @param options - Normalized batching options with limits and settings\n * @returns Array of optimally-sized contract function configuration batches\n */\nasync function createBatches(\n client: PublicClient,\n contracts: readonly ContractFunctionConfig[],\n options: NormalizedOptions,\n): Promise<ContractFunctionConfig[][]> {\n const batches: ContractFunctionConfig[][] = [];\n let currentBatch: ContractFunctionConfig[] = [];\n let currentBytes = 0;\n let lastCheckpointIndex = 0;\n let lastCheckpointBytes = 0;\n let lastEstimatedGas = 0n;\n\n for (let i = 0; i < contracts.length; i++) {\n const contract = contracts[i];\n\n // Calculate encoded size for this call\n const encoded = encodeContractCall(contract);\n const callBytes = size(encoded);\n\n // Check if we need a gas checkpoint\n const callsSinceCheckpoint = i - lastCheckpointIndex;\n const bytesSinceCheckpoint = currentBytes - lastCheckpointBytes;\n\n const needsCheckpoint =\n callsSinceCheckpoint >= options.checkpointFrequency.calls ||\n bytesSinceCheckpoint >= options.checkpointFrequency.bytes;\n\n // Perform checkpoint if needed\n if (needsCheckpoint && currentBatch.length > 0) {\n try {\n lastEstimatedGas = await estimateBatchGas(\n client,\n currentBatch,\n options.multicallAddress,\n );\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n } catch (error) {\n // If estimation fails, finalize current batch to be safe\n if (currentBatch.length > 1) {\n // Try with half the batch\n const halfBatch = currentBatch.slice(\n 0,\n Math.floor(currentBatch.length / 2),\n );\n batches.push(halfBatch);\n currentBatch = currentBatch.slice(halfBatch.length);\n currentBytes = calculateBatchSize(currentBatch);\n lastCheckpointIndex = i;\n lastCheckpointBytes = currentBytes;\n lastEstimatedGas = 0n;\n } else {\n // Single call failed, skip it or throw based on allowFailure\n if (!options.allowFailure) {\n throw new Error(\n `Gas estimation failed for call ${i}: ${String(error)}`,\n );\n }\n currentBatch = [];\n currentBytes = 0;\n continue;\n }\n }\n }\n\n // Check if adding this call would exceed limits\n const wouldExceedCalldata =\n currentBytes + callBytes > options.maxCalldataBytes;\n const wouldExceedGas =\n lastEstimatedGas > 0n &&\n estimateNextGas(lastEstimatedGas, callsSinceCheckpoint + 1) >\n options.maxGasPerBatch;\n\n // If we would exceed limits, finalize current batch\n if ((wouldExceedCalldata || wouldExceedGas) && currentBatch.length > 0) {\n batches.push(currentBatch);\n currentBatch = [];\n currentBytes = 0;\n lastCheckpointIndex = i;\n lastCheckpointBytes = 0;\n lastEstimatedGas = 0n;\n }\n\n // Add call to current batch\n currentBatch.push(contract);\n currentBytes += callBytes;\n }\n\n // Add final batch if not empty\n if (currentBatch.length > 0) {\n batches.push(currentBatch);\n }\n\n return batches;\n}\n\n/**\n * Encodes a contract call to measure its calldata size.\n *\n * @param contract - The contract function configuration to encode\n * @returns Hex-encoded function data\n */\nfunction encodeContractCall(contract: ContractFunctionConfig): Hex {\n const { abi, functionName, args } = contract;\n\n return encodeFunctionData({\n abi,\n functionName,\n args,\n } as EncodeFunctionDataParameters);\n}\n\n/**\n * Calculates total encoded size of a batch.\n *\n * @param batch - Array of contract function configurations to measure\n * @returns Total size in bytes of all encoded calls in the batch\n */\nfunction calculateBatchSize(batch: ContractFunctionConfig[]): number {\n return batch.reduce((total, contract) => {\n const encoded = encodeContractCall(contract);\n return total + size(encoded);\n }, 0);\n}\n\n/**\n * Estimates gas for a batch of calls via multicall3.\n *\n * @param client - The viem public client for gas estimation\n * @param batch - Array of contract calls to estimate gas for\n * @param multicallAddress - The multicall3 contract address to use\n * @returns Estimated gas cost for executing the batch\n */\nasync function estimateBatchGas(\n client: PublicClient,\n batch: ContractFunctionConfig[],\n multicallAddress: Address,\n): Promise<bigint> {\n // Encode batch as multicall3 aggregate3 call\n const calls = batch.map((contract) => ({\n target: contract.address,\n allowFailure: false,\n callData: encodeContractCall(contract),\n }));\n\n // Estimate gas for the multicall\n const gas = await client.estimateGas({\n to: multicallAddress,\n data: encodeFunctionData({\n abi: multicall3Abi,\n functionName: \"aggregate3\",\n args: [calls],\n }),\n });\n\n return gas;\n}\n\n/**\n * Extrapolates gas usage for calls added since last checkpoint.\n *\n * @remarks\n * Uses a conservative 1.1x multiplier for safety to account for gas usage variations.\n *\n * @param lastGas - The gas estimate from the last checkpoint\n * @param callsSinceCheckpoint - Number of calls added since the checkpoint\n * @returns Extrapolated gas estimate with safety margin\n */\nfunction estimateNextGas(\n lastGas: bigint,\n callsSinceCheckpoint: number,\n): bigint {\n if (callsSinceCheckpoint === 0) return lastGas;\n\n // Assume linear scaling with safety factor\n const avgGasPerCall = lastGas / BigInt(Math.max(1, callsSinceCheckpoint - 1));\n const estimatedGas = lastGas + avgGasPerCall;\n\n // Apply 10% safety margin\n return (estimatedGas * 110n) / 100n;\n}\n\n/**\n * Minimal multicall3 ABI for gas estimation\n */\nconst multicall3Abi = [\n {\n name: \"aggregate3\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"allowFailure\", type: \"bool\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n },\n] as const;\n\n/**\n * Utility function to analyze calls and predict optimal batch configuration\n *\n * @remarks\n * This function helps determine the best configuration for a specific set of calls\n * by analyzing their characteristics. Useful for optimizing repeated operations.\n *\n * @param contracts - The calls to analyze\n * @returns Suggested configuration based on call analysis\n */\nexport function analyzeCallsForOptimalConfig(\n contracts: readonly ContractFunctionConfig[],\n): Pick<GasAwareMulticallOptions, \"checkpointFrequency\" | \"maxCalldataBytes\"> {\n // Calculate average call size\n const totalBytes = contracts.reduce((sum, contract) => {\n const encoded = encodeContractCall(contract);\n return sum + size(encoded);\n }, 0);\n\n const avgBytesPerCall = totalBytes / contracts.length;\n\n // Suggest checkpoint frequency based on call density\n const checkpointFrequency = {\n calls: avgBytesPerCall > 500 ? 16 : 32, // More frequent for large calls\n bytes: avgBytesPerCall > 500 ? 4096 : 8192,\n };\n\n // Suggest calldata limit based on total size\n // For 1000 calls with small arrays, totalBytes will be much less than 500KB,\n // so use number of contracts as additional signal\n const maxCalldataBytes =\n totalBytes > 50_000 || contracts.length > 500 ? 128_000 : 100_000;\n\n return {\n checkpointFrequency,\n maxCalldataBytes,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/parseTransactionPojo.ts"],"sourcesContent":["/**\n * Transaction parsing with POJO support and NO heuristics.\n
|
|
1
|
+
{"version":3,"sources":["../../src/utils/parseTransactionPojo.ts"],"sourcesContent":["/**\n * Transaction parsing with POJO support and NO heuristics.\n *\n * @remarks\n * This is the new POJO-based parser that works with TransactionResult objects.\n * Principle: Explicit over implicit, guarantees over guesses.\n */\n\nimport { decodeEventLog, type TransactionReceipt } from \"viem\";\nimport type { TransactionResult } from \"../types/operations\";\nimport type {\n TypedTransactionResult,\n Contract,\n Fn,\n ExpectedEvents,\n} from \"../generated/event-types\";\nimport { EVENT_REGISTRY, TOPIC_TO_ABIS } from \"../generated/eventRegistry\";\n\n/**\n * Parses a transaction using TransactionResult POJO with ZERO heuristics.\n *\n * @remarks\n * - Uses function-scoped event registry for O(1) lookups\n * - Only expects events explicitly mapped for this contract.function\n * - Returns typed events matching the exact TypedTransactionResult interface\n *\n * @param transactionResult - The TransactionResult POJO with context\n * @param transactionResult.hash - Transaction hash\n * @param transactionResult.from - Transaction sender address\n * @param transactionResult.contract - Contract name\n * @param transactionResult.fn - Function name\n * @param transactionResult.chainId - Optional chain ID\n * @param transactionResult.value - Optional transaction value\n * @param transactionResult.nonce - Optional nonce\n * @param transactionResult.to - Optional recipient address\n * @param receipt - The transaction receipt from the blockchain\n * @returns Typed transaction result with parsed events\n */\nexport function parseTransaction<C extends Contract, F extends Fn<C>>(\n transactionResult: TransactionResult<C, F>,\n receipt: TransactionReceipt,\n): TypedTransactionResult<C, F> {\n const { contract: contractName, fn: functionName } = transactionResult;\n\n // Look up expected events from the function-specific registry\n const registryKey = `${contractName}.${functionName}`;\n const registry = EVENT_REGISTRY[registryKey];\n\n // Initialize the expected events object with proper types\n const expectedEvents: Record<string, unknown> = {};\n const allEvents: Array<{\n contractAddress: string;\n eventName: string;\n args: Record<string, unknown>;\n logIndex: number;\n }> = [];\n\n let hasExpectedEvents = false;\n\n if (receipt.logs) {\n // Parse logs using the function-scoped registry\n for (const log of receipt.logs) {\n if (!log.topics || log.topics.length === 0) {\n // Skip malformed logs\n continue;\n }\n\n const eventTopic = log.topics[0] as `0x${string}`;\n\n // Try to decode using TOPIC_TO_ABIS for O(1) lookup\n const abiCandidates = TOPIC_TO_ABIS.get(eventTopic);\n\n if (abiCandidates && abiCandidates.length > 0) {\n // Try each ABI variant (handles collisions)\n for (const abiEvent of abiCandidates) {\n try {\n const decoded = decodeEventLog({\n abi: [abiEvent],\n data: log.data,\n topics: log.topics as [`0x${string}`, ...`0x${string}`[]],\n });\n\n // Add to allEvents\n allEvents.push({\n contractAddress: log.address || \"\",\n eventName: decoded.eventName,\n args: decoded.args as Record<string, unknown>,\n logIndex: log.logIndex ?? 0,\n });\n\n // If this event is expected for this function, add to expectedEvents\n if (registry && registry.eventNames.includes(decoded.eventName)) {\n expectedEvents[decoded.eventName] = decoded.args;\n hasExpectedEvents = true;\n }\n\n break; // Successfully decoded, don't try other variants\n } catch {\n // Try next ABI variant\n continue;\n }\n }\n } else {\n // Event not decodable, add as unknown\n allEvents.push({\n contractAddress: log.address || \"\",\n eventName: \"Unknown\",\n args: { topic0: eventTopic, data: log.data },\n logIndex: log.logIndex ?? 0,\n });\n }\n }\n }\n\n // Return a properly typed TypedTransactionResult\n return {\n hash: transactionResult.hash,\n from: transactionResult.from,\n contract: contractName,\n fn: functionName,\n expectedEvents: expectedEvents as ExpectedEvents<C, F>,\n allEvents,\n hasExpectedEvents,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,kBAAwD;AAQxD,2BAA8C;AAsBvC,SAAS,iBACd,mBACA,SAC8B;AAC9B,QAAM,EAAE,UAAU,cAAc,IAAI,aAAa,IAAI;AAGrD,QAAM,cAAc,GAAG,YAAY,IAAI,YAAY;AACnD,QAAM,WAAW,oCAAe,WAAW;AAG3C,QAAM,iBAA0C,CAAC;AACjD,QAAM,YAKD,CAAC;AAEN,MAAI,oBAAoB;AAExB,MAAI,QAAQ,MAAM;AAEhB,eAAW,OAAO,QAAQ,MAAM;AAC9B,UAAI,CAAC,IAAI,UAAU,IAAI,OAAO,WAAW,GAAG;AAE1C;AAAA,MACF;AAEA,YAAM,aAAa,IAAI,OAAO,CAAC;AAG/B,YAAM,gBAAgB,mCAAc,IAAI,UAAU;AAElD,UAAI,iBAAiB,cAAc,SAAS,GAAG;AAE7C,mBAAW,YAAY,eAAe;AACpC,cAAI;AACF,kBAAM,cAAU,4BAAe;AAAA,cAC7B,KAAK,CAAC,QAAQ;AAAA,cACd,MAAM,IAAI;AAAA,cACV,QAAQ,IAAI;AAAA,YACd,CAAC;AAGD,sBAAU,KAAK;AAAA,cACb,iBAAiB,IAAI,WAAW;AAAA,cAChC,WAAW,QAAQ;AAAA,cACnB,MAAM,QAAQ;AAAA,cACd,UAAU,IAAI,YAAY;AAAA,YAC5B,CAAC;AAGD,gBAAI,YAAY,SAAS,WAAW,SAAS,QAAQ,SAAS,GAAG;AAC/D,6BAAe,QAAQ,SAAS,IAAI,QAAQ;AAC5C,kCAAoB;AAAA,YACtB;AAEA;AAAA,UACF,QAAQ;AAEN;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AAEL,kBAAU,KAAK;AAAA,UACb,iBAAiB,IAAI,WAAW;AAAA,UAChC,WAAW;AAAA,UACX,MAAM,EAAE,QAAQ,YAAY,MAAM,IAAI,KAAK;AAAA,UAC3C,UAAU,IAAI,YAAY;AAAA,QAC5B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL,MAAM,kBAAkB;AAAA,IACxB,MAAM,kBAAkB;AAAA,IACxB,UAAU;AAAA,IACV,IAAI;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { TransactionReceipt } from 'viem';
|
|
2
|
-
import { TransactionResult } from '../types/operations.js';
|
|
3
|
-
import { Contract, Fn, TypedTransactionResult } from '../generated/event-types.js';
|
|
4
|
-
import '../generated/server/server-exports.js';
|
|
5
|
-
import '../generated/server/server.js';
|
|
6
|
-
|
|
7
1
|
/**
|
|
8
2
|
* Transaction parsing with POJO support and NO heuristics.
|
|
9
3
|
*
|
|
@@ -11,7 +5,9 @@ import '../generated/server/server.js';
|
|
|
11
5
|
* This is the new POJO-based parser that works with TransactionResult objects.
|
|
12
6
|
* Principle: Explicit over implicit, guarantees over guesses.
|
|
13
7
|
*/
|
|
14
|
-
|
|
8
|
+
import { type TransactionReceipt } from "viem";
|
|
9
|
+
import type { TransactionResult } from "../types/operations";
|
|
10
|
+
import type { TypedTransactionResult, Contract, Fn } from "../generated/event-types";
|
|
15
11
|
/**
|
|
16
12
|
* Parses a transaction using TransactionResult POJO with ZERO heuristics.
|
|
17
13
|
*
|
|
@@ -32,6 +28,4 @@ import '../generated/server/server.js';
|
|
|
32
28
|
* @param receipt - The transaction receipt from the blockchain
|
|
33
29
|
* @returns Typed transaction result with parsed events
|
|
34
30
|
*/
|
|
35
|
-
declare function parseTransaction<C extends Contract, F extends Fn<C>>(transactionResult: TransactionResult<C, F>, receipt: TransactionReceipt): TypedTransactionResult<C, F>;
|
|
36
|
-
|
|
37
|
-
export { parseTransaction };
|
|
31
|
+
export declare function parseTransaction<C extends Contract, F extends Fn<C>>(transactionResult: TransactionResult<C, F>, receipt: TransactionReceipt): TypedTransactionResult<C, F>;
|