Standardized Deposit and Withdrawal

Interledger Protocol Proposal

Standardized Deposit and Withdrawal

Motivation

Currently, there is no standardized way for users of an ILP service to deposit or withdraw funds from their account. In other words, there is no prescribed means of moving money into or out of the ILP system, nor the API support to update account balances and issue transactions on the appropriate ledger.

This is an important core component of any ILP service provider that is facing the edges of the network (as opposed to acting solely as a connector), and requiring each node to independently scope and implement such a system could significantly hinder adoption due to increased cost and security risk creating a substantial hurdle.

Consequently, we propose that (1) such a standard be created and (2) that reference implementations for various ledgers be produced. In sticking with the general ILP philosophy, this solution should be standardized across ledgers with the lower layer ledger mechanics (Layer 1 & 2) abstracted. We additionally argue that systems such as the ILP account system and the ledger interface/key management system should be self-contained and only publicly expose atomic, complete functions to ensure security, prevent dependencies, and avoid code/function duplication.

Proposed Solution

We propose expanding the current Settlement Engine concept to a General Ledger Interface (GLI), which handles all settlement functions on behalf of an ILP node for a given ledger. The GLI will facilitate ILP node to ILP node (i.e. ILP peering) settlements as well as the on-ledger deposit and withdrawal transactions.

The GLI would be the sole custodial module of the access to its particular settlement rail (the key manager in the case of a cryptocurrency), which restricts complexity bloat in access management and, more importantly, avoids any race conditions that could arise during withdrawals with separate key managers.

Besides the ledger itself, the GLI will only interface with the ILP node. This insulates its safety critical functionality and also ensures that the ledger settlement details are appropriately abstracted from any service built on top of the ILP node.

We believe the alternative — requiring the user service to bypassing the ILP node to interface with the settlement module directly — is an inferior system design choice for several reasons:

  1. Breaks down the layering structure and removes the abstraction that is one of the key value propositions of ILP (services interacting with ILP on L3 should not have to interface with L1/L2)
  2. Creates a large number of potential edge cases since both ILP node and service provider will both be communicating with the settlement module
  3. Increases the complexity of deploying and managing a service

Deposit and withdrawal would further require two additional, asynchronous API methods at the ILP node, one for each action. When these API functions are called, the ILP node interfaces with the GLI to provide the response and, if appropriate, execute a transaction on the ledger. The asynchronous API methods should provide a service that is similar to the features provided by “reliable transaction submission” in which the status shall guarantee the finality of the on-ledger transaction. Conventionally there should be two status provided by these APIs: the first status confirms/rejects the submission of the withdraw/deposit request and the second status confirms/rejects the finality of the submitted transaction.

The Deposit API function would instruct the ILP node to return an “address” (which would vary in form, depending on the currency rail), with all the necessary information for a user to deposit into the system. In the case of XRP, this would involve the GLI providing an XRP address plus a tag (or an X-address) that is forwarded to the client via the ILP node. Then, the GLI would listen on the ledger for the transaction and report it to the ILP node, which would update the appropriate account balance and send a success notification to the client.

The Withdraw API function would provide the ILP node with a similar “address” that has all the necessary information for the withdrawal transaction plus amount and account. The GLI would then execute the transaction on the ledger and provide confirmation to the ILP node, which would update the appropriate account balance and send a success notification to the client.

Further Considerations

System Design

The GLI could either be an expansion of the Settlement Engine specification itself or a broader module that includes the Settlement Engine, the Deposit/Withdrawal Engine, and a Key Management System. In the case of the latter, access to the custodied funds would need to be serialized and controlled via a semaphore to prevent unforeseen race conditions.

Withdrawal Conditions

Handling withdrawal can be tricky in the presence of unsettled channels with ILP peers. For example: User X wishes to withdraw 100 XRP from ILP service provider A who is currently has 0 XRP in its XRP Settlement Engine address and 100 XRP owed in a channel with ILP node B. A must decide whether that should force a settlement of its channel with B or if it should return an error on the Withdraw request.

1 Like

Thanks @mzochowski for writing up this proposal!

I’m still trying to wrap my head around what would be needed to support this.

Would this work for payment channel based settlement engines or only on-ledger ones? If it supported payment channels, would the interface also need to be extended to handle operations like opening, closing, topping up, and checking the payment channel balance (in addition to operations related to the on-ledger balance)? I wonder if it would be possible to abstract away the differences between the different channel constructions. Also, if you had a GLI for a payment channel network like lightning, would the withdrawal be to a lightning address, a bitcoin address, or both?

Are there any other APIs that would be needed aside from deposit / withdraw to support the kinds of use cases you’re imagining?

1 Like

