Skip to content

Payment Operations

The Synapse SDK uses USDFC (a Filecoin-native stablecoin) for storage payments. Before uploading files, you must fund your account and approve operators.

This guide covers the essential operations. For advanced topics (understanding rails, settlement strategies), see Rails & Settlement.

Before working with payments, familiarize yourself with these fundamental concepts:

  • USDFC Token: Stablecoin on Filecoin which is used for all storage payments. The protocol requires USDFC approval before operations.
  • Payment Rails: Continuous payment streams created automatically when you upload files. Rate is fixed per epoch.
  • Epochs: Time periods (one epoch is 30 seconds). Payments accumulate per epoch and can be settled periodically.
  • Operator Allowances: Permissions that allow contracts (like WarmStorage) to spend your USDFC and create payment rails.

Monitor your account balance to ensure you have sufficient funds for storage operations.

const
const walletBalance: bigint
walletBalance
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.walletBalance(token?: TokenIdentifier): Promise<bigint>
walletBalance
();
const
const accountInfo: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
accountInfo
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.accountInfo(token?: TokenIdentifier): Promise<{
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}>
accountInfo
();
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Available:",
const accountInfo: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
accountInfo
.
availableFunds: bigint
availableFunds
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Locked:",
const accountInfo: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
accountInfo
.
lockupCurrent: bigint
lockupCurrent
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Spending rate:",
const accountInfo: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
accountInfo
.
lockupRate: bigint
lockupRate
, "per epoch");
import {
const TOKENS: {
readonly USDFC: "USDFC";
readonly FIL: "FIL";
}
TOKENS
} from "@filoz/synapse-sdk";
const
const amount: bigint
amount
=
function parseUnits(value: string | number | bigint | Dnum, decimals?: number): bigint
parseUnits
("100");
const
const hash: `0x${string}`
hash
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.depositWithPermit(amount: TokenAmount, token?: TokenIdentifier, deadline?: bigint): Promise<Hash>
depositWithPermit
(
const amount: bigint
amount
);
await
const synapse: Synapse
synapse
.
Synapse.client: Client<Transport, Chain, Account, PublicRpcSchema, PublicActions<Transport, Chain>>
client
.
waitForTransactionReceipt: (args: WaitForTransactionReceiptParameters<Chain>) => Promise<TransactionReceipt>

Waits for the Transaction to be included on a Block (one confirmation), and then returns the Transaction Receipt. If the Transaction reverts, then the action will throw an error.

@paramargs - WaitForTransactionReceiptParameters

@returnsThe transaction receipt. WaitForTransactionReceiptReturnType

@example

import { createPublicClient, http } from 'viem' import { mainnet } from 'viem/chains'

const client = createPublicClient({ chain: mainnet, transport: http(), }) const transactionReceipt = await client.waitForTransactionReceipt({ hash: '0x4ca7ee652d57678f26e887c149ab0735f41de37bcad58c9f6d3ed5824f15b74d', })

waitForTransactionReceipt
({
hash: `0x${string}`

The hash of the transaction.

hash
});
Alternative: Two-Transaction Deposit (not recommended)

If you cannot use permit-based deposits, you can use the traditional two-transaction approach:

// 1. Approve USDFC spending
await usdfc.approve(paymentAddress, depositAmount);
// 2. Deposit
await synapse.payments.deposit(depositAmount);

This requires two transactions and higher gas costs. Use depositWithPermit instead.

Important: Monitor your account health regularly. Insufficient balance causes payment failures and service interruptions.

import {
const TIME_CONSTANTS: {
readonly EPOCH_DURATION: 30;
readonly EPOCHS_PER_DAY: 2880n;
readonly EPOCHS_PER_MONTH: 86400n;
readonly DAYS_PER_MONTH: 30n;
readonly DEFAULT_LOCKUP_DAYS: 30n;
}
TIME_CONSTANTS
} from "@filoz/synapse-sdk";
const
const info: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
info
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.accountInfo(token?: TokenIdentifier): Promise<{
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}>
accountInfo
();
const
const epochsRemaining: bigint
epochsRemaining
=
const info: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
info
.
availableFunds: bigint
availableFunds
/
const info: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
info
.
lockupRate: bigint
lockupRate
;
const
const daysRemaining: number
daysRemaining
=
var Number: NumberConstructor
(value?: any) => number

An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.

Number
(
const epochsRemaining: bigint
epochsRemaining
) /
var Number: NumberConstructor
(value?: any) => number

An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.

