diff --git a/.github/release-please-config.json b/.github/release-please-config.json index ecc40841..d4b544c2 100644 --- a/.github/release-please-config.json +++ b/.github/release-please-config.json @@ -32,6 +32,11 @@ "hidden": false } ] + }, + "packages/synapse-core": { + "bump-minor-pre-major": true, + "pull-request-header": "šŸ“¦ Release Preparation", + "pull-request-footer": "\n\n## šŸš€ How to Release\n\n1. **Review** the changelog and version bump in this PR\n2. **Merge this PR** to trigger the release\n3. After merging, the workflow will:\n - Create a GitHub release with tag ${version}\n - Publish to npm automatically\n4. Wait until the workflow is complete before merging another release PR\n\nāš ļø **Note**: The release has NOT been created yet. It will only be created after you merge this PR." } } } diff --git a/.github/release-please-manifest.json b/.github/release-please-manifest.json index a02a71a5..f6792332 100644 --- a/.github/release-please-manifest.json +++ b/.github/release-please-manifest.json @@ -1,3 +1,4 @@ { - "packages/synapse-sdk": "0.31.1" + "packages/synapse-sdk": "0.31.1", + "packages/synapse-core": "0.0.1" } diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index ac9df97a..5135e66e 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -26,7 +26,8 @@ jobs: npm: needs: release if: | - contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-sdk') + contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-sdk') || + contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-core') runs-on: ubuntu-latest permissions: contents: read @@ -49,6 +50,7 @@ jobs: docs: needs: release if: | - contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-sdk') + contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-sdk') || + contains(fromJson(needs.release.outputs.paths_released), 'packages/synapse-core') uses: ./.github/workflows/docs.yml secrets: inherit diff --git a/.github/workflows/synapse-core.yml b/.github/workflows/synapse-core.yml new file mode 100644 index 00000000..fc06f699 --- /dev/null +++ b/.github/workflows/synapse-core.yml @@ -0,0 +1,41 @@ +name: synapse-core +on: + push: + branches: + - master + paths: + - "packages/synapse-core/**" + - .github/workflows/synapse-core.yml + pull_request: + paths: + - "packages/synapse-core/**" + - .github/workflows/synapse-core.yml +jobs: + test: + strategy: + fail-fast: false + matrix: + node: [lts/*, current] + os: [macos-latest, ubuntu-latest, windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout Repository + uses: actions/checkout@v5 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: latest + - name: Use Node.js ${{ matrix.node }} + uses: actions/setup-node@v5 + with: + node-version: ${{ matrix.node }} + - name: Playwright for Windows + if: matrix.os == 'windows-latest' + run: pnpx playwright install winldd + - name: Install Dependencies + run: pnpm install + # - name: Run tests + # run: pnpm -r --filter @filoz/synapse-core run test + # shell: bash + - name: Check docs build + run: pnpm -r --filter docs run build diff --git a/.github/workflows/synapse-sdk.yml b/.github/workflows/synapse-sdk.yml index c0a1b045..3322d82a 100644 --- a/.github/workflows/synapse-sdk.yml +++ b/.github/workflows/synapse-sdk.yml @@ -35,8 +35,7 @@ jobs: - name: Install Dependencies run: pnpm install - name: Run tests - run: | - pnpm config set script-shell bash - pnpm -r --filter @filoz/synapse-sdk run test + run: pnpm -r --filter @filoz/synapse-sdk run test + shell: bash - name: Check docs build run: pnpm -r --filter docs run build diff --git a/.gitignore b/.gitignore index 313f10bb..2efa340f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ filecoin-project-*/ # VIM *.swp .env +.wireit/ \ No newline at end of file diff --git a/biome.json b/biome.json index 8356931e..74261fc7 100644 --- a/biome.json +++ b/biome.json @@ -32,7 +32,8 @@ "!**/__snapshots__", "!**/components.d.ts", "!**/mockServiceWorker.js", - "!**/abis/gen.ts" + "!**/abis/gen.ts", + "!packages/synapse-core/src/gen.ts" ] }, "vcs": { diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index e0b64981..3a0201db 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -91,7 +91,7 @@ export default defineConfig({ parametersFormat: 'table', indexFormat: 'table', groupOrder: ['classes', 'functions', 'variables', 'types', '*'], - plugin: ['typedoc-plugin-mdn-links', 'typedoc-plugin-missing-exports'], + plugin: ['typedoc-plugin-mdn-links'], }, }), starlightLlmsTxt(), diff --git a/package.json b/package.json index 1209aae0..b0106741 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "@biomejs/biome": "~2.2.5", "knip": "^5.64.1", "markdownlint-cli2": "^0.18.1", - "typescript": "5.9.3" + "typescript": "5.9.3", + "wireit": "^0.14.12" }, "simple-git-hooks": { "pre-commit": "pnpm exec biome check --no-errors-on-unmatched --files-ignore-unknown=true --staged" diff --git a/packages/synapse-core/README.md b/packages/synapse-core/README.md new file mode 100644 index 00000000..17f1a3ee --- /dev/null +++ b/packages/synapse-core/README.md @@ -0,0 +1,32 @@ +# Synapse Core + +[![NPM](https://nodei.co/npm/@filoz/synapse-sdk.svg?style=flat&data=n,v&color=blue)](https://nodei.co/npm/@filoz/synapse-core/) + +> A JavaScript/TypeScript SDK for interacting with Filecoin Synapse - a smart-contract based marketplace for storage and other services in the Filecoin ecosystem. + +## Overview + +TODO + +## Installation + +```bash +pnpm install @filoz/synapse-core viem@2.x +``` + +Note: `viem` is a peer dependency and must be installed separately. + +## Docs + +Check the documentation [website](https://synapse.filecoin.services/) + +## Contributing + +Read contributing [guidelines](../../.github/CONTRIBUTING.md). + +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/FilOzone/synapse-sdk) + +## License + +Dual-licensed: [MIT](../../LICENSE.md), [Apache Software License v2](../../LICENSE.md) by way of the +[Permissive License Stack](https://protocol.ai/blog/announcing-the-permissive-license-stack/). diff --git a/packages/synapse-core/package.json b/packages/synapse-core/package.json new file mode 100644 index 00000000..15fb3564 --- /dev/null +++ b/packages/synapse-core/package.json @@ -0,0 +1,108 @@ +{ + "name": "@filoz/synapse-core", + "version": "0.0.1", + "description": "JavaScript Standard Library for Filecoin Onchain Cloud", + "repository": { + "type": "git", + "url": "git+https://github.com/FilOzone/synapse-sdk.git" + }, + "keywords": [ + "filecoin", + "synapse", + "filecoin pay", + "filecoin onchain cloud", + "web3" + ], + "author": "Hugo Dias ", + "license": "Apache-2.0 OR MIT", + "bugs": { + "url": "https://github.com/FilOzone/synapse-sdk/issues" + }, + "homepage": "https://github.com/FilOzone/synapse-sdk/tree/main/packages/synapse-core", + "type": "module", + "main": "dist/src/index.js", + "types": "dist/src/index.d.ts", + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "default": "./dist/src/index.js" + }, + "./chains": { + "types": "./dist/src/chains.d.ts", + "default": "./dist/src/chains.js" + }, + "./utils": { + "types": "./dist/src/utils.d.ts", + "default": "./dist/src/utils.js" + } + }, + "typesVersions": { + "*": { + "chains": [ + "./dist/src/chains" + ], + "utils": [ + "./dist/src/utils" + ] + } + }, + "files": [ + "src", + "dist/src", + "dist/src/**/*.d.ts", + "dist/src/**/*.d.ts.map" + ], + "scripts": { + "generate-abi": "wagmi generate", + "build": "wireit", + "lint": "wireit", + "test": "pnpm run lint && pnpm run test:node", + "test:node": "playwright-test 'src/test/**/*.test.ts' --mode node", + "test:browser": "playwright-test 'src/test/**/*.test.ts' --assets ./src/test/mocks" + }, + "wireit": { + "build": { + "command": "tsc --build --pretty", + "clean": "if-file-deleted", + "files": [ + "src/**/*.ts", + "tsconfig.json" + ], + "output": [ + "dist/**" + ] + }, + "lint": { + "command": "biome check --no-errors-on-unmatched --files-ignore-unknown=true .", + "files": [ + "src/**/*.ts", + "../../biome.json" + ], + "output": [], + "dependencies": [ + "build" + ] + } + }, + "devDependencies": { + "@biomejs/biome": "~2.2.5", + "@types/mocha": "^10.0.10", + "@types/node": "^24.6.2", + "@wagmi/cli": "^2.6.0", + "mocha": "^11.7.4", + "playwright-test": "^14.1.12", + "typescript": "5.9.3" + }, + "publishConfig": { + "access": "public" + }, + "msw": { + "workerDirectory": [ + "src/test/mocks" + ] + }, + "peerDependencies": { + "ethers": "6.x", + "viem": "2.x" + } +} diff --git a/packages/synapse-core/src/chains.ts b/packages/synapse-core/src/chains.ts new file mode 100644 index 00000000..8660279e --- /dev/null +++ b/packages/synapse-core/src/chains.ts @@ -0,0 +1,221 @@ +/** + * Synapse Core - Chains + * + * @example + * ```ts + * import * as Chains from '@filoz/synapse-core/chains' + * ``` + * + * @packageDocumentation + * @module Chains + */ + +import type { Address, ChainContract, Chain as ViemChain } from 'viem' +import { ERC20_WITH_PERMIT_ABI } from './constants.ts' +import * as generated from './gen.ts' + +/** + * Viem compatible chain interface with all the FOC contracts addresses and ABIs + */ +export interface Chain extends ViemChain { + contracts: { + multicall3: ChainContract + usdfc: { + address: Address + abi: typeof ERC20_WITH_PERMIT_ABI + } + payments: { + address: Address + abi: typeof generated.paymentsAbi + } + storage: { + address: Address + abi: typeof generated.filecoinWarmStorageServiceAbi + } + storageView: { + address: Address + abi: typeof generated.filecoinWarmStorageServiceStateViewAbi + } + serviceProviderRegistry: { + address: Address + abi: typeof generated.serviceProviderRegistryAbi + } + sessionKeyRegistry: { + address: Address + abi: typeof generated.sessionKeyRegistryAbi + } + pdp: { + address: Address + abi: typeof generated.pdpVerifierAbi + } + } +} + +/** + * Filecoin Mainnet + * + * Compatible with Viem + * + */ +export const mainnet: Chain = { + id: 314, + name: 'Filecoin - Mainnet', + nativeCurrency: { + name: 'Filecoin', + symbol: 'FIL', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://api.node.glif.io/rpc/v1'], + webSocket: ['wss://wss.node.glif.io/apigw/lotus/rpc/v1'], + }, + }, + blockExplorers: { + Beryx: { + name: 'Beryx', + url: 'https://beryx.io/fil/mainnet', + }, + Filfox: { + name: 'Filfox', + url: 'https://filfox.info', + }, + Glif: { + name: 'Glif', + url: 'https://www.glif.io/en', + }, + default: { + name: 'Blockscout', + url: 'https://filecoin.blockscout.com', + }, + }, + contracts: { + multicall3: { + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + blockCreated: 3328594, + }, + usdfc: { + address: '0x80B98d3aa09ffff255c3ba4A241111Ff1262F045', + abi: ERC20_WITH_PERMIT_ABI, + }, + payments: { + address: generated.paymentsAddress['314'], + abi: generated.paymentsAbi, + }, + storage: { + address: generated.filecoinWarmStorageServiceAddress['314'], + abi: generated.filecoinWarmStorageServiceAbi, + }, + storageView: { + address: generated.filecoinWarmStorageServiceStateViewAddress['314'], + abi: generated.filecoinWarmStorageServiceStateViewAbi, + }, + serviceProviderRegistry: { + address: generated.serviceProviderRegistryAddress['314'], + abi: generated.serviceProviderRegistryAbi, + }, + sessionKeyRegistry: { + address: generated.sessionKeyRegistryAddress['314'], + abi: generated.sessionKeyRegistryAbi, + }, + pdp: { + address: generated.pdpVerifierAddress['314'], + abi: generated.pdpVerifierAbi, + }, + }, +} + +/** + * Filecoin Calibration + * + * Compatible with Viem + * + */ +export const calibration: Chain = { + id: 314_159, + name: 'Filecoin - Calibration testnet', + nativeCurrency: { + name: 'Filecoin', + symbol: 'tFIL', + decimals: 18, + }, + rpcUrls: { + default: { + http: ['https://api.calibration.node.glif.io/rpc/v1'], + webSocket: ['wss://wss.calibration.node.glif.io/apigw/lotus/rpc/v1'], + }, + }, + blockExplorers: { + Beryx: { + name: 'Beryx', + url: 'https://beryx.io/fil/calibration', + }, + Filfox: { + name: 'Filfox', + url: 'https://calibration.filfox.info', + }, + Glif: { + name: 'Glif', + url: 'https://www.glif.io/en/calibrationnet', + }, + default: { + name: 'Blockscout', + url: 'https://filecoin-testnet.blockscout.com', + }, + }, + contracts: { + multicall3: { + address: '0xcA11bde05977b3631167028862bE2a173976CA11', + blockCreated: 1446201, + }, + usdfc: { + address: '0xb3042734b608a1B16e9e86B374A3f3e389B4cDf0', + abi: ERC20_WITH_PERMIT_ABI, + }, + payments: { + address: generated.paymentsAddress['314159'], + abi: generated.paymentsAbi, + }, + storage: { + address: generated.filecoinWarmStorageServiceAddress['314159'], + abi: generated.filecoinWarmStorageServiceAbi, + }, + storageView: { + address: generated.filecoinWarmStorageServiceStateViewAddress['314159'], + abi: generated.filecoinWarmStorageServiceStateViewAbi, + }, + serviceProviderRegistry: { + address: generated.serviceProviderRegistryAddress['314159'], + abi: generated.serviceProviderRegistryAbi, + }, + sessionKeyRegistry: { + address: generated.sessionKeyRegistryAddress['314159'], + abi: generated.sessionKeyRegistryAbi, + }, + pdp: { + address: generated.pdpVerifierAddress['314159'], + abi: generated.pdpVerifierAbi, + }, + }, + testnet: true, +} + +/** + * Get a chain by id + * + * @param [id] - The chain id. Defaults to mainnet. + */ +export function getChain(id?: number): Chain { + if (id == null) { + return mainnet + } + + switch (id) { + case 314: + return mainnet + case 314159: + return calibration + default: + throw new Error(`Chain with id ${id} not found`) + } +} diff --git a/packages/synapse-core/src/constants.ts b/packages/synapse-core/src/constants.ts new file mode 100644 index 00000000..3c9e2907 --- /dev/null +++ b/packages/synapse-core/src/constants.ts @@ -0,0 +1,25 @@ +import { erc20Abi } from 'viem' + +/** + * ERC20 ABI with Permit extension + * @see https://eips.ethereum.org/EIPS/eip-2612 + */ +export const ERC20_WITH_PERMIT_ABI = [ + ...erc20Abi, + ...[ + { + type: 'function', + stateMutability: 'view', + name: 'nonces', + inputs: [{ name: 'owner', type: 'address' }], + outputs: [{ name: '', type: 'uint256' }], + }, + { + type: 'function', + stateMutability: 'view', + name: 'version', + inputs: [], + outputs: [{ name: '', type: 'string' }], + }, + ], +] as const diff --git a/packages/synapse-core/src/errors/base.ts b/packages/synapse-core/src/errors/base.ts new file mode 100644 index 00000000..09e387a6 --- /dev/null +++ b/packages/synapse-core/src/errors/base.ts @@ -0,0 +1,34 @@ +import type { UnsupportedChainError } from './chains.ts' + +const symbol = Symbol.for('synapse-error') + +interface SynapseErrorOptions extends ErrorOptions { + cause?: Error +} + +/** + * Check if a value is a SynapseError + * + */ +export function isSynapseError(value: unknown): value is SynapseError { + return value instanceof Error && symbol in value +} + +export class SynapseError extends Error { + [symbol]: boolean = true + + override name = 'SynapseError' + override cause?: Error + + constructor(message: string, options?: SynapseErrorOptions) { + const causeString = options?.cause instanceof Error ? options.cause.message : undefined + + const msg = [message || 'Unknown error', ...(causeString ? [`Cause: ${causeString}`] : [])].join('\n') + super(msg, options) + this.cause = options?.cause ?? undefined + } + + static is(value: unknown): value is SynapseError { + return isSynapseError(value) && value.name === 'SynapseError' + } +} diff --git a/packages/synapse-core/src/errors/chains.ts b/packages/synapse-core/src/errors/chains.ts new file mode 100644 index 00000000..ffc13d99 --- /dev/null +++ b/packages/synapse-core/src/errors/chains.ts @@ -0,0 +1,16 @@ +import { calibration, mainnet } from '../chains.ts' +import { isSynapseError, SynapseError } from './base.ts' + +export class UnsupportedChainError extends SynapseError { + override name: 'UnsupportedChainError' = 'UnsupportedChainError' + + constructor(chainId: number) { + super( + `Unsupported chain: ${chainId} (only Filecoin mainnet (${mainnet.id}) and calibration (${calibration.id}) are supported)` + ) + } + + static override is(value: unknown): value is UnsupportedChainError { + return isSynapseError(value) && value.name === 'UnsupportedChainError' + } +} diff --git a/packages/synapse-sdk/src/abis/gen.ts b/packages/synapse-core/src/gen.ts similarity index 98% rename from packages/synapse-sdk/src/abis/gen.ts rename to packages/synapse-core/src/gen.ts index 842a5882..6106bf60 100644 --- a/packages/synapse-sdk/src/abis/gen.ts +++ b/packages/synapse-core/src/gen.ts @@ -4,7 +4,7 @@ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x80617b65FD2EEa1D7fDe2B4F85977670690ed348) */ export const filecoinWarmStorageServiceAbi = [ { @@ -1295,16 +1295,16 @@ export const filecoinWarmStorageServiceAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x80617b65FD2EEa1D7fDe2B4F85977670690ed348) */ export const filecoinWarmStorageServiceAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0x80617b65FD2EEa1D7fDe2B4F85977670690ed348', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x80617b65FD2EEa1D7fDe2B4F85977670690ed348) */ export const filecoinWarmStorageServiceConfig = { address: filecoinWarmStorageServiceAddress, @@ -1317,7 +1317,7 @@ export const filecoinWarmStorageServiceConfig = { /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x87EDE87cEF4BfeFE0374c3470cB3F5be18b739d5) */ export const filecoinWarmStorageServiceStateViewAbi = [ { @@ -1583,16 +1583,16 @@ export const filecoinWarmStorageServiceStateViewAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x87EDE87cEF4BfeFE0374c3470cB3F5be18b739d5) */ export const filecoinWarmStorageServiceStateViewAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0x87EDE87cEF4BfeFE0374c3470cB3F5be18b739d5', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x87EDE87cEF4BfeFE0374c3470cB3F5be18b739d5) */ export const filecoinWarmStorageServiceStateViewConfig = { address: filecoinWarmStorageServiceStateViewAddress, @@ -1605,7 +1605,7 @@ export const filecoinWarmStorageServiceStateViewConfig = { /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137) */ export const pdpVerifierAbi = [ { type: 'constructor', inputs: [], stateMutability: 'nonpayable' }, @@ -2347,16 +2347,16 @@ export const pdpVerifierAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137) */ export const pdpVerifierAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137) */ export const pdpVerifierConfig = { address: pdpVerifierAddress, @@ -2369,7 +2369,7 @@ export const pdpVerifierConfig = { /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x1096025c9D6B29E12E2f04965F6E64d564Ce0750) */ export const paymentsAbi = [ { type: 'constructor', inputs: [], stateMutability: 'nonpayable' }, @@ -3461,16 +3461,16 @@ export const paymentsAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x1096025c9D6B29E12E2f04965F6E64d564Ce0750) */ export const paymentsAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0x1096025c9D6B29E12E2f04965F6E64d564Ce0750', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x1096025c9D6B29E12E2f04965F6E64d564Ce0750) */ export const paymentsConfig = { address: paymentsAddress, @@ -3483,7 +3483,7 @@ export const paymentsConfig = { /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0xA8a7e2130C27e4f39D1aEBb3D538D5937bCf8ddb) */ export const serviceProviderRegistryAbi = [ { type: 'constructor', inputs: [], stateMutability: 'nonpayable' }, @@ -4540,16 +4540,16 @@ export const serviceProviderRegistryAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0xA8a7e2130C27e4f39D1aEBb3D538D5937bCf8ddb) */ export const serviceProviderRegistryAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0xA8a7e2130C27e4f39D1aEBb3D538D5937bCf8ddb', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0xA8a7e2130C27e4f39D1aEBb3D538D5937bCf8ddb) */ export const serviceProviderRegistryConfig = { address: serviceProviderRegistryAddress, @@ -4562,7 +4562,7 @@ export const serviceProviderRegistryConfig = { /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x97Dd879F5a97A8c761B94746d7F5cfF50AAd4452) */ export const sessionKeyRegistryAbi = [ { @@ -4612,16 +4612,16 @@ export const sessionKeyRegistryAbi = [ /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x97Dd879F5a97A8c761B94746d7F5cfF50AAd4452) */ export const sessionKeyRegistryAddress = { 314: '0x0000000000000000000000000000000000000000', - 314159: '0x0000000000000000000000000000000000000000', + 314159: '0x97Dd879F5a97A8c761B94746d7F5cfF50AAd4452', } as const /** * - [__View Contract on Filecoin Mainnet Filfox__](https://filfox.info/en/address/0x0000000000000000000000000000000000000000) - * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x0000000000000000000000000000000000000000) + * - [__View Contract on Filecoin Calibration Filscan__](https://calibration.filscan.io/address/0x97Dd879F5a97A8c761B94746d7F5cfF50AAd4452) */ export const sessionKeyRegistryConfig = { address: sessionKeyRegistryAddress, diff --git a/packages/synapse-core/src/index.ts b/packages/synapse-core/src/index.ts new file mode 100644 index 00000000..d57ab479 --- /dev/null +++ b/packages/synapse-core/src/index.ts @@ -0,0 +1,21 @@ +/** + * Synapse Core - Main entry point + * + * @example + * ```ts + * import * as SynapseCore from '@filoz/synapse-core' + * ``` + * + * @packageDocumentation + * @module Core + */ + +/** + * Synapse SDK main entry point + */ + +export * as chains from './chains.ts' +export * from './constants.ts' +export * from './errors/base.ts' +export * from './errors/chains.ts' +export * from './utils.ts' diff --git a/packages/synapse-core/src/utils.ts b/packages/synapse-core/src/utils.ts new file mode 100644 index 00000000..5d16d43f --- /dev/null +++ b/packages/synapse-core/src/utils.ts @@ -0,0 +1,102 @@ +import { BrowserProvider, FallbackProvider, JsonRpcProvider, JsonRpcSigner, Wallet } from 'ethers' +import { + type Account, + type Chain, + type Client, + createClient, + type FallbackTransport, + fallback, + type HttpTransport, + http, + type Transport, + type TransportConfig, + type WebSocketTransport, + webSocket, +} from 'viem' + +/** + * Convert a Viem public client to an ethers.js provider + * + * @param client - Viem client + */ +export function clientToProvider(client: Client) { + const { chain, transport } = client + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + + if (transport.type === 'fallback') { + const providers = (transport.transports as ReturnType[]).map( + ({ value }) => new JsonRpcProvider(value?.url, network) + ) + if (providers.length === 1) return providers[0] + return new FallbackProvider(providers) + } + + return new JsonRpcProvider(transport.url, network) +} + +/** + * Convert a Viem wallet client to an ethers.js signer + * + * @param client - Viem wallet client + */ +export function walletClientToSigner(client: Client) { + const { account, chain, transport } = client + + const network = { + chainId: chain.id, + name: chain.name, + ensAddress: chain.contracts?.ensRegistry?.address, + } + + if (account.type === 'json-rpc') { + const provider = new BrowserProvider(transport, network) + const signer = new JsonRpcSigner(provider, account.address) + return signer + } else if (account.type === 'local') { + const provider = new JsonRpcProvider(transport.url, network) + // @ts-ignore + const signer = new Wallet(account.privateKey, provider) + + return signer + } else { + throw new Error('Unsupported account type') + } +} + +/** + * Create a Viem public client from a transport configuration + */ +export function clientFromTransport({ + chain, + transportConfig, +}: { + chain: Chain + transportConfig?: TransportConfig +}): Client { + let transport: HttpTransport | WebSocketTransport | FallbackTransport = http() + if (transportConfig) { + switch (transportConfig.type) { + case 'http': + // @ts-ignore + transport = http(transportConfig.url, transportConfig) + break + case 'webSocket': + // @ts-ignore + transport = webSocket(transportConfig.getSocket(), transportConfig) + break + case 'fallback': + // @ts-ignore + transport = fallback(transportConfig.transports, transportConfig) + break + } + } + + return createClient({ + chain, + transport, + }) +} diff --git a/packages/synapse-core/tsconfig.json b/packages/synapse-core/tsconfig.json new file mode 100644 index 00000000..1032b057 --- /dev/null +++ b/packages/synapse-core/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"], + "typedocOptions": { + "entryPointStrategy": "resolve", + "entryPoints": ["src/index.ts", "src/chains.ts", "src/utils.ts"] + } +} diff --git a/packages/synapse-sdk/wagmi.config.ts b/packages/synapse-core/wagmi.config.ts similarity index 73% rename from packages/synapse-sdk/wagmi.config.ts rename to packages/synapse-core/wagmi.config.ts index c2e15168..41476116 100644 --- a/packages/synapse-sdk/wagmi.config.ts +++ b/packages/synapse-core/wagmi.config.ts @@ -5,55 +5,55 @@ import type { Address } from 'viem' const GIT_REF = 'tags/alpha/calibnet/0x80617b65FD2EEa1D7fDe2B4F85977670690ed348-v2' const BASE_URL = `https://raw.githubusercontent.com/FilOzone/filecoin-services/refs/${GIT_REF}/service_contracts/abi` -const config = defineConfig(() => { +const config: ReturnType = defineConfig(() => { const contracts = [ { name: 'Payments', address: { 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314159: '0x1096025c9D6B29E12E2f04965F6E64d564Ce0750' as Address, }, }, { name: 'FilecoinWarmStorageService', address: { - 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314: '0x81DFD9813aDd354f03704F31419b0c6268d46232' as Address, + 314159: '0x80617b65FD2EEa1D7fDe2B4F85977670690ed348' as Address, }, }, { name: 'FilecoinWarmStorageServiceStateView', address: { 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314159: '0x87EDE87cEF4BfeFE0374c3470cB3F5be18b739d5' as Address, }, }, { name: 'PDPVerifier', address: { 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314159: '0x445238Eca6c6aB8Dff1Aa6087d9c05734D22f137' as Address, }, }, { name: 'ServiceProviderRegistry', address: { 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314159: '0xA8a7e2130C27e4f39D1aEBb3D538D5937bCf8ddb' as Address, }, }, { name: 'SessionKeyRegistry', address: { 314: '0x0000000000000000000000000000000000000000' as Address, - 314159: '0x0000000000000000000000000000000000000000' as Address, + 314159: '0x97Dd879F5a97A8c761B94746d7F5cfF50AAd4452' as Address, }, }, ] return [ { - out: 'src/abis/gen.ts', + out: 'src/gen.ts', plugins: [ fetch({ contracts, diff --git a/packages/synapse-sdk/package.json b/packages/synapse-sdk/package.json index e747881a..2ecd2cfc 100644 --- a/packages/synapse-sdk/package.json +++ b/packages/synapse-sdk/package.json @@ -53,22 +53,75 @@ } }, "scripts": { - "generate-abi": "wagmi generate", - "build": "tsc --build", - "lint": "tsc --build && biome check --no-errors-on-unmatched --files-ignore-unknown=true .", - "lint:fix": "biome check --no-errors-on-unmatched --files-ignore-unknown=true --fix .", - "test": "pnpm run lint && pnpm run test:node", - "test:node": "playwright-test 'src/test/**/!(*.browser).test.ts' --mode node", - "test:browser": "playwright-test 'src/test/**/!(*.node).test.ts' --assets ./src/test/mocks", + "build": "wireit", + "lint": "wireit", + "test": "wireit", + "test:node": "wireit", + "test:browser": "wireit", "clean": "rm -rf dist", "prepublishOnly": "pnpm run clean && pnpm run build" }, + "wireit": { + "build": { + "command": "tsc --build --pretty", + "clean": "if-file-deleted", + "files": [ + "src/**/*.ts", + "tsconfig.json" + ], + "output": [ + "dist/**" + ] + }, + "lint": { + "command": "biome check --no-errors-on-unmatched --files-ignore-unknown=true .", + "files": [ + "src/**/*.ts", + "../../biome.json" + ], + "output": [], + "dependencies": [ + "build" + ] + }, + "test": { + "command": "pnpm run test:node && pnpm run test:browser", + "files": [ + "src/**/*.ts" + ], + "output": [], + "dependencies": [ + "lint" + ] + }, + "test:node": { + "command": "playwright-test \"src/test/**/*.test.ts\" --mode node", + "files": [ + "src/**/*.ts" + ], + "output": [], + "dependencies": [ + "../synapse-core:build" + ] + }, + "test:browser": { + "command": "playwright-test \"src/test/**/*.test.ts\" --assets ./src/test/mocks", + "files": [ + "src/**/*.ts" + ], + "output": [], + "dependencies": [ + "../synapse-core:build" + ] + } + }, "dependencies": { + "@filoz/synapse-core": "workspace:*", "@web3-storage/data-segment": "^5.3.0", "ethers": "^6.15.0", "multiformats": "^13.4.1", "ox": "^0.9.6", - "viem": "^2.37.11" + "viem": "2.x" }, "devDependencies": { "@biomejs/biome": "~2.2.5", diff --git a/packages/synapse-sdk/src/abis/erc20-permit.ts b/packages/synapse-sdk/src/abis/erc20-permit.ts deleted file mode 100644 index 48c69b0f..00000000 --- a/packages/synapse-sdk/src/abis/erc20-permit.ts +++ /dev/null @@ -1,16 +0,0 @@ -export const erc20PermitAbi = [ - { - type: 'function', - stateMutability: 'view', - name: 'nonces', - inputs: [{ name: 'owner', type: 'address' }], - outputs: [{ name: '', type: 'uint256' }], - }, - { - type: 'function', - stateMutability: 'view', - name: 'version', - inputs: [], - outputs: [{ name: '', type: 'string' }], - }, -] as const diff --git a/packages/synapse-sdk/src/payments/service.ts b/packages/synapse-sdk/src/payments/service.ts index ba2f7e20..b4245a24 100644 --- a/packages/synapse-sdk/src/payments/service.ts +++ b/packages/synapse-sdk/src/payments/service.ts @@ -111,7 +111,6 @@ export class PaymentsService { // Create interfaces for encoding/decoding const erc20Interface = new ethers.Interface(CONTRACT_ABIS.ERC20) - const permitInterface = new ethers.Interface(CONTRACT_ABIS.ERC20_PERMIT) // Prepare multicall batch: balanceOf, name, version (with fallback), nonces const calls = [ @@ -128,12 +127,12 @@ export class PaymentsService { { target: this._usdfcAddress, allowFailure: true, // Allow failure for version, we'll fallback to '1' - callData: permitInterface.encodeFunctionData('version'), + callData: erc20Interface.encodeFunctionData('version'), }, { target: this._usdfcAddress, allowFailure: false, - callData: permitInterface.encodeFunctionData('nonces', [signerAddress]), + callData: erc20Interface.encodeFunctionData('nonces', [signerAddress]), }, ] @@ -187,7 +186,7 @@ export class PaymentsService { let domainVersion = '1' if (results[2].success) { try { - const decoded = permitInterface.decodeFunctionResult('version', results[2].returnData) + const decoded = erc20Interface.decodeFunctionResult('version', results[2].returnData) const maybeVersion = decoded[0] if (typeof maybeVersion === 'string' && maybeVersion.length > 0) { domainVersion = maybeVersion @@ -200,7 +199,7 @@ export class PaymentsService { // Result 3: nonces let nonce: bigint try { - const decoded = permitInterface.decodeFunctionResult('nonces', results[3].returnData) + const decoded = erc20Interface.decodeFunctionResult('nonces', results[3].returnData) nonce = decoded[0] } catch (error) { throw createError( diff --git a/packages/synapse-sdk/src/pdp/auth.ts b/packages/synapse-sdk/src/pdp/auth.ts index f38b1ecc..3660fdad 100644 --- a/packages/synapse-sdk/src/pdp/auth.ts +++ b/packages/synapse-sdk/src/pdp/auth.ts @@ -2,7 +2,7 @@ * EIP-712 Authentication helpers for PDP operations */ -import { ethers } from 'ethers' +import { BrowserProvider, ethers, JsonRpcProvider } from 'ethers' import { asPieceCID, type PieceCID } from '../piece/index.ts' import type { AuthSignature, MetadataEntry } from '../types.ts' import { METADATA_KEYS } from '../utils/constants.ts' @@ -79,32 +79,12 @@ export class PDPAuthHelper { // Get the actual signer (unwrap NonceManager if needed) const actualSigner = this.getUnderlyingSigner() - // If it's a Wallet, it can sign locally, so not a MetaMask signer - if (actualSigner.constructor.name === 'Wallet') { - return false - } - - // Check if signer has a provider - const provider = actualSigner.provider - if (provider == null) { - return false - } - - // Check for ethers v6 BrowserProvider - if ('_eip1193Provider' in provider) { + if (actualSigner.provider instanceof BrowserProvider) { return true } - - // If it's a JsonRpcProvider or WebSocketProvider, it's not a browser provider - // These can sign locally with a wallet - if (provider instanceof ethers.JsonRpcProvider || provider instanceof ethers.WebSocketProvider) { + if (actualSigner.provider instanceof JsonRpcProvider) { return false } - - // For any other provider with request method (potential EIP-1193 provider) - if ('request' in provider && typeof (provider as any).request === 'function') { - return true - } } catch { // Silently fail and return false } diff --git a/packages/synapse-sdk/src/synapse.ts b/packages/synapse-sdk/src/synapse.ts index 7b7e819e..bda154e9 100644 --- a/packages/synapse-sdk/src/synapse.ts +++ b/packages/synapse-sdk/src/synapse.ts @@ -2,7 +2,11 @@ * Main Synapse class for interacting with Filecoin storage and other on-chain services */ +import { UnsupportedChainError } from '@filoz/synapse-core' +import { calibration, getChain, mainnet } from '@filoz/synapse-core/chains' +import { clientFromTransport, clientToProvider, walletClientToSigner } from '@filoz/synapse-core/utils' import { ethers } from 'ethers' +import type { Account, Chain, Client, Transport } from 'viem' import { PaymentsService } from './payments/index.ts' import { ChainRetriever, FilBeamRetriever, SubgraphRetriever } from './retriever/index.ts' import { SessionKey } from './session/key.ts' @@ -20,20 +24,20 @@ import type { SubgraphConfig, SynapseOptions, } from './types.ts' -import { CHAIN_IDS, CONTRACT_ADDRESSES, getFilecoinNetworkType } from './utils/index.ts' import { ProviderResolver } from './utils/provider-resolver.ts' import { WarmStorageService } from './warm-storage/index.ts' export class Synapse { private readonly _signer: ethers.Signer - private readonly _network: FilecoinNetworkType private readonly _withCDN: boolean private readonly _payments: PaymentsService private readonly _provider: ethers.Provider - private readonly _warmStorageAddress: string private readonly _warmStorageService: WarmStorageService private readonly _pieceRetriever: PieceRetriever private readonly _storageManager: StorageManager + + private readonly _walletClient: Client + private readonly _publicClient: Client private _session: SessionKey | null = null /** @@ -42,102 +46,28 @@ export class Synapse { * @returns A fully initialized Synapse instance */ static async create(options: SynapseOptions): Promise { - // Validate options - const providedOptions = [options.privateKey, options.provider, options.signer].filter(Boolean).length - if (providedOptions !== 1) { - throw new Error('Must provide exactly one of: privateKey, provider, or signer') + if (options.client.chain.id !== mainnet.id && options.client.chain.id !== calibration.id) { + throw new UnsupportedChainError(options.client.chain.id) } - // Detect network from chain - let network: FilecoinNetworkType | undefined - - // Create or derive signer and provider - let signer: ethers.Signer - let provider: ethers.Provider - - if (options.privateKey != null) { - // Handle private key input - const rpcURL = options.rpcURL ?? options.rpcURL - if (rpcURL == null) { - throw new Error('rpcURL is required when using privateKey') - } - - // Sanitize private key - let privateKey = options.privateKey - if (!privateKey.startsWith('0x')) { - privateKey = `0x${privateKey}` - } - - // Create provider and wallet - // if websockets, use correct provider - if (/^ws(s)?:\/\//i.test(rpcURL)) { - provider = new ethers.WebSocketProvider(rpcURL) - } else { - provider = new ethers.JsonRpcProvider(rpcURL) - } + const publicClient = clientFromTransport({ + chain: options.client.chain, + transportConfig: options.transportConfig ?? options.client.transport, + }) - network = await getFilecoinNetworkType(provider) - - // Create wallet with provider - always use NonceManager unless disabled - const wallet = new ethers.Wallet(privateKey, provider) - signer = options.disableNonceManager === true ? wallet : new ethers.NonceManager(wallet) - } else if (options.provider != null) { - // Handle provider input - provider = options.provider - - network = await getFilecoinNetworkType(provider) - - // Get signer - apply NonceManager unless disabled - // For ethers v6, we need to check if provider has getSigner method - if ('getSigner' in provider && typeof provider.getSigner === 'function') { - const baseSigner = await (provider as any).getSigner(0) - signer = options.disableNonceManager === true ? baseSigner : new ethers.NonceManager(baseSigner) - } else { - throw new Error('Provider does not support signing operations') - } - } else if (options.signer != null) { - // Handle signer input - signer = options.signer - - // Apply NonceManager wrapper unless disabled - if (options.disableNonceManager !== true && !(signer instanceof ethers.NonceManager)) { - signer = new ethers.NonceManager(signer) - } - - // Get provider from signer - if (signer.provider == null) { - throw new Error('Signer must have a provider') - } - provider = signer.provider - - network = await getFilecoinNetworkType(provider) - } else { - // This should never happen due to validation above - throw new Error('No valid authentication method provided') - } - - // Final network validation - if (network !== 'mainnet' && network !== 'calibration') { - throw new Error(`Invalid network: ${String(network)}. Only 'mainnet' and 'calibration' are supported.`) - } + const chain = getChain(options.client.chain.id) + const network = chain.id === mainnet.id ? 'mainnet' : 'calibration' + const signer = walletClientToSigner(options.client) + const provider = clientToProvider(publicClient) // Create Warm Storage service with initialized addresses - const warmStorageAddress = options.warmStorageAddress ?? CONTRACT_ADDRESSES.WARM_STORAGE[network] - if (!warmStorageAddress) { - throw new Error(`No Warm Storage address configured for network: ${network}`) - } + const warmStorageAddress = options.warmStorageAddress ?? chain.contracts.storage.address const warmStorageService = await WarmStorageService.create(provider, warmStorageAddress) // Create payments service with discovered addresses const paymentsAddress = warmStorageService.getPaymentsAddress() const usdfcAddress = warmStorageService.getUSDFCTokenAddress() - const payments = new PaymentsService( - provider, - signer, - paymentsAddress, - usdfcAddress, - options.disableNonceManager === true - ) + const payments = new PaymentsService(provider, signer, paymentsAddress, usdfcAddress, false) // Create SPRegistryService for use in retrievers const registryAddress = warmStorageService.getServiceProviderRegistryAddress() @@ -166,35 +96,31 @@ export class Synapse { } return new Synapse( - signer, - provider, - network, + options.client, + publicClient, payments, options.withCDN === true, - warmStorageAddress, warmStorageService, pieceRetriever ) } private constructor( - signer: ethers.Signer, - provider: ethers.Provider, - network: FilecoinNetworkType, + walletClient: Client, + publicClient: Client, payments: PaymentsService, withCDN: boolean, - warmStorageAddress: string, warmStorageService: WarmStorageService, pieceRetriever: PieceRetriever ) { - this._signer = signer - this._provider = provider - this._network = network + this._walletClient = walletClient + this._publicClient = publicClient + this._signer = walletClientToSigner(walletClient) + this._provider = clientToProvider(publicClient) this._payments = payments this._withCDN = withCDN this._warmStorageService = warmStorageService this._pieceRetriever = pieceRetriever - this._warmStorageAddress = warmStorageAddress this._session = null // Initialize StorageManager @@ -206,7 +132,7 @@ export class Synapse { * @returns The network type ('mainnet' or 'calibration') */ getNetwork(): FilecoinNetworkType { - return this._network + return this._walletClient.chain.id === mainnet.id ? 'mainnet' : 'calibration' } /** @@ -234,11 +160,11 @@ export class Synapse { * @param sessionKeySigner The signer for the session key * @returns The SessionKey object for this signer */ - createSessionKey(sessionKeySigner: ethers.Signer): SessionKey { + createSessionKey(client: Client): SessionKey { return new SessionKey( this._provider, this._warmStorageService.getSessionKeyRegistryAddress(), - sessionKeySigner, + walletClientToSigner(client), this._signer ) } @@ -275,12 +201,28 @@ export class Synapse { return this._provider } + /** + * Gets the public client instance + * @returns The public client + */ + getPublicClient(): Client { + return this._publicClient + } + + /** + * Gets the wallet client instance + * @returns The wallet client + */ + getWalletClient(): Client { + return this._walletClient + } + /** * Gets the current chain ID * @returns The numeric chain ID */ getChainId(): number { - return this._network === 'mainnet' ? CHAIN_IDS.mainnet : CHAIN_IDS.calibration + return this._walletClient.chain.id } /** @@ -288,7 +230,7 @@ export class Synapse { * @returns The Warm Storage service address */ getWarmStorageAddress(): string { - return this._warmStorageAddress + return this._warmStorageService.getAddress() } /** diff --git a/packages/synapse-sdk/src/test/mocks/jsonrpc/index.ts b/packages/synapse-sdk/src/test/mocks/jsonrpc/index.ts index 7ddc057f..95d5b5b7 100644 --- a/packages/synapse-sdk/src/test/mocks/jsonrpc/index.ts +++ b/packages/synapse-sdk/src/test/mocks/jsonrpc/index.ts @@ -17,7 +17,7 @@ import { sessionKeyRegistryCallHandler } from './session-key-registry.ts' import type { JSONRPCOptions, RpcRequest, RpcResponse } from './types.ts' import { warmStorageCallHandler, warmStorageViewCallHandler } from './warm-storage.ts' -export const PRIVATE_KEYS = { +export const PRIVATE_KEYS: Record = { key1: '0x1234567890123456789012345678901234567890123456789012345678901234', key2: '0x4123456789012345678901234567890123456789012345678901234567890123', } @@ -101,6 +101,9 @@ function handler(body: RpcRequest, options: JSONRPCOptions) { if (!options.eth_chainId) { throw new Error('eth_chainId is not defined') } + if (options.debug) { + console.debug('eth_chainId: calling function', 'with args', params) + } return options.eth_chainId } case 'eth_blockNumber': { @@ -113,6 +116,9 @@ function handler(body: RpcRequest, options: JSONRPCOptions) { if (!options.eth_accounts) { throw new Error('eth_accounts is not defined') } + if (options.debug) { + console.debug('eth_accounts: calling function', 'with args', params) + } return options.eth_accounts case 'eth_getTransactionByHash': { if (!options.eth_getTransactionByHash) { diff --git a/packages/synapse-sdk/src/test/synapse.test.ts b/packages/synapse-sdk/src/test/synapse.test.ts index 2d06cb43..0f49b088 100644 --- a/packages/synapse-sdk/src/test/synapse.test.ts +++ b/packages/synapse-sdk/src/test/synapse.test.ts @@ -4,12 +4,25 @@ * Basic tests for Synapse class */ +import { calibration } from '@filoz/synapse-core/chains' import { assert } from 'chai' -import { ethers } from 'ethers' import { setup } from 'iso-web/msw' import { HttpResponse, http } from 'msw' import pDefer from 'p-defer' -import { type Address, isAddressEqual, parseUnits } from 'viem' +import { + type Account, + type Address, + type Chain, + type Client, + createPublicClient, + createWalletClient, + isAddressEqual, + parseUnits, + type Transport, + http as viemHttp, +} from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { base } from 'viem/chains' import { PaymentsService } from '../payments/index.ts' import { PDP_PERMISSIONS } from '../session/key.ts' import { Synapse } from '../synapse.ts' @@ -22,8 +35,8 @@ import { PING } from './mocks/ping.ts' const server = setup([]) describe('Synapse', () => { - let signer: ethers.Signer - let provider: ethers.Provider + let walletClient: Client + let publicClient: Client before(async () => { await server.start({ quiet: true }) }) @@ -33,14 +46,23 @@ describe('Synapse', () => { }) beforeEach(() => { server.resetHandlers() - provider = new ethers.JsonRpcProvider('https://api.calibration.node.glif.io/rpc/v1') - signer = new ethers.Wallet(PRIVATE_KEYS.key1, provider) + + walletClient = createWalletClient({ + account: privateKeyToAccount(PRIVATE_KEYS.key1), + chain: calibration, + transport: viemHttp(), + }) + + publicClient = createPublicClient({ + chain: calibration, + transport: viemHttp(), + }) }) describe('Instantiation', () => { it('should create instance with signer', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) assert.exists(synapse) assert.exists(synapse.payments) assert.isTrue(synapse.payments instanceof PaymentsService) @@ -48,100 +70,38 @@ describe('Synapse', () => { it('should create instance with provider', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ provider }) + const synapse = await Synapse.create({ client: walletClient, transportConfig: publicClient.transport }) assert.exists(synapse) assert.exists(synapse.payments) assert.isTrue(synapse.payments instanceof PaymentsService) - }) - - it('should create instance with private key', async () => { - server.use(JSONRPC(presets.basic)) - const privateKey = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef' - const rpcURL = 'https://api.calibration.node.glif.io/rpc/v1' - const synapse = await Synapse.create({ privateKey, rpcURL }) - assert.exists(synapse) - assert.exists(synapse.payments) - assert.isTrue(synapse.payments instanceof PaymentsService) - }) - - it('should apply NonceManager by default', async () => { - server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) - assert.exists(synapse) - // We can't directly check if NonceManager is applied, but we can verify the instance is created - }) - - it('should allow disabling NonceManager', async () => { - server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ - signer, - disableNonceManager: true, - }) - assert.exists(synapse) - // We can't directly check if NonceManager is not applied, but we can verify the instance is created + assert.equal(synapse.getPublicClient().transport.url, 'https://api.calibration.node.glif.io/rpc/v1') }) it.skip('should allow enabling CDN', async () => { // Skip this test as it requires real contract interactions const synapse = await Synapse.create({ - signer, + client: walletClient, withCDN: true, }) const storageService = await synapse.createStorage() assert.exists(storageService) // CDN is part of the storage service configuration }) + }) - it('should reject when no authentication method provided', async () => { - try { - await Synapse.create({} as any) - assert.fail('Should have thrown') - } catch (error: any) { - assert.include(error.message, 'Must provide exactly one of') - } - }) - - it('should reject when multiple authentication methods provided', async () => { - try { - await Synapse.create({ - privateKey: '0x123', - provider, - rpcURL: 'https://example.com', - } as any) - assert.fail('Should have thrown') - } catch (error: any) { - assert.include(error.message, 'Must provide exactly one of') - } - }) - - it('should reject privateKey without rpcURL', async () => { + describe('Network validation', () => { + it('should reject create with unsupported chain', async () => { try { await Synapse.create({ - privateKey: '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef', + client: createWalletClient({ + account: privateKeyToAccount(PRIVATE_KEYS.key1), + chain: base, + transport: viemHttp(), + }), }) assert.fail('Should have thrown') } catch (error: any) { - assert.include(error.message, 'rpcURL is required when using privateKey') - } - }) - }) - - describe('Network validation', () => { - it('should reject unsupported networks', async () => { - // Create mock provider with unsupported chain ID - // const unsupportedProvider = createMockProvider(999999) - server.use( - JSONRPC({ - ...presets.basic, - eth_chainId: '999999', - }) - ) - try { - await Synapse.create({ provider }) - assert.fail('Should have thrown for unsupported network') - } catch (error: any) { - assert.include(error.message, 'Unsupported network') - assert.include(error.message, '999999') + assert.include(error.message, 'Unsupported chain: 8453') } }) @@ -152,75 +112,15 @@ describe('Synapse', () => { eth_chainId: '314159', }) ) - const synapse = await Synapse.create({ provider }) - assert.exists(synapse) - }) - - it('should accept mainnet with custom warmStorage address', async () => { - server.use( - JSONRPC({ - ...presets.basic, - eth_chainId: '314', - }) - ) - const synapse = await Synapse.create({ - provider, - warmStorageAddress: '0x1234567890123456789012345678901234567890', // Custom address for mainnet - pdpVerifierAddress: '0x9876543210987654321098765432109876543210', // Custom PDPVerifier address for mainnet - }) - assert.exists(synapse) - }) - - // custom addresses are not used anymore in the SDK - it.skip('should accept custom pdpVerifierAddress', async () => { - const customPDPVerifierAddress = '0xabcdef1234567890123456789012345678901234' - server.use( - JSONRPC({ - ...presets.basic, - warmStorage: { - pdpVerifierAddress: () => [customPDPVerifierAddress], - }, - }) - ) - - const synapse = await Synapse.create({ - provider, - pdpVerifierAddress: customPDPVerifierAddress, - }) + const synapse = await Synapse.create({ client: walletClient }) assert.exists(synapse) - assert.ok(isAddressEqual(synapse.getPDPVerifierAddress() as Address, customPDPVerifierAddress)) - }) - - // theres no default pdpVerifierAddress in the SDK anymore - it.skip('should use default pdpVerifierAddress when not provided', async () => { - server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ - provider, - }) - assert.exists(synapse) - assert.ok(isAddressEqual(synapse.getPDPVerifierAddress() as Address, ADDRESSES.calibration.pdpVerifier)) - }) - - // custom addresses are not used anymore in the SDK - it.skip('should accept both custom warmStorageAddress and pdpVerifierAddress', async () => { - const customPDPVerifierAddress = '0x2222222222222222222222222222222222222222' - - server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ - provider, - warmStorageAddress: ADDRESSES.mainnet.warmStorage, - pdpVerifierAddress: customPDPVerifierAddress, - }) - assert.exists(synapse) - assert.equal(synapse.getWarmStorageAddress(), ADDRESSES.mainnet.warmStorage) - assert.ok(isAddressEqual(synapse.getPDPVerifierAddress() as Address, customPDPVerifierAddress)) }) }) describe('StorageManager access', () => { it('should provide access to StorageManager via synapse.storage', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) // Should be able to access storage manager assert.exists(synapse.storage) @@ -237,7 +137,7 @@ describe('Synapse', () => { it('should create storage manager with CDN settings', async () => { server.use(JSONRPC(presets.basic)) const synapse = await Synapse.create({ - signer, + client: walletClient, withCDN: true, }) @@ -249,7 +149,7 @@ describe('Synapse', () => { it('should return same storage manager instance', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) const storage1 = synapse.storage const storage2 = synapse.storage @@ -307,9 +207,11 @@ describe('Synapse', () => { }) it('should storage.createContext with session key', async () => { - const signerAddress = await signer.getAddress() - const sessionKeySigner = new ethers.Wallet(PRIVATE_KEYS.key2) - const sessionKeyAddress = await sessionKeySigner.getAddress() + const sessionClient = createWalletClient({ + account: privateKeyToAccount(PRIVATE_KEYS.key2), + chain: calibration, + transport: viemHttp(), + }) const EXPIRY = BigInt(1757618883) server.use( JSONRPC({ @@ -318,8 +220,8 @@ describe('Synapse', () => { authorizationExpiry: (args) => { const client = args[0] const signer = args[1] - assert.equal(client, signerAddress) - assert.equal(signer, sessionKeyAddress) + assert.equal(client, walletClient.account.address) + assert.equal(signer, sessionClient.account.address) const permission = args[2] assert.isTrue(PDP_PERMISSIONS.includes(permission)) return [EXPIRY] @@ -332,7 +234,7 @@ describe('Synapse', () => { const client = args[1] const operator = args[2] assert.equal(token, ADDRESSES.calibration.usdfcToken) - assert.equal(client, signerAddress) + assert.equal(client, walletClient.account.address) assert.equal(operator, ADDRESSES.calibration.warmStorage) return [ true, // isApproved @@ -346,7 +248,7 @@ describe('Synapse', () => { accounts: (args) => { const token = args[0] const user = args[1] - assert.equal(user, signerAddress) + assert.equal(user, walletClient.account.address) assert.equal(token, ADDRESSES.calibration.usdfcToken) return [BigInt(127001 * 635000000), BigInt(0), BigInt(0), BigInt(0)] }, @@ -363,18 +265,17 @@ describe('Synapse', () => { }, }) ) - const synapse = await Synapse.create({ signer }) - const sessionKey = synapse.createSessionKey(sessionKeySigner) + const synapse = await Synapse.create({ client: walletClient }) + const sessionKey = synapse.createSessionKey(sessionClient) synapse.setSession(sessionKey) - assert.equal(sessionKey.getSigner(), sessionKeySigner) + assert.equal(await sessionKey.getSigner().getAddress(), sessionClient.account.address) const expiries = await sessionKey.fetchExpiries(PDP_PERMISSIONS) for (const permission of PDP_PERMISSIONS) { assert.equal(expiries[permission], EXPIRY) } - const context = await synapse.storage.createContext() - assert.equal((context as any)._signer, sessionKeySigner) + assert.equal(await synapse.getSigner().getAddress(), sessionClient.account.address) const info = await context.preflightUpload(127) assert.isTrue(info.allowanceCheck.sufficient) @@ -387,7 +288,7 @@ describe('Synapse', () => { describe('Payment access', () => { it('should provide read-only access to payments', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) // Should be able to access payments assert.exists(synapse.payments) @@ -411,7 +312,7 @@ describe('Synapse', () => { it('should get provider info for valid approved provider', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ provider }) + const synapse = await Synapse.create({ client: walletClient }) const providerInfo = await synapse.getProviderInfo(ADDRESSES.serviceProvider1) assert.ok(isAddressEqual(providerInfo.serviceProvider as Address, ADDRESSES.serviceProvider1)) @@ -420,7 +321,7 @@ describe('Synapse', () => { it('should throw for invalid provider address', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) try { await synapse.getProviderInfo('invalid-address') @@ -445,7 +346,7 @@ describe('Synapse', () => { ) try { - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) await synapse.getProviderInfo(ADDRESSES.serviceProvider1) assert.fail('Should have thrown') } catch (error: any) { @@ -474,7 +375,7 @@ describe('Synapse', () => { ) try { - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) await synapse.getProviderInfo(ADDRESSES.serviceProvider1) assert.fail('Should have thrown') } catch (error: any) { @@ -486,7 +387,7 @@ describe('Synapse', () => { describe('download', () => { it('should validate PieceCID input', async () => { server.use(JSONRPC(presets.basic)) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) try { await synapse.download('invalid-piece-link') @@ -516,7 +417,7 @@ describe('Synapse', () => { ) const synapse = await Synapse.create({ - signer, + client: walletClient, }) // Use the actual PieceCID for 'test data' @@ -551,7 +452,7 @@ describe('Synapse', () => { ) const synapse = await Synapse.create({ - signer, + client: walletClient, withCDN: false, // Instance default }) @@ -599,7 +500,7 @@ describe('Synapse', () => { }) ) const synapse = await Synapse.create({ - signer, + client: walletClient, }) const testPieceCid = 'bafkzcibcoybm2jlqsbekq6uluyl7xm5ffemw7iuzni5ez3a27iwy4qu3ssebqdq' @@ -618,7 +519,7 @@ describe('Synapse', () => { ) const synapse = await Synapse.create({ - signer, + client: walletClient, }) const testPieceCid = 'bafkzcibcoybm2jlqsbekq6uluyl7xm5ffemw7iuzni5ez3a27iwy4qu3ssebqdq' @@ -639,7 +540,7 @@ describe('Synapse', () => { it('should return comprehensive storage information', async () => { server.use(JSONRPC({ ...presets.basic })) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) const storageInfo = await synapse.getStorageInfo() // Check pricing @@ -681,7 +582,7 @@ describe('Synapse', () => { }) ) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) const storageInfo = await synapse.getStorageInfo() // Should still return data with null allowances @@ -731,7 +632,7 @@ describe('Synapse', () => { }) ) - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) const storageInfo = await synapse.getStorageInfo() // Should filter out zero address provider @@ -752,7 +653,7 @@ describe('Synapse', () => { }) ) try { - const synapse = await Synapse.create({ signer }) + const synapse = await Synapse.create({ client: walletClient }) await synapse.getStorageInfo() assert.fail('Should have thrown') } catch (error: any) { diff --git a/packages/synapse-sdk/src/test/warm-storage-service.test.ts b/packages/synapse-sdk/src/test/warm-storage-service.test.ts index 5dfaf63c..a97d6f62 100644 --- a/packages/synapse-sdk/src/test/warm-storage-service.test.ts +++ b/packages/synapse-sdk/src/test/warm-storage-service.test.ts @@ -6,8 +6,7 @@ import { assert } from 'chai' import { ethers } from 'ethers' -import { filecoinWarmStorageServiceAbi, filecoinWarmStorageServiceStateViewAbi } from '../abis/gen.ts' -import { CONTRACT_ADDRESSES, SIZE_CONSTANTS, TIME_CONSTANTS } from '../utils/constants.ts' +import { CONTRACT_ABIS, CONTRACT_ADDRESSES, SIZE_CONSTANTS, TIME_CONSTANTS } from '../utils/constants.ts' import { WarmStorageService } from '../warm-storage/index.ts' import { createMockProvider, extendMockProviderCall, MOCK_ADDRESSES } from './test-utils.ts' @@ -19,8 +18,8 @@ describe('WarmStorageService', () => { const clientAddress = '0x1234567890123456789012345678901234567890' // Create Interface instances for encoding/decoding contract responses - const viewInterface = new ethers.Interface(filecoinWarmStorageServiceStateViewAbi) - const warmInterface = new ethers.Interface(filecoinWarmStorageServiceAbi) + const viewInterface = new ethers.Interface(CONTRACT_ABIS.WARM_STORAGE_VIEW) + const warmInterface = new ethers.Interface(CONTRACT_ABIS.WARM_STORAGE) // Helper to handle viewContractAddress calls const handleViewContractAddress = (data: string | undefined): string | null => { diff --git a/packages/synapse-sdk/src/types.ts b/packages/synapse-sdk/src/types.ts index 69fd19f2..83a59c23 100644 --- a/packages/synapse-sdk/src/types.ts +++ b/packages/synapse-sdk/src/types.ts @@ -6,6 +6,7 @@ */ import type { ethers } from 'ethers' +import type { Account, Chain, Client, Transport, TransportConfig } from 'viem' import type { PieceCID } from './piece/index.ts' import type { ProviderInfo } from './sp-registry/types.ts' @@ -35,34 +36,33 @@ export type TokenIdentifier = 'USDFC' | string * 3. signer (for direct ethers.js integration) */ export interface SynapseOptions { - // Wallet Configuration (exactly one required) - - /** Private key for signing transactions (requires rpcURL) */ - privateKey?: PrivateKey - /** Ethers Provider instance (handles both reads and transactions) */ - provider?: ethers.Provider - /** Ethers Signer instance (for direct ethers.js integration) */ - signer?: ethers.Signer - - // Network Configuration - - /** RPC URL for Filecoin node (required with privateKey) */ - rpcURL?: string - /** Authorization header value for API authentication (e.g., Bearer token) */ - authorization?: string + /** + * Viem wallet client for signing transactions and typed data + * + * @see https://viem.sh/docs/clients/wallet + * @see https://wagmi.sh/react/api/hooks/useConnectorClient + * @see https://wagmi.sh/core/api/actions/getConnectorClient + */ + client: Client - // Advanced Configuration + /** + * Viem transport configuration for creating a public client for reading data from the chain + * + * When not provided, a public client will be created using {@link https://viem.sh/docs/clients/transports/http} based on the {@link SynapseOptions.client} chain. + * + * Only [http](https://viem.sh/docs/clients/transports/http), [websocket](https://viem.sh/docs/clients/transports/websocket), and [fallback](https://viem.sh/docs/clients/transports/fallback) transports config are supported. + * + * @see https://viem.sh/docs/clients/public + * + */ + transportConfig?: TransportConfig /** Whether to use CDN for retrievals (default: false) */ withCDN?: boolean /** Optional override for piece retrieval */ pieceRetriever?: PieceRetriever - /** Whether to disable NonceManager for automatic nonce management (default: false, meaning NonceManager is used) */ - disableNonceManager?: boolean /** Override Warm Storage service contract address (defaults to network's default) */ warmStorageAddress?: string - /** Override PDPVerifier contract address (defaults to network's default) */ - pdpVerifierAddress?: string // Subgraph Integration (provide ONE of these options) /** Optional override for default subgraph service, to enable subgraph-based retrieval. */ diff --git a/packages/synapse-sdk/src/utils/constants.ts b/packages/synapse-sdk/src/utils/constants.ts index 70aa0ac1..30e0dc74 100644 --- a/packages/synapse-sdk/src/utils/constants.ts +++ b/packages/synapse-sdk/src/utils/constants.ts @@ -2,9 +2,8 @@ * Constants for the Synapse SDK */ -import { erc20Abi, multicall3Abi } from 'viem' -import { erc20PermitAbi } from '../abis/erc20-permit.ts' -import * as abis from '../abis/gen.ts' +import { chains } from '@filoz/synapse-core' +import { multicall3Abi } from 'viem' import type { FilecoinNetworkType } from '../types.ts' /** @@ -30,34 +29,29 @@ export const CONTRACT_ABIS = { /** * ERC20 ABI - minimal interface needed for balance and approval operations */ - ERC20: erc20Abi, - - /** - * Minimal ERC20Permit ABI - for reading nonces() and version() - */ - ERC20_PERMIT: erc20PermitAbi, + ERC20: chains.mainnet.contracts.usdfc.abi, /** * Payments contract ABI - based on fws-payments contract */ - PAYMENTS: abis.paymentsAbi, + PAYMENTS: chains.mainnet.contracts.payments.abi, /** * PDPVerifier contract ABI - core PDP verification functions */ - PDP_VERIFIER: abis.pdpVerifierAbi, + PDP_VERIFIER: chains.mainnet.contracts.pdp.abi, /** * Warm Storage ABI - write functions and service provider management * View methods are in the WARM_STORAGE_VIEW contract */ - WARM_STORAGE: abis.filecoinWarmStorageServiceAbi, + WARM_STORAGE: chains.mainnet.contracts.storage.abi, /** * Warm Storage View contract ABI - read-only view methods separated from main contract * These methods were moved from the main Warm Storage contract to reduce contract size */ - WARM_STORAGE_VIEW: abis.filecoinWarmStorageServiceStateViewAbi, + WARM_STORAGE_VIEW: chains.mainnet.contracts.storageView.abi, /** * Multicall3 ABI - for batching multiple contract calls into a single RPC request @@ -67,12 +61,12 @@ export const CONTRACT_ABIS = { /** * ServiceProviderRegistry ABI - for provider management */ - SERVICE_PROVIDER_REGISTRY: abis.serviceProviderRegistryAbi, + SERVICE_PROVIDER_REGISTRY: chains.mainnet.contracts.serviceProviderRegistry.abi, /** * SessionKeyRegistry ABI - for session key management */ - SESSION_KEY_REGISTRY: abis.sessionKeyRegistryAbi, + SESSION_KEY_REGISTRY: chains.mainnet.contracts.sessionKeyRegistry.abi, } as const /** diff --git a/packages/synapse-sdk/src/warm-storage/service.ts b/packages/synapse-sdk/src/warm-storage/service.ts index e1544757..6b508be0 100644 --- a/packages/synapse-sdk/src/warm-storage/service.ts +++ b/packages/synapse-sdk/src/warm-storage/service.ts @@ -234,6 +234,10 @@ export class WarmStorageService { return this._addresses.sessionKeyRegistry } + getAddress(): string { + return this._warmStorageAddress + } + /** * Get the provider instance * @returns The ethers provider diff --git a/packages/synapse-sdk/tsconfig.json b/packages/synapse-sdk/tsconfig.json index 652d1e7f..6a55108b 100644 --- a/packages/synapse-sdk/tsconfig.json +++ b/packages/synapse-sdk/tsconfig.json @@ -5,6 +5,11 @@ }, "include": ["src/**/*"], "exclude": ["node_modules", "dist"], + "references": [ + { + "path": "../../packages/synapse-core" + } + ], "typedocOptions": { "entryPointStrategy": "resolve", "entryPoints": [ diff --git a/patches/viem.patch b/patches/viem.patch new file mode 100644 index 00000000..8127f6ed --- /dev/null +++ b/patches/viem.patch @@ -0,0 +1,12 @@ +diff --git a/_esm/accounts/privateKeyToAccount.js b/_esm/accounts/privateKeyToAccount.js +index b78582991ab867e8bf5d5fad9458699711f32050..e1c8cda40f1d2c253df445717d3696ab708c30e1 100644 +--- a/_esm/accounts/privateKeyToAccount.js ++++ b/_esm/accounts/privateKeyToAccount.js +@@ -38,6 +38,7 @@ export function privateKeyToAccount(privateKey, options = {}) { + return { + ...account, + publicKey, ++ privateKey, + source: 'privateKey', + }; + } diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c17509e2..94b37081 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,3 +9,6 @@ onlyBuiltDependencies: - msw - sharp - workerd + +patchedDependencies: + viem: patches/viem.patch