Synapse Core
Synapse Core (@filoz/synapse-core) is the low-level foundation that both the Synapse SDK and Synapse React build on. Use Synapse Core when you need:
- Direct control over individual contract calls without the
Synapseclass abstraction - Custom integrations that combine only the modules you need
Install dependencies:
npm install @filoz/synapse-core viempnpm add @filoz/synapse-core viemyarn add @filoz/synapse-core viembun add @filoz/synapse-core viemSynapse Core requires viem 2.x as a peer dependency.
Client setup:
All Synapse Core functions accept a viem Client as their first argument. Create one using viem’s standard client factories:
import { function createPublicClient<transport extends Transport, chain extends Chain | undefined = undefined, accountOrAddress extends Account | Address | undefined = undefined, rpcSchema extends RpcSchema | undefined = undefined, const tokens extends Tokens | undefined = undefined>(parameters: PublicClientConfig<transport, chain, accountOrAddress, rpcSchema, tokens>): PublicClient<transport, chain, ParseAccount<accountOrAddress>, rpcSchema, tokens>Creates a Public Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
- Docs: https://viem.sh/docs/clients/public
A Public Client is an interface to "public" [JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods such as retrieving block numbers, transactions, reading from smart contracts, etc through [Public Actions](/docs/actions/public/introduction).createPublicClient, function createWalletClient<transport extends Transport, chain extends Chain | undefined = undefined, accountOrAddress extends Account | Address | undefined = undefined, rpcSchema extends RpcSchema | undefined = undefined, const tokens extends Tokens | undefined = undefined>(parameters: WalletClientConfig<transport, chain, accountOrAddress, rpcSchema, tokens>): WalletClient<transport, chain, ParseAccount<accountOrAddress>, rpcSchema, tokens>Creates a Wallet Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
- Docs: https://viem.sh/docs/clients/wallet
A Wallet Client is an interface to interact with [Ethereum Account(s)](https://ethereum.org/en/glossary/#account) and provides the ability to retrieve accounts, execute transactions, sign messages, etc. through [Wallet Actions](https://viem.sh/docs/actions/wallet/introduction).
The Wallet Client supports signing over:
- [JSON-RPC Accounts](https://viem.sh/docs/clients/wallet#json-rpc-accounts) (e.g. Browser Extension Wallets, WalletConnect, etc).
- [Local Accounts](https://viem.sh/docs/clients/wallet#local-accounts-private-key-mnemonic-etc) (e.g. private key/mnemonic wallets).createWalletClient } from "viem"
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccountprivateKeyToAccount } from "viem/accounts"
import { const calibration: FilecoinChaincalibration } from "@filoz/synapse-core/chains"
import { function getTransport(chain: Chain): TransportgetTransport } from "@filoz/synapse-core/client"
// Read-only client for queries
const const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient = createPublicClient<Transport, FilecoinChain, undefined, undefined, undefined>(parameters: {
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined | undefined;
cacheTime?: number | undefined | undefined;
ccipRead?: {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | false | undefined | undefined;
... 7 more ...;
transport: Transport;
}): {
...;
}
Creates a Public Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
- Docs: https://viem.sh/docs/clients/public
A Public Client is an interface to "public" [JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/) methods such as retrieving block numbers, transactions, reading from smart contracts, etc through [Public Actions](/docs/actions/public/introduction).createPublicClient({
chain?: Chain | FilecoinChain | undefinedChain for the client.chain: const calibration: FilecoinChaincalibration, // or mainnet
transport: TransportThe RPC transporttransport: function getTransport(chain: Chain): TransportgetTransport(const calibration: FilecoinChaincalibration),
})
// Wallet client for transactions
const const account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
}
account = function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccountprivateKeyToAccount("0x...")
const const walletClient: {
account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
};
... 43 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
walletClient = createWalletClient<Transport, FilecoinChain, {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
... 4 more ...;
type: "local";
}, undefined, undefined>(parameters: {
...;
}): {
...;
}
Creates a Wallet Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/clients/chains).
- Docs: https://viem.sh/docs/clients/wallet
A Wallet Client is an interface to interact with [Ethereum Account(s)](https://ethereum.org/en/glossary/#account) and provides the ability to retrieve accounts, execute transactions, sign messages, etc. through [Wallet Actions](https://viem.sh/docs/actions/wallet/introduction).
The Wallet Client supports signing over:
- [JSON-RPC Accounts](https://viem.sh/docs/clients/wallet#json-rpc-accounts) (e.g. Browser Extension Wallets, WalletConnect, etc).
- [Local Accounts](https://viem.sh/docs/clients/wallet#local-accounts-private-key-mnemonic-etc) (e.g. private key/mnemonic wallets).createWalletClient({
account?: `0x${string}` | {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
} | Account | undefined
The Account to use for the Client. This will be used for Actions that require an account as an argument.account,
chain?: Chain | FilecoinChain | undefinedChain for the client.chain: const calibration: FilecoinChaincalibration, // or mainnet
transport: TransportThe RPC transporttransport: function getTransport(chain: Chain): TransportgetTransport(const calibration: FilecoinChaincalibration),
})The @filoz/synapse-core/chains subpath exports chain definitions with all contract addresses pre-configured for Filecoin Mainnet (mainnet) and Filecoin testnet (calibration) networks. Import the FOC chain type as FilecoinChain when you need it in TypeScript.
The @filoz/synapse-core/client subpath exports getTransport (ranked Filecoin RPC fallbacks), asClient, and toReadClient. Prefer getTransport(chain) over a bare http() endpoint when talking to mainnet or Calibration.
Pagination
Section titled “Pagination”Collection actions in Synapse Core return one bounded page at a time. They share the same options and result shapes:
type PaginationOptions = {
cursor?: bigint
limit?: bigint
}
type Page<T> = {
items: T[]
nextCursor?: bigint
}Some actions also return a total alongside the page. A cursor is an opaque continuation value: pass the returned nextCursor back as cursor without calculating or incrementing it yourself. An omitted limit uses the action’s bounded default, while an explicit limit must be greater than 0n.
To read one page, call the action directly:
import { function getClientDataSets(client: Client<Transport, Chain>, options: getClientDataSets.OptionsType): Promise<getClientDataSets.OutputType>getClientDataSets } from "@filoz/synapse-core/warm-storage"
const const page: getClientDataSets.OutputTypepage = await function getClientDataSets(client: Client<Transport, Chain>, options: getClientDataSets.OptionsType): Promise<getClientDataSets.OutputType>getClientDataSets(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, {
address: `0x${string}`address,
limit?: bigint | undefinedlimit: 25n,
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const page: getClientDataSets.OutputTypepage.items: DataSetInfo[]items)
if (const page: getClientDataSets.OutputTypepage.nextCursor?: bigint | undefinednextCursor !== var undefinedundefined) {
const const nextPage: getClientDataSets.OutputTypenextPage = await function getClientDataSets(client: Client<Transport, Chain>, options: getClientDataSets.OptionsType): Promise<getClientDataSets.OutputType>getClientDataSets(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, {
address: `0x${string}`address,
cursor?: bigint | undefinedcursor: const page: getClientDataSets.OutputTypepage.nextCursor?: bigintnextCursor,
limit?: bigint | undefinedlimit: 25n,
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const nextPage: getClientDataSets.OutputTypenextPage.items: DataSetInfo[]items)
}Use paginate() when you want to traverse every page. It follows nextCursor, yields individual items, and rejects a repeated or non-advancing cursor. A normal break exits the for await loop, closes the generator, and prevents any further page requests.
import { function paginate<T>(getPage: paginate.GetPage<T>, options?: paginate.OptionsType): paginate.OutputType<T>paginate } from "@filoz/synapse-core"
import { function getClientDataSetIds(client: Client<Transport, Chain>, options: getClientDataSetIds.OptionsType): Promise<getClientDataSetIds.OutputType>getClientDataSetIds } from "@filoz/synapse-core/warm-storage"
for await (const const dataSetId: bigintdataSetId of paginate<bigint>(getPage: paginate.GetPage<bigint>, options?: paginate.OptionsType): paginate.OutputType<bigint>paginate(({ cursor: bigintcursor }) =>
function getClientDataSetIds(client: Client<Transport, Chain>, options: getClientDataSetIds.OptionsType): Promise<getClientDataSetIds.OutputType>getClientDataSetIds(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, { address: `0x${string}`address, cursor?: bigint | undefinedcursor })
)) {
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const dataSetId: bigintdataSetId)
}
const const allDataSetIds: bigint[]allDataSetIds = await var Array: ArrayConstructorArray.ArrayConstructor.fromAsync<bigint>(iterableOrArrayLike: AsyncIterable<bigint> | Iterable<bigint | PromiseLike<bigint>> | ArrayLike<bigint | PromiseLike<bigint>>): Promise<bigint[]> (+1 overload)Creates an array from an async iterator or iterable object.fromAsync(
paginate<bigint>(getPage: paginate.GetPage<bigint>, options?: paginate.OptionsType): paginate.OutputType<bigint>paginate(({ cursor: bigintcursor }) =>
function getClientDataSetIds(client: Client<Transport, Chain>, options: getClientDataSetIds.OptionsType): Promise<getClientDataSetIds.OutputType>getClientDataSetIds(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, { address: `0x${string}`address, cursor?: bigint | undefinedcursor })
)
)The exported *Call helpers remain literal ABI adapters for multicalls. They use contract-facing fields such as offset or startPieceId and require an explicit limit; cursor translation and default limits are handled by the corresponding action.
Payments
Section titled “Payments”Query account balances, deposit funds, manage operator approvals, and settle payment rails on the Filecoin Pay contract.
import * as import paypay from "@filoz/synapse-core/pay"
import { function parseUnits(value: string, decimals: number): bigintMultiplies a string representation of a number by a given exponent of base 10 (10exponent).
- Docs: https://viem.sh/docs/utilities/parseUnitsparseUnits } from "viem"
// Query Filecoin Pay account info for the USDFC token
const const info: pay.accounts.OutputTypeinfo = await import paypay.function accounts(client: Client<Transport, Chain>, options: pay.accounts.OptionsType): Promise<pay.accounts.OutputType>accounts(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, {
// If not provided, the USDFC token address will be used.
token?: `0x${string}` | undefinedtoken: const calibration: FilecoinChaincalibration.FilecoinChain.contracts: {
multicall3: ChainContract;
usdfc: {
address: Address;
abi: typeof erc20WithPermit;
};
filecoinPay: {
address: Address;
abi: typeof filecoinPayV1Abi;
};
fwss: {
address: Address;
abi: typeof fwss;
};
fwssView: {
address: Address;
abi: typeof fwssView;
};
serviceProviderRegistry: {
address: Address;
abi: typeof serviceProviderRegistry;
};
sessionKeyRegistry: {
address: Address;
abi: typeof sessionKeyRegistryAbi;
};
pdp: {
address: Address;
abi: typeof pdpVerifierAbi;
};
endorsements: {
address: Address;
abi: typeof providerIdSetAbi;
};
}
Collection of contractscontracts.usdfc: {
address: Address;
abi: typeof erc20WithPermit;
}
usdfc.address: `0x${string}`address,
address: `0x${string}`address: const account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
}
account.address: `0x${string}`address,
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const info: pay.accounts.OutputTypeinfo.availableFunds: bigintavailableFunds) // bigint — funds available in Filecoin Pay
// Deposit USDFC in Filecoin Pay
const const depositTxHash: `0x${string}`depositTxHash = await import paypay.function depositAndApprove(client: Client<Transport, Chain, Account>, options: pay.DepositAndApproveOptions): Promise<`0x${string}`>depositAndApprove(const walletClient: {
account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
};
... 43 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
walletClient, {
// If not provided, the USDFC token address will be used.
token?: `0x${string}` | undefinedtoken: const calibration: FilecoinChaincalibration.FilecoinChain.contracts: {
multicall3: ChainContract;
usdfc: {
address: Address;
abi: typeof erc20WithPermit;
};
filecoinPay: {
address: Address;
abi: typeof filecoinPayV1Abi;
};
fwss: {
address: Address;
abi: typeof fwss;
};
fwssView: {
address: Address;
abi: typeof fwssView;
};
serviceProviderRegistry: {
address: Address;
abi: typeof serviceProviderRegistry;
};
sessionKeyRegistry: {
address: Address;
abi: typeof sessionKeyRegistryAbi;
};
pdp: {
address: Address;
abi: typeof pdpVerifierAbi;
};
endorsements: {
address: Address;
abi: typeof providerIdSetAbi;
};
}
Collection of contractscontracts.usdfc: {
address: Address;
abi: typeof erc20WithPermit;
}
usdfc.address: `0x${string}`address,
amount: bigintamount: function parseUnits(value: string, decimals: number): bigintMultiplies a string representation of a number by a given exponent of base 10 (10exponent).
- Docs: https://viem.sh/docs/utilities/parseUnitsparseUnits("1", 18), // 1 USDFC
})
await const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient.waitForTransactionReceipt: (args: WaitForTransactionReceiptParameters<FilecoinChain>) => Promise<TransactionReceipt>Waits for the [Transaction](https://viem.sh/docs/glossary/terms#transaction) to be included on a [Block](https://viem.sh/docs/glossary/terms#block) (one confirmation), and then returns the [Transaction Receipt](https://viem.sh/docs/glossary/terms#transaction-receipt). If the Transaction reverts, then the action will throw an error.
- Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
- Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
- JSON-RPC Methods:
- Polls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt) on each block until it has been processed.
- If a Transaction has been replaced:
- Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) and extracts the transactions
- Checks if one of the Transactions is a replacement
- If so, calls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt).waitForTransactionReceipt({
hash: `0x${string}`The hash of the transaction.hash: const depositTxHash: `0x${string}`depositTxHash
})
// Withdraw USDFC from Filecoin Pay
const const withdrawTxHash: `0x${string}`withdrawTxHash = await import paypay.function withdraw(client: Client<Transport, Chain, Account>, options: pay.withdraw.OptionsType): Promise<Hash>withdraw(const walletClient: {
account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
};
... 43 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
walletClient, {
// If not provided, the USDFC token address will be used.
token?: `0x${string}` | undefinedtoken: const calibration: FilecoinChaincalibration.FilecoinChain.contracts: {
multicall3: ChainContract;
usdfc: {
address: Address;
abi: typeof erc20WithPermit;
};
filecoinPay: {
address: Address;
abi: typeof filecoinPayV1Abi;
};
fwss: {
address: Address;
abi: typeof fwss;
};
fwssView: {
address: Address;
abi: typeof fwssView;
};
serviceProviderRegistry: {
address: Address;
abi: typeof serviceProviderRegistry;
};
sessionKeyRegistry: {
address: Address;
abi: typeof sessionKeyRegistryAbi;
};
pdp: {
address: Address;
abi: typeof pdpVerifierAbi;
};
endorsements: {
address: Address;
abi: typeof providerIdSetAbi;
};
}
Collection of contractscontracts.usdfc: {
address: Address;
abi: typeof erc20WithPermit;
}
usdfc.address: `0x${string}`address,
amount: bigintamount: function parseUnits(value: string, decimals: number): bigintMultiplies a string representation of a number by a given exponent of base 10 (10exponent).
- Docs: https://viem.sh/docs/utilities/parseUnitsparseUnits("1", 18), // 1 USDFC
})
await const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient.waitForTransactionReceipt: (args: WaitForTransactionReceiptParameters<FilecoinChain>) => Promise<TransactionReceipt>Waits for the [Transaction](https://viem.sh/docs/glossary/terms#transaction) to be included on a [Block](https://viem.sh/docs/glossary/terms#block) (one confirmation), and then returns the [Transaction Receipt](https://viem.sh/docs/glossary/terms#transaction-receipt). If the Transaction reverts, then the action will throw an error.
- Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
- Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
- JSON-RPC Methods:
- Polls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt) on each block until it has been processed.
- If a Transaction has been replaced:
- Calls [`eth_getBlockByNumber`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getblockbynumber) and extracts the transactions
- Checks if one of the Transactions is a replacement
- If so, calls [`eth_getTransactionReceipt`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getTransactionReceipt).waitForTransactionReceipt({
hash: `0x${string}`The hash of the transaction.hash: const withdrawTxHash: `0x${string}`withdrawTxHash
})Storage
Section titled “Storage”List approved storage providers.
import * as import warmStoragewarmStorage from "@filoz/synapse-core/warm-storage"
// Read one bounded page of approved provider IDs
const const page: warmStorage.getApprovedProviderIds.OutputTypepage = await import warmStoragewarmStorage.function getApprovedProviderIds(client: Client<Transport, Chain>, options?: warmStorage.getApprovedProviderIds.OptionsType): Promise<warmStorage.getApprovedProviderIds.OutputType>getApprovedProviderIds(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient)
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const page: warmStorage.getApprovedProviderIds.OutputTypepage.items: bigint[]items, const page: warmStorage.getApprovedProviderIds.OutputTypepage.nextCursor?: bigint | undefinednextCursor)Create a data set and upload a file.
import * as import piecepiece from "@filoz/synapse-core/piece"
import * as import spsp from "@filoz/synapse-core/sp"
import { function getPDPProvider(client: Client<Transport, Chain>, options: getPDPProvider.OptionsType): Promise<getPDPProvider.OutputType>getPDPProvider } from "@filoz/synapse-core/sp-registry"
// 1. Select a provider
const const provider: getPDPProvider.OutputTypeprovider = await function getPDPProvider(client: Client<Transport, Chain>, options: getPDPProvider.OptionsType): Promise<getPDPProvider.OutputType>getPDPProvider(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, { providerId: bigintproviderId: 1n })
if (!const provider: getPDPProvider.OutputTypeprovider) {
throw new var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error('Provider not found.');
}
// 2. Calculate PieceCID and upload data
const const pieceCid: piece.PieceCIDpieceCid = await import piecepiece.function calculate(input: piece.CalculateInput): Promise<piece.PieceCID>
export calculate
calculate(const data: Uint8Array<ArrayBuffer>data)
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const pieceCid: piece.PieceCIDpieceCid.PieceCID.size: numbersize) // size of the piece in bytes
// Upload the piece to the provider
await import spsp.function uploadPiece(options: sp.uploadPiece.OptionsType): Promise<void>uploadPiece({
data: Uint8Array<ArrayBufferLike>data,
pieceCid: piece.PieceCIDpieceCid,
serviceURL: stringserviceURL: const provider: PDPProviderprovider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL,
})
// Poll the provider to confirm the piece is stored
await import spsp.function findPiece(options: sp.findPiece.OptionsType): Promise<sp.findPiece.OutputType>findPiece({
pieceCid: piece.PieceCIDpieceCid,
serviceURL: stringserviceURL: const provider: PDPProviderprovider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL,
poll?: boolean | undefinedpoll: true,
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(`Piece ${const pieceCid: piece.PieceCIDpieceCid.CID<unknown, 85, 4113, 1>.toString(base?: MultibaseEncoder<string>): stringReturns a string representation of an object.toString()} uploaded to provider ${const provider: PDPProviderprovider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL}`)
// 3. Create a data set and add the piece on-chain
const const result: sp.createDataSetAndAddPieces.ReturnTyperesult = await import spsp.function createDataSetAndAddPieces(client: Client<Transport, Chain, Account>, options: sp.CreateDataSetAndAddPiecesOptions): Promise<sp.createDataSetAndAddPieces.ReturnType>createDataSetAndAddPieces(const walletClient: {
account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
};
... 43 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
walletClient, {
serviceURL: stringserviceURL: const provider: PDPProviderprovider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL,
payee: `0x${string}`payee: const provider: PDPProviderprovider.payee: `0x${string}`payee,
cdn?: boolean | undefinedcdn: false,
pieces: {
pieceCid: piece.PieceCID;
metadata?: MetadataObject;
}[]
pieces: [{ pieceCid: piece.PieceCIDpieceCid }],
})
// 4. Wait for the transaction on chain (follows the provider's fee replacements)
const const confirmed: sp.waitForCreateDataSetAddPieces.OutputTypeconfirmed = await import spsp.function waitForCreateDataSetAddPieces(options: sp.waitForCreateDataSetAddPieces.OptionsType): Promise<sp.waitForCreateDataSetAddPieces.OutputType>waitForCreateDataSetAddPieces({ client: Client<Transport, Chain, Account | undefined>client: const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, ...const result: sp.createDataSetAndAddPieces.ReturnTyperesult })
const { const dataSetId: bigintdataSetId, const pieceIds: bigint[]pieceIds, const txHash: `0x${string}`txHash } = const confirmed: sp.waitForCreateDataSetAddPieces.OutputTypeconfirmed
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(`Data set ${const dataSetId: bigintdataSetId} created and piece ${const pieceCid: piece.PieceCIDpieceCid.CID<unknown, 85, 4113, 1>.toString(base?: MultibaseEncoder<string>): stringReturns a string representation of an object.toString()} added to data set`)For large files, use uploadPieceStreaming instead of uploadPiece:
// Stream upload — PieceCID is calculated during transfer
const const stream: ReadableStream<Uint8Array<ArrayBufferLike>>stream = new var ReadableStream: new <Uint8Array<ArrayBufferLike>>(underlyingSource: UnderlyingDefaultSource<Uint8Array<ArrayBufferLike>>, strategy?: QueuingStrategy<Uint8Array<ArrayBufferLike>> | undefined) => ReadableStream<Uint8Array<ArrayBufferLike>> (+2 overloads)ReadableStream<interface Uint8Array<TArrayBuffer extends ArrayBufferLike = ArrayBufferLike>A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
requested number of bytes could not be allocated an exception is raised.Uint8Array>({ /* ... */ })
const const uploaded: sp.uploadPieceStreaming.OutputTypeuploaded = await import spsp.function uploadPieceStreaming(options: sp.uploadPieceStreaming.OptionsType): Promise<sp.uploadPieceStreaming.OutputType>uploadPieceStreaming({
data: anydata: const stream: ReadableStream<Uint8Array<ArrayBufferLike>>stream,
serviceURL: stringserviceURL,
onProgress?: ((bytesUploaded: number) => void) | undefinedonProgress(bytes: numberbytes) {
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(`${bytes: numberbytes} bytes uploaded`)
},
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const uploaded: sp.uploadPieceStreaming.OutputTypeuploaded.pieceCid: PieceCIDpieceCid) // PieceCID — calculated from streamed data
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const uploaded: sp.uploadPieceStreaming.OutputTypeuploaded.size: numbersize) // number — total bytes uploadedDownload a piece from a storage provider.
import { function downloadAndValidate(options: downloadAndValidate.OptionsType): Promise<Uint8Array>downloadAndValidate } from "@filoz/synapse-core/piece"
// Download a piece
const const data: Uint8Array<ArrayBufferLike>data = await function downloadAndValidate(options: downloadAndValidate.OptionsType): Promise<Uint8Array>downloadAndValidate({
url: stringurl: `${const provider: PDPProviderprovider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL}/piece`,
expectedPieceCid: string | PieceCIDexpectedPieceCid: "bafkzcib...",
})
var console: Consoleconsole.Console.log(...data: any[]): voidThe **`console.log()`** static method outputs a message to the console.
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)log(const data: Uint8Array<ArrayBufferLike>data) // Uint8Array — downloaded piece dataProvider Selection
Section titled “Provider Selection”For custom upload pipelines, you can use the provider selection functions directly to find matching data sets and providers:
import { function fetchProviderSelectionInput(client: Client<Transport, Chain>, options: fetchProviderSelectionInput.OptionsType): Promise<ProviderSelectionInput>fetchProviderSelectionInput, function selectProviders(options: ProviderSelectionOptions): ResolvedLocation[]selectProviders } from "@filoz/synapse-core/warm-storage"
// Fetch all chain data needed for selection
const const input: ProviderSelectionInputinput = await function fetchProviderSelectionInput(client: Client<Transport, Chain>, options: fetchProviderSelectionInput.OptionsType): Promise<ProviderSelectionInput>fetchProviderSelectionInput(const publicClient: {
account: undefined;
batch?: {
multicall?: boolean | Prettify<MulticallBatchOptions> | undefined;
} | undefined;
cacheTime: number;
ccipRead?: false | {
request?: (parameters: CcipRequestParameters) => Promise<CcipRequestReturnType>;
} | undefined;
chain: FilecoinChain;
dataSuffix?: DataSuffix | undefined;
experimental_blockTag?: BlockTag | undefined;
... 70 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
publicClient, {
address: `0x${string}`address: const account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
}
account.address: `0x${string}`address,
})
// Primary: pass endorsedIds to restrict pool to endorsed providers only
const [const primary: ResolvedLocationprimary] = function selectProviders(options: ProviderSelectionOptions): ResolvedLocation[]selectProviders({
...const input: ProviderSelectionInputinput,
ProviderSelectionOptions.count?: number | undefinedcount: 1,
ProviderSelectionOptions.metadata?: MetadataObject | undefinedmetadata: { source: stringsource: "my-app" },
})
// Secondary: pass empty set to allow any approved provider
const [const secondary: ResolvedLocationsecondary] = function selectProviders(options: ProviderSelectionOptions): ResolvedLocation[]selectProviders({
...const input: ProviderSelectionInputinput,
ProviderSelectionInput.endorsedIds: bigint[]endorsedIds: [],
ProviderSelectionOptions.count?: number | undefinedcount: 1,
ProviderSelectionOptions.excludeProviderIds?: bigint[] | undefinedexcludeProviderIds: [const primary: ResolvedLocationprimary.ResolvedLocation.provider: PDPProviderprovider.PDPProvider.id: bigintid],
ProviderSelectionOptions.metadata?: MetadataObject | undefinedmetadata: { source: stringsource: "my-app" },
})fetchProviderSelectionInput() makes a single multicall to gather providers, endorsements, and existing data sets. selectProviders() is a pure function (no network calls) that applies a 2-tier preference within the eligible pool:
- Existing data set with matching metadata
- New data set (no matching data set found)
The endorsedIds parameter controls which providers are eligible. When non-empty, only endorsed providers can be selected (no fallback to non-endorsed). When empty, all approved providers are eligible. See Storage Provider Tiers for what approval and endorsement mean and how providers qualify.
SP-to-SP Pull
Section titled “SP-to-SP Pull”Transfer pieces between providers without using client bandwidth:
import * as import SPSP from "@filoz/synapse-core/sp"
const const response: SP.pullPieces.ReturnTyperesponse = await import SPSP.function waitForPullPieces(client: Client<Transport, Chain, Account>, options: SP.waitForPullPieces.OptionsType): Promise<SP.waitForPullPieces.ReturnType>waitForPullPieces(const walletClient: {
account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
};
... 43 more ...;
extend: <const client extends {
...;
} & ExactPartial<...>>(fn: (client: Client<...>) => client) => Client<...>;
}
walletClient, {
serviceURL: stringserviceURL: const secondaryProvider: PDPProvidersecondaryProvider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL,
pieces: SP.PullPieceInput[]pieces: [{
pieceCid: PieceCIDpieceCid,
sourceUrl: stringsourceUrl: `${const primaryProvider: PDPProviderprimaryProvider.PDPProvider.pdp: PDPOfferingpdp.PDPOffering.serviceURL: stringserviceURL}/pdp/piece/${const pieceCid: anypieceCid}`,
}],
payee: `0x${string}`payee: const secondaryProvider: PDPProvidersecondaryProvider.payee: `0x${string}`payee,
payer?: `0x${string}` | undefinedpayer: const account: {
address: Address;
nonceManager?: NonceManager | undefined;
sign: (parameters: {
hash: Hash;
}) => Promise<Hex>;
signAuthorization: (parameters: AuthorizationRequest) => Promise<SignAuthorizationReturnType>;
signMessage: ({ message }: {
message: SignableMessage;
}) => Promise<Hex>;
signTransaction: <serializer extends SerializeTransactionFn<TransactionSerializable> = SerializeTransactionFn<TransactionSerializable>, transaction extends Parameters<serializer>[0] = Parameters<serializer>[0]>(transaction: transaction, options?: {
serializer?: serializer | undefined;
} | undefined) => Promise<Hex>;
signTypedData: <const typedData extends TypedData | Record<string, unknown>, primaryType extends keyof typedData | "EIP712Domain" = keyof typedData>(parameters: TypedDataDefinition<typedData, primaryType>) => Promise<Hex>;
publicKey: Hex;
source: "privateKey";
type: "local";
}
account.address: `0x${string}`address,
cdn?: boolean | undefinedcdn: false,
metadata?: MetadataObject | undefinedmetadata: {},
})This path requires manual EIP-712 signing. The signAddPieces and signCreateDataSetAndAddPieces functions from @filoz/synapse-core/typed-data handle the signature creation.
Check out the Synapse Core Reference for all available modules and functions.