You’re right that payment channel settlement is challenging. I’m not sure if it is better to limit the scope to on-ledger settlement (including fiat) or strive for a more general standard. In the case of the latter, the Deposit and Withdraw functions would likely have to support a few round trips of communication to set up the channels in addition to more generalized support for the operations you mentioned. However, this can still be abstracted from the perspective of the ILP node and the user-facing service themselves. This could be achieved by the introduction of a third API method for “LinkedAccountManagement” (we’d need a better name) that wraps all the settlement rail logic in a standardized package.

In my mind this is an open question, so hopefully some others can weigh in. In the meantime, I think it would be instructive to further drill down into the simpler on-ledger flow.

1 Like

I don’t entirely agree with this but that depends how you setup your wallet. For example, if you give your users raw ILP access to their own accounts then they can use the protocols defined for the Settlement Engine to make deposits and withdrawals.

E.g. Imagine a user has an account with a wallet that is denominated in XRP. The wallet runs an XRP settlement engine.

To make a deposit, the user connects to their account via the /ilp endpoint exposed by the wallet and sends the necessary peer.settle packets to setup settlement with the wallet via XRP. The user then does a settlement to the wallet on the XRP Ledger which is picked up by the wallet’s Settlement Engine and the user’s account is credited.

To make a withdrawal the user uses ILDCP to establish their own ILP address and sends themself packets until they trigger a settlement from the wallet to them.

Can say specifically what functions you’d add to the existing Settlement Engine?

I would favour a design where these are all kept separate and the function of the Deposit/Withdrawal Engine is to expose an API as you describe to wallet users but it would then interface with the Settlement Engine via the node.

In effect the D/W Engine would perform the deposit and withdrawal functions as I described above on behalf of the user. It would not need any keys for access to the settlement system, these would still be held by the Settlement Engine exclusively.

I’m still getting up-to-speed on the ILP architecture, so hope you bear with me on a specific example to help frame this discussion.

ILP Service Provider InterCo connects consumers to ILP via front end wallet portal (Wallet). To do so, InterCo runs a Connector node with an XRP Settlement Engine. InterCo uses a single, commingled XRP account to custody users’ XRP.

Alice has an account on Coinbase with 100 XRP. She doesn’t have access to her account’s private key, but she can send to an XRP address + tag and can receive at her account’s address + tag. She creates an account at the InterCo Wallet to use ILP and gets an ILP payment pointer.

Scenario A: Alice wants to deposit 100 XRP into her InterCo account from Coinbase
Scenario B: Alice wants to withdraw 100 XRP from her InterCo account to Coinbase

If I am understanding this correctly, you are suggesting that the InterCo Wallet spin up an ad hoc settlement engine on behalf of Alice that exchanges ILP packets with the Connector Settlement Engine up to 100 XRP and triggers a settlement. Does the Connector Settlement Engine provide an XRP address and a tag that Alice will need to manually trigger the Coinbase send? How does the Connector know which account that belongs to? Does InterCo Wallet need to call an API to adjust Alice’s account at the Connector?

Similar questions here: can this be handled completely by the Wallet without Alice’s knowledge?

My more general concern with this approach is the complexity required to implement at the Wallet level. Deposit/Withdraw are among the most basic functions any ILPSP will need to provide to users, and any additional requirements at the wallet level beyond interfacing with an ILP node could become a hurdle for adoption.

From what I understand, the Settlement Engine specification is pretty set, so what I think the separate D/W Engine may be the easiest course.

If “node” here refers to the ILP node/connector, then I believe we are on the same page.

I’m largely in support of this. Now that the community has reached a point where we have a target customer demographic (custodial wallets) for our connector implementations I think it makes sense to implement this on our end to reduce friction and ensure it it is implemented in a secure way.

The GLI could either be an expansion of the Settlement Engine specification itself or a broader module that includes the Settlement Engine, the Deposit/Withdrawal Engine, and a Key Management System.

I support one of these implementations as opposed to isolating each into their own service. I think constraining key access to a single service makes it easier to secure and reduces likelihood of any race conditions.

Would this work for payment channel based settlement engines or only on-ledger ones?

My vote is to only implement on-ledger. I think it’s fair to assume that most users would be migrating funds from another custodial wallet, and I’m not aware of any popular wallet today that gives the option to withdraw funds over L2. Solely implementing this for L1 would reduce complexity (and correspondingly the potential for messing up management of funds) and allow us to ship a reference implementation faster.

Additionally, any user that is sophisticated enough to be holding funds in L2 will have no issue dropping them back to L1 to migrate. I suspect this will be such a niche of users that this tradeoff of UX would be worth the saved complexity and time.

@mzochowski thanks for bringing this up. Partners joining the ecosystem in the past have struggled significantly with piecing together all of the different components necessary to run a full node. The more we can do for them, the better. I’d love to see a spec on a simple L1 API interface.

1 Like