The backend
parameter is an object of the abstract type PluginBackend
:
interface PluginBackend {
getTransferLog(options): TransferLog
}
interface TransferLogOptions {
maximum: string | null, // Maximum allowed balance (or null if unlimited)
minimum: string | null, // Minimum allowed balance (or null if unlimited)
}
interface TransferLog {
async setMaximum(n: string): void
async setMinimum(n: string): void
async getMaximum(): string
async getMinimum(): string
async getBalance(): string
async get(transferId: string): Promise<TransferWithInfo> // Asynchronously retrieve a transfer from the persistent store
async prepare(transfer: Transfer, isIncoming: boolean): Promise<void> // Asynchronously prepare a transfer in the persistent store
async fulfill(transferId: string, fulfillment: string): Promise<void> // Set transfer state to fulfilled
async cancel(transferId: string): Promise<void> // Set transfer state to canceled
async cancelExpired(now: DateTime): Promise<void> // cancels all prepared transfers whose `.expiresAt` is before now
}
interface TransferWithInfo {
// see Ledger Plugin Interface, plus:
direction: 'incoming' (counts towards upper estimate while prepared) or 'outgoing' (counts towards lower estimate while prepared)
fulfillment: string
state: 'prepared', 'fulfilled', or 'cancelled'
transfer: Transfer
}
At any time there is a range of possible future balance, depending on which prepared transfers will be fulfilled, and which ones will be rejected. The conditions for successfully preparing a new transfer are:
balance + SUM(incomingPrepared) <= maxBalance
balance - SUM(outgoingPrepared) >= minBalance
When a transfer is fulfilled, the balance is updated:
balance += incomingTransfer.amount
balance -= outgoingTransfer.amount
If a transfer is rejected, nothing happens to the balance, but for both fulfilling and rejecting, the transfer in question is removed from the set of prepared transfers.
Outgoing settlements are modeled as incoming transfers, and vice versa.
The currently existing key-value store will still exist, and will become multi-process shared.
We can imagine several implementations of this interface:
MockPluginBackend
- In-memory backend for unit tests or developmentSequelizePluginBackend
- Simple single-process backend for ILP KitKafkaPluginBackend
- More sophisticated and scalable future backend for multi-process environments
I think
rejectionReason
should be part of the TransferWithInfo interface