statechannels / go-nitro

Implementation of nitro-protocol in Go
Other
39 stars 19 forks source link

Scope out a `transferAllAssets` -> `deposit` pipeline. #1342

Open NiloCK opened 1 year ago

NiloCK commented 1 year ago

POV: You are Irene, servicing Alice and Bob, who are a client & service provider, respectively. L(AI) is spent - Alice has no more in-network funds. L(BI) is spent - Bob has no more receive capacity.

Currently, you:

Suffering two L1 tx fees.

Irene is generally interested in cycling most funds accrued in service-client ledger channels back into service-provider ledger channels.

Could she combine these acts? Sure!

Proposed protocol:

  1. (off-chain) Irene, Bob update the outcome of their L(BI) to include Irene's pending increased balance (aka Bob's receive capacity)
    • This is unconditionally safe for Bob if the updated balance is appended to the outcome - IE, made lowest priority
  2. (off-chain) Alice, Irene update final outcome of L(AI) to point funds at L(BI) rather than Irene. (Alice performs this as a courtesy, possibly with a chapp backstop that allows Irene to perform it unilaterally).
  3. (on-chain) Irene calls concludeAndTransferAllAssets(), which triggers the assets to move to the correct channel.
  4. (off-chain) Irene, Bob update the outcome of L(BI) to "integrate" Irene's allocations (if they were disjoint after step 1). They also update the appData to reflect Irene's increased balance of interest-bearing capital.

Consideration: Deposited event?

The asset movement triggered by the above sequence doesn't actually hit nitro's usual deposit method. Should we consider emitting a deposited event when funds are transferred from one channel to another? Would make it easier for nitro nodes to know when to execute step 4.

The above protocol could as easily be used to fund new ledger channels as well as executing topups - is there a semantic difference to channel participants between on-chain receipts of funds through transfer and deposit?

Remark

Pairing this operation with batched transfers (#1334) could represent a significant cost saving.

NiloCK commented 1 year ago

Assumption:

Under this assumption, it'd be useful / common to liquidate several client ledger channels directly into one service provider ledger channel.

Protocol Revision

In step 2 from above, instead of adjusting L(AI)'s outcome to point at L(IB), we take a collection {L_i(AI)} of ledgers and adjust their outcomes to point at the BatchOperator contract.

Then, the channels are liquidated into L(IB) via something like:

BatchOperator.rebalanceBatch(
        INitroTypes.FixedPart[] memory fixedParts,
        INitroTypes.SignedVariablePart[] memory candidates,
        uint256 total,
        uint256 expectedHeld,
        address asset,
        bytes32 target
    ) public {
        require(fixedParts.length == candidates.length, lengthsErr);
        for (uint256 i = 0; i < fixedParts.length; i++) {
            adjudicator.concludeAndTransferAllAssets(fixedParts[i], candidates[i]);
        }
        adjudicator.deposit(asset, target, expectedHeld, amount);
    }

If liquidating, say, 10 client channels into one provider channel, this replaces the 10 Deposited emits with a single one. It's not completely obvious whether this flow improves storage read / write efficiency, since the prior sequential writes to move holdings[asset][sourceChannelID] to holdings[asset][targetChannelID] are now replaced by sequential moves of the same asset to the BatchOperator contract.

Possibly: this would be cheaper for ETH than existing, but more expensive for ERC20 operations.