---
# System prepended metadata

title: 'Actor Spec: PaymentChannel'

---

# Actor Spec: PaymentChannel

[Back to Master Tracking Doc](https://hackmd.io/LOZjAsz-THelSD5lWqSVlw)

## Contents

[TOC]

## At a Glance

The PaymentChannel actor allows two parties to establish an off-chain payment channel. This channel is only one directional from the party that sends the funds to the party that receives the funds.

* Both parties may engage in microtransactions off-chain by exchanging signed Vouchers.
* Vouchers may be submitted to the PaymentChannel instance by either party. Submitted Vouchers update the on-chain state of the PaymentChannel.
* Either party may call `Settle` to begin the PaymentChannel's settling period.
* Once the settling period ends, either party may call `Collect` to finalize the PaymentChannel's on-chain state, sending the appropriate amounts to each party and terminating the actor itself.

**Actor Type:**
- Instanced

**Exported Methods:**

1. Constructor
2. UpdateChannelState
3. Settle
4. Collect

## State

```go=
type State struct {
	From addr.Address
	To addr.Address
	ToSend abi.TokenAmount
	SettlingAt abi.ChainEpoch
	MinSettleHeight abi.ChainEpoch
	LaneStates []*LaneState
}
```

**`From`**: The owner of the channel. Expected to send microtransactions to `To` off-chain.
* Notes:
    * `From` is expected to fund the PaymentChannel with a token amount.
* Invariants:
    * `From` is an ID address
    * `From` is an Account actor

**`To`**: The beneficiary who receives payments off-chain in the form of signed vouchers.
* Notes:
    * `To` is expected to validate that the `CurrentBalance` of the PaymentChannel actor on-chain meets or exceeds the value of the vouchers being signed off-chain.
* Invariants:
    * `To` is an ID address
    * `To` is an Account actor

**`ToSend`**: The token amount successfully redeemed by the highest-nonce voucher submitted to `UpdateChannelState`. Paid to `To` on `Collect`.
* Notes:
    * Any remaining value will be sent to `From`.
* Invariants:
    * `ToSend >= 0`
    * `ToSend <= rt.CurrentBalance()`

**`SettlingAt`**: The epoch after which a call to `Collect` will send `ToSend` to `To`.
* Notes:
    * Initially, `SettlingAt` is set to 0, denoting that the PaymentChannel is not currently settling.
    * A nonzero value denotes that the PaymentChannel will settle at `SettlingAt`, at which point `Collect` can be called.
* Invariants:
    * `SettlingAt >= 0`

**`MinSettleHeight`**: If set, denotes the minimum epoch at which the PaymentChannel can `Settle`.
* Notes:
    * Can only be set via `UpdateChannelState`: both parties must agree to this value.
* Invariants:
    * `MinSettleHeight >= 0`

**`LaneStates`**: A collection of "lanes" between the parties. Each lane keeps track of its latest-seen `Nonce` and total `Redeemed` amount.
* Invariants:
    * `len(st.LaneStates) <= LaneLimit` (256)

#### LaneState

```go=
type LaneState struct {
	ID       uint64
	Redeemed big.Int
	Nonce    uint64
}
```

**`ID`**: The lane's ID in `st.LaneStates`.
* Notes:
    * Any valid `uint64` value may serve as an `ID`.
    * A signed voucher specifies to which lane it applies via the field `sv.Lane`

**`Redeemed`**: The token amount successfully redeemed by the highest-nonce voucher associated with this lane.
* Notes:
    * `Redeemed <= rt.CurrentBalance()`
    * `Redeemed >= 0`

**`Nonce`**: The highest-seen nonce attributed to a voucher redeemed for this lane.

## Exported Methods

#### 1. Constructor

```go=
func (pca *Actor) Constructor(rt vmr.Runtime, params *ConstructorParams) *adt.EmptyValue
```

Initializes actor state with the resolved addresses of `params.From` and `params.To` as the PaymentChannel's parties.

**`params.From`** may be provided as address protocols SECP, BLS, or ID.
**`params.To`** may be provided as address protocols SECP, BLS, or ID.

##### Failure conditions
* `params.From` is not an Account actor
* `params.To` is not an Account actor

#### 2. UpdateChannelState

```go=
func (a Actor) UpdateChannelState(rt vmr.Runtime, params *UpdateChannelStateParams) *adt.EmptyValue
```

Allows either party to update the channel's state by providing a voucher signed by their counterparty.

Supports two primary operations:
* Lane creation: If the lane specified by `params.Sv.Lane` does not exist, it will be created.
    * Up to 256 unique lanes may be exist in PaymentChannel before lane creation fails.
    * Lanes are created one-at-a-time: a maximum of 1 lane will be created per call to `UpdateChannelState`
    * On creation, the new lane is placed in `st.LaneStates` with the following values:
        * `ID`: `params.Sv.Lane`
        * `Redeemed`: `params.Sv.Amount`
        * `Nonce`: `params.Sv.Nonce`
* Lane merges: The redemption of a voucher through `UpdateChannelState` is an implicit "merge" of the voucher's `params.Sv.Amount` into the lane's state. A merge updates the lane's `Redeemed` and `Nonce` fields.
    * Additional merges may be specified through the optional field `params.Sv.Merges`. For each entry therein, a merge operation will be performed from `merge.Lane` into `params.Sv.Lane`.
    * Each merged lane's `Redeemed` total is subtracted from `params.Sv.Amount`. The sum of these operations is added to `st.ToSend`.

##### Parameters

```go=
type UpdateChannelStateParams struct {
	Sv     SignedVoucher
	Secret []byte
}
```

**`Sv`**: A voucher signed by either `st.From` or `st.To`

**`Secret`**: If the SignedVoucher has a SecretPreImage (`len(sv.SecretPreimage) > 0`), the hash of `Secret` must match it.
* Requirements:
    * `len(Secret) <= MaxSecretSize` (256)

###### SignedVoucher

```go=
type SignedVoucher struct {
	ChannelAddr addr.Address
    TimeLockMin abi.ChainEpoch
	TimeLockMax abi.ChainEpoch
	SecretPreimage []byte
	Extra *ModVerifyParams
	Lane uint64
	Nonce uint64
	Amount big.Int
	MinSettleHeight abi.ChainEpoch
	Merges []Merge
	Signature *crypto.Signature
}
```

**`ChannelAddr`**: The address of the PaymentChannel actor this SignedVoucher is valid for
* Requirements:
    * `ChannelAddr == rt.Message().Receiver()`

**`TimeLockMin`**: Before epoch `TimeLockMin`, this voucher may not be redeemed.
* Notes:
    * OPTIONAL. 0 by default.
* Requirements:
    * `rt.CurrEpoch() < TimeLockMin`

**`TimeLockMax`**: After epoch `TimeLockMax`, this voucher may not be redeemed. If `TimeLockMax` is 0, this field is not checked.
* Notes:
    * OPTIONAL. 0 by default.
    * `TimeLockMin == TimeLockMax` implies a 1-epoch window in which the voucher may be redeemed
* Requirements:
    * `TimeLockMax == 0 || rt.CurrEpoch() >= TimeLockMax`

**`SecretPreimage`**: If provided, `params.Secret` must be a valid preimage of `SecretPreimage`
* Notes:
    * OPTIONAL. `nil` by default.

**`Extra`**: If provided, `Extra` defines an arbitrary Send that should succeed when provided some additional `Proof` by the Caller.
* Notes:
    * OPTIONAL. `nil` by default.
    * No value will be sent with this Send.
    * See `ModVerifyParams` below for details on individual fields.
* Requirements:
    * The Send must succeed (`ExitCode == 0`)

**`Lane`**: Specifies which lane the voucher will be redeemed for.
* Notes:
    * If the lane does not exist within `st.LaneStates`, it will be created.
        * A lane may not be created if there are already 256 lanes in the PaymentChannel.

**`Nonce`**: Prevents the redemption of old vouchers. `Nonce` is compared to the highest-seen nonce of the lane specified by `Lane`. The lane's `ls.Nonce` will be set to `Nonce`.
* Requirements:
    * `ls.Nonce < Nonce`

**`Amount`**: The token amount this voucher may be redeemed for. The lane's `ls.Redeemed` field will be set to `Amount`.
* Notes:
    * The sum of `Amount`, the lane's current `ls.Redeemed` amount, and any `ls.Redeemed` amounts from other lanes specified in `Merges` will be added to `st.ToSend`.
* Requirements:
    * `Amount >= 0`

**`MinSettleHeight`**: If nonzero, may cause `UpdateChannelState` to modify the settling epoch.
* Notes:
    * OPTIONAL. 0 by default.
    * If the settling epoch has been set (`st.SettlingAt != 0`) AND `MinSettleHeight` specifies a greater epoch, the settling epoch is updated to `MinSettleHeight`.
    * If `MinSettleHeight` specifies a greater epoch than the one currently recorded in `st.MinSettleHeight`, this state is updated.
* Requirements:
    * `MinSettleHeight >= 0`

**`Merges`**: If provided, denotes a collection of other lanes that will be merged into the `Lane` specified by the voucher.
* Notes:
    * OPTIONAL. `nil` by default.
    * See `Merge` below.

**`Signature`**: A signature over `sv.SigningBytes`, signed by the counterparty to the Caller.
* Notes:
    * If Caller is `st.From`, the signature must be from `st.To`
    * If Caller is `st.To`, the signature must be from `st.From`
* Requirements:
    * `Signature != nil`
    * Must be a valid signature as determined by `rt.Syscalls().VerifySignature`

###### ModVerifyParams

```go=
type ModVerifyParams struct {
	Actor  addr.Address
	Method abi.MethodNum
	Params   []byte
}
```

**`Actor`**: The actor to which a Send will be made, denoting extra verification.

**`Method`**: The MethodNum of the actor to invoke.

**`Params`**: The data provided as parameters to the method invocation.

###### Merge

```go=
type Merge struct {
	Lane  uint64
	Nonce uint64
}
```

**`Lane`**: Which lane will be merged into the lane specified by the voucher (`sv.Lane`).
* Requirements:
    * `Lane` must exist in `st.LaneStates`
    * `Lane != sv.Lane`

**`Nonce`**: Compared to the highest-seen nonce of the merging lane. The lane's nonce is updated to this value.
* Requirements:
    * `Nonce` must be greater than the current nonce of the merging lane.

##### Failure conditions
* Caller is not `st.From` or `st.To`
* `sv.Signature == nil`
* `st.SettlingAt != 0 && rt.CurrEpoch >= st.SettlingAt`
* `len(params.Secret) > MaxSecretSize` (256)
* SignedVoucher unable to be serialized via `SigningBytes`
* Signature verification fails (via `rt.Syscalls().VerifySignature`)
* SignedVoucher is not valid for this PaymentChannel (`rt.Message().Receiver() != sv.ChannelAddr`)
* `rt.CurrEpoch() < sv.TimeLockMin`
* `sv.TimeLockMax != 0 && rt.CurrEpoch() > sv.TimeLockMax`
* `sv.Amount < 0`
* `len(sv.SecretPreimage) != 0` AND hashed `params.Secret` does not match
* `sv.Extra != nil` AND external validation fails
* `sv.Lane` specifies a lane that does not exist in `st.LaneStates` AND `len(st.LaneStates) >= 256`
* `ls.Nonce >= sv.Nonce`
* For any provided Merge:
    * `merge.Lane == sv.Lane`
    * `merge.Lane` does not exist in `st.LaneStates`
    * Nonce specified by `merge.Lane` LaneState is greater than or equal to nonce specified by `merge.Nonce`
* Updated `st.ToSend` balance would be negative
* Updated `st.ToSend` balance would be greater than the current balance of the PaymentChannel

#### 3. Settle

```go=
func (pca Actor) Settle(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue
```

Sets `st.SettlingAt`, which is the epoch where either party may call `Collect`. This may only be called once.
* `st.SettlingAt` is set to the maximum value between `rt.CurrEpoch() + SettleDelay` and `st.MinSettleHeight`

Once the channel has settled (`CurrEpoch == st.SettlingAt`), further updates to the channel are prohibited.

##### Failure conditions
* Caller is not `st.From` or `st.To`
* `Settle` has already been called (`st.SettlingAt != 0`)

#### 4. Collect

```go=
func (pca Actor) Collect(rt vmr.Runtime, _ *adt.EmptyValue) *adt.EmptyValue
```

At or after the settling epoch, allows either party to collect the amount redeemed so far.
* `st.ToSend` is sent to `st.To`
* The PaymentChannel actor is deleted via `rt.DeleteActor`, with `st.From` supplied as the beneficiary of the remaining funds.

##### Failure conditions
* Caller is not `st.From` or `st.To`
* `st.SettlingAt == 0`, denoting that `Settle` has not been called yet
* `rt.CurrEpoch() < st.SettlingAt`, denoting that the settling epoch has not been reached
* The Send to `st.To` fails
* `rt.DeleteActor(st.From)` fails because `st.From` does not exist

## Open Questions

* UpdateChannelState: Does `SigningBytes()` add additional salt, domain separators, or other information to ensure that signed vouchers are unique in respect to both the payment channel AND the specific permutation of provided values?
* UpdateChannelState: Does `Syscalls().VerifySignature()` resolve the `signer` to a BLS/SECP address?
* UpdateChannelState: Should `SignedVoucher.ChannelAddr` use the PaymentChannel's ACTOR address for re-org protection?
* Collect: Could `st.From` cause the first `Send` to fail in any way outside of the actor being underfunded already?