---
# System prepended metadata

title: Snowball Liquidity Staking

---

# Snowball Liquidity Staking

## Design

[![](https://i.imgur.com/sWn9848.png)](https://i.imgur.com/sWn9848.png)

### User types

1. Investor - a person who stakes AVAX to Snowball contract on C-Chain
2. Node Operator - a person who participates in  Snowball Private Network consensus. Responsible to run Snowball Avalanche Node.
3. DAO member - holders of xSNOB token

### Flow
1. Deposit to Lido
    * `Investor` transfer AVAX to Snowball/Lido Smart Contract
    * Smart Contract keeps Node Operator list through DAO.
2. Smart Contract selects next Node Operator and transfer AVAX to its C-Chain address (potential risk ⚠️)
3. Off-chain relayer handles AVAX transfer from Smart Contract to Operator address
4. Construct unsigned [`ExportTx`](https://github.com/ava-labs/coreth/blob/6c2d53cd55cb474be488f378051c132a258dc577/plugin/evm/export_tx.go#L231-L239) and broadcast to Snowball Private Network
5. Snowball Private Network will produce a block with signed`ExportTx` transaction
6. Relayer gets it and broadcast to Avalanche Mainnet
7. `ExportTx` transaction get mined on Avalanche Mainnet, Relayer handles it and submit unsigned `ImportTx` to Snowball Private Network
8. Snowball Private Network will produce a block with signed`ImportTx` transaction
9. Relayer gets it and broadcast to Avalanche Mainnet
10. The same as 4.
11. The same as 5.
12. The same as 6.
13. The same as 7.
14. The same as 8.
15. The same as 9.
16.  Construct unsigned [`UnsignedAddDelegatorTx`](https://github.com/ava-labs/avalanchego/blob/master/vms/platformvm/add_delegator_tx.go#L293-L312) and broadcast to Snowball Private Network
17.  Get signed `AddDelegatorTx` transaction from Private Network
18.  🔥 Broadcast this tx for staking


## Relayer

Relayer subscribes to Smart Contract events on C-Chain, keeps track Node Operators list and Validators list from Smart Contract. 

Then constructs raw unsigned transaction (Export/Import/AddDelegatorTx) with built-in avalanche multisig.

⚠️ Probably these endpoints in Private Network need to have authorization. 
* One solution is to run relayer in trusted environment. 
* Another solution is to implement multisig on Relayer level as well. Run `N` nodes with `M` threshold (`M` < `N`)

## Snowball Private network

We are going to fork Avalanche source code and implement custom VM and block type. It will hold original unsigned tx and list of signatures applied during consensus.


⚠️ These nodes have to run in unseal mode (with unlocked wallet) to be able to sign transactions. It should be run in well secured environment and doesn't expose API Endpoint to Internet. The same private key will be used in Avalanche Mainnet.

## Smart Contract

TDB

## Rewards

TBD

## Risks

### Smart Contract security

Smart Contract code needs to be audited

### Node Operator malicious behavior

Even Node Operators controlled by DAO they could try to steal AVAX. To perform it they could watch for transfer event on C-Chain from Smart Contract to its account and immediatly transfer it to another account.
When relayer will submit signed `ExportTx` transaction (step 6.) it will fail because of insufficient funds.

There are a couple of solutions to minimize this risk:
* Handle failed transaction `ExportTx` (step 6) and exclude or pause this Node Operator on Smart Contract level
* Define maximum transfer value from Smart Contract to Node Operator account. For example 10 AVAX.
* Node Operator needs to pay some sort of security deposit prior to include to list. It should be at least 2x of maximum transfer amount

### Relayer malicious behavior

TDB

### Private Network node security

TBD


---



### [Draft] Block structure

Similar to `ProposalBlock`

```go=
// ProposalBlock is a proposal to change the chain's state.
//
// A proposal may be to:
//  1. Advance the chain's timestamp (*AdvanceTimeTx)
//  2. Remove a staker from the staker set (*RewardStakerTx)
//  3. Add a new staker to the set of pending (future) stakers
//     (*AddValidatorTx, *AddDelegatorTx, *AddSubnetValidatorTx)
//
// The proposal will be enacted (change the chain's state) if the proposal block
// is accepted and followed by an accepted Commit block
type ProposalBlock struct {
	CommonBlock `serialize:"true"`

	Tx Tx `serialize:"true" json:"tx"`
    
	Signatures Signatures // signatures from validator

	// The state that the chain will have if this block's proposal is committed
	onCommitState VersionedState
	// The state that the chain will have if this block's proposal is aborted
	onAbortState VersionedState
	// The function to execute if this block's proposal is committed
	onCommitFunc func() error
	// The function to execute if this block's proposal is aborted
	onAbortFunc func() error
}
```

* impelement custom `Verify()` method to ignore discrepancy in `Signatures` field. Because each validator will have its own signature.
* implement `onCommitState`, `onAbortState`, `onAbortFunc` with logic similar to `VersionedState`
* call `Apply()` method in `Block.Accept`

In `Apply()` method validator needs to sign the Transaction with private key. For it validator have to be running in unsealed mode: it means user need to import private key and unseal it (provide user and password on server start up). It adds aditional security requirements.