Number
(
const TIME_CONSTANTS: {
readonly EPOCH_DURATION: 30;
readonly EPOCHS_PER_DAY: 2880n;
readonly EPOCHS_PER_MONTH: 86400n;
readonly DAYS_PER_MONTH: 30n;
readonly DEFAULT_LOCKUP_DAYS: 30n;
}
TIME_CONSTANTS
.
type EPOCHS_PER_DAY: 2880n
EPOCHS_PER_DAY
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
(`Days remaining: ${
const daysRemaining: number
daysRemaining
.
Number.toFixed(fractionDigits?: number): string

Returns a string representing a number in fixed-point notation.

@paramfractionDigits Number of digits after the decimal point. Must be in the range 0 - 20, inclusive.

toFixed
(1)}`);
if (
const daysRemaining: number
daysRemaining
< 7)
var console: Console
console
.
Console.warn(...data: any[]): void

The console.warn() static method outputs a warning message to the console at the 'warning' log level.

MDN Reference

warn
("⚠️ Low balance!");
const
const info: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
info
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.accountInfo(token?: TokenIdentifier): Promise<{
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}>
accountInfo
();
await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.withdraw(amount: TokenAmount, token?: TokenIdentifier): Promise<Hash>
withdraw
(
const info: {
funds: bigint;
lockupCurrent: bigint;
lockupRate: bigint;
lockupLastSettledAt: bigint;
availableFunds: bigint;
}
info
.
availableFunds: bigint
availableFunds
);

Operators are smart contracts authorized to spend your tokens for specific services. Before uploading files, you must approve the WarmStorage operator. This approval is required only once per operator and grants permission to create payment rails on your behalf.

Three types of allowances protect your funds from unauthorized spending:

  1. Rate Allowance - Max spending per epoch across all rails
  2. Lockup Allowance - Max total funds locked across all rails
  3. Max Lockup Period - Max duration funds can be locked (the safety net)

Approving warmStorage for 1TiB of storage for 3 months.

import {
const TIME_CONSTANTS: {
readonly EPOCH_DURATION: 30;
readonly EPOCHS_PER_DAY: 2880n;
readonly EPOCHS_PER_MONTH: 86400n;
readonly DAYS_PER_MONTH: 30n;
readonly DEFAULT_LOCKUP_DAYS: 30n;
}
TIME_CONSTANTS
} from "@filoz/synapse-sdk";
const
const months: 3n
months
= 3n;
const
const rateAllowance: bigint
rateAllowance
=
const monthlyPricePerTiB: bigint
monthlyPricePerTiB
/
const TIME_CONSTANTS: {
readonly EPOCH_DURATION: 30;
readonly EPOCHS_PER_DAY: 2880n;
readonly EPOCHS_PER_MONTH: 86400n;
readonly DAYS_PER_MONTH: 30n;
readonly DEFAULT_LOCKUP_DAYS: 30n;
}
TIME_CONSTANTS
.
type EPOCHS_PER_MONTH: 86400n
EPOCHS_PER_MONTH
;
const
const lockupAllowance: bigint
lockupAllowance
=
const monthlyPricePerTiB: bigint
monthlyPricePerTiB
*
const months: 3n
months
;
const
const maxLockupPeriod: 86400n
maxLockupPeriod
=
const TIME_CONSTANTS: {
readonly EPOCH_DURATION: 30;
readonly EPOCHS_PER_DAY: 2880n;
readonly EPOCHS_PER_MONTH: 86400n;
readonly DAYS_PER_MONTH: 30n;
readonly DEFAULT_LOCKUP_DAYS: 30n;
}
TIME_CONSTANTS
.
type EPOCHS_PER_MONTH: 86400n
EPOCHS_PER_MONTH
;
await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.approveService(service: Address, rateAllowance: TokenAmount, lockupAllowance: TokenAmount, maxLockupPeriod: TokenAmount, token?: TokenIdentifier): Promise<Hash>
approveService
(
const calibration: Chain
calibration
.
Chain.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 filecoinWarmStorageServiceStateViewAbi;
};
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 contracts

contracts
.
fwss: {
address: Address;
abi: typeof fwss;
}
fwss
.
address: `0x${string}`
address
,
const rateAllowance: bigint
rateAllowance
,
const lockupAllowance: bigint
lockupAllowance
,
const maxLockupPeriod: 86400n
maxLockupPeriod
);

Revoking warmStorage’s operator approvals.

await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.revokeService(service: Address, token?: TokenIdentifier): Promise<Hash>
revokeService
(
const calibration: Chain
calibration
.
Chain.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 filecoinWarmStorageServiceStateViewAbi;
};
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 contracts

contracts
.
fwss: {
address: Address;
abi: typeof fwss;
}
fwss
.
address: `0x${string}`
address
);
const
const approval: operatorApprovals.OutputType
approval
= await
const synapse: Synapse
synapse
.
Synapse.payments: PaymentsService
payments
.
PaymentsService.serviceApproval(service: Address, token?: TokenIdentifier): Promise<operatorApprovals.OutputType>
serviceApproval
(
const calibration: Chain
calibration
.
Chain.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 filecoinWarmStorageServiceStateViewAbi;
};
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 contracts

contracts
.
fwss: {
address: Address;
abi: typeof fwss;
}
fwss
.
address: `0x${string}`
address
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Approved:",
const approval: operatorApprovals.OutputType
approval
.
isApproved: boolean
isApproved
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
(
"Rate allowance:",
const approval: operatorApprovals.OutputType
approval
.
rateAllowance: bigint
rateAllowance
,
"used:",
const approval: operatorApprovals.OutputType
approval
.
rateUsage: bigint
rateUsage
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
(
"Lockup allowance:",
const approval: operatorApprovals.OutputType
approval
.
lockupAllowance: bigint
lockupAllowance
,
"used:",
const approval: operatorApprovals.OutputType
approval
.
lockupUsage: bigint
lockupUsage
);
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Max lockup period:",
const approval: operatorApprovals.OutputType
approval
.
maxLockupPeriod: bigint
maxLockupPeriod
);