# Snowball Liquidity Staking
## Design
[](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.