# Staking Contracts

Open Source Contracts: <https://github.com/coinecta/staking-contracts/>

Sundae Labs Audit: <https://coinecta.fi/downloads/coinecta-staking-audit.pdf>

The Coinecta staking contracts support the requirement of being able to allow users to lock tokens for certain time periods and get a percentage reward for it. Because these locking periods can potentially be long, we bind the time lock to a unique NFT (the stake key) minted during the locking transaction. This allows the user to move to another wallet (for example due to loss of seed phrase of the original wallet) or even sell the stake key to someone else on a secondary market such as jpg.store.

<figure><img src="https://github.com/coinecta/staking-contracts/raw/main/img/coinecta-staking-overview.png" alt=""><figcaption></figcaption></figure>

## Main requirements

These are the main requirements the contracts need to fulfil:

* Guarding the assets in the stake pool to only be used as rewards for staking
* Protect the user and ensure the staking reward and time period match their expectation
* Mint unique stake key to the user
* Rewards are part of the lock from the beginning.

## Validators

### stake\_pool

This validator ensures that the assets within the UTXO are only spent by a locking transaction or by the owner of the stake pool. Part of it's datum is a list of RewardSettings, each containing a valid locking period in days and the percentage reward that follows with it. The owner can choose to remove the assets from the stake pool or change the reward settings at any time.

Main validations to be done in a locking transaction:

* A new utxo is made with the same datum and validator attached.
* The reward matches the percentage in the chosen reward setting.
* The assets are unchanged other than the reward that is moved to the time lock utxo
* The time lock is locked according to the chosen reward setting.

### stake\_proxy

This validator protects the assets that the user wants to lock. Because the stake\_pool is a singleton interacting with it directly could give issues during busy periods. So the user defines their staking order in a stake\_proxy utxo after which automated off chain code can ensure the order is fulfilled. If for whatever reason the order is not fulfilled the utxo can be refunded in a transaction signed by the user.

Main validations to be done in a locking transaction:

* The reward is matching user expectation
* The locking period is matching user expectation
* The stake key is minted to the user using expected policy

### time\_lock

This is a fairly simple time lock, making sure it can not be spend before a certain time. Once the time is reached it can be spend as long as the stake key is burned in the same transaction.

Main validations to be done in unstake transaction:

* The transaction is executed after the unlock time has been reached.
* The stake key is burned in the transaction.

## Minting policies

### stake\_key\_mint

This minting policy checks which assets are locked and when they unlock. On top of that it ensures the asset name is unique.

The expected template for the stake key asset name is:

{% code overflow="wrap" %}

```
s{staked amount}{staked asset name}{unlock date}{time}{stake_pool output_index}{stake_pool tx_hash}
```

{% endcode %}

| Component                  | length | description                                                                                                   |
| -------------------------- | ------ | ------------------------------------------------------------------------------------------------------------- |
| prefix s                   | 1      |                                                                                                               |
| staked amount              | 4      | Staked amount including reward, max 3 digits + letter (for example 345K)                                      |
| staked asset name          | 6      | First 6 characters of the staked asset                                                                        |
| unlock date                | 6      | Date on which stake is unlocked, format YYMMDD                                                                |
| time                       | 4      | 8 most significant digits of upper validity of transaction, encoded as hex values (so 2 digits form one byte) |
| stake\_pool\_output\_index | 1      | Output index of the stake\_pool that is part of the transactions' input                                       |
| stake\_pool tx\_hash       | 10     | First characters of the hex representation of the tx\_hash of the stake\_pool input                           |
| total                      | 32     |                                                                                                               |

Main validations during a mint:

* Asset name follows the expected template
* Only 1 NFT is minted

## Transactions

### Create stake proxy

| inputs      | mints | outputs      |
| ----------- | ----- | ------------ |
| user wallet |       | stake\_proxy |

<figure><img src="https://github.com/coinecta/staking-contracts/raw/main/img/coinecta-staking-create-proxy.png" alt=""><figcaption></figcaption></figure>

### Create Stake Pool

| inputs       | mints | outputs     |
| ------------ | ----- | ----------- |
| owner wallet |       | stake\_pool |

<figure><img src="https://github.com/coinecta/staking-contracts/raw/main/img/coinecta-staking-create-pool.png" alt=""><figcaption></figcaption></figure>

### Lock stake

| inputs       | mints                | outputs                     |
| ------------ | -------------------- | --------------------------- |
| stake\_pool  |                      | stake\_pool                 |
| stake\_proxy |                      | time\_lock                  |
|              | stake\_key\_mint + 1 | user wallet                 |
|              |                      | Off chain operator (change) |

<figure><img src="https://github.com/coinecta/staking-contracts/raw/main/img/coinecta-staking-lock.png" alt=""><figcaption></figcaption></figure>

### Unstake

| inputs      | mints                | outputs     |
| ----------- | -------------------- | ----------- |
| time\_lock  |                      | user wallet |
| user wallet | stake\_key\_mint - 1 |             |

<figure><img src="https://github.com/coinecta/staking-contracts/raw/main/img/coinecta-staking-unstake.png" alt=""><figcaption></figcaption></figure>

## Building

```
aiken build
```

## Testing

You can write tests in any module using the `test` keyword. For example:

```
test foo() {
  1 + 1 == 2
}
```

To run all tests, simply do:

```
aiken check
```

To run only tests matching the string `foo`, do:

```
aiken check -m foo
```

## Documentation

If you're writing a library, you might want to generate an HTML documentation for it.

Use:

```
aiken docs
```

## Resources

Find more on the [Aiken's user manual](https://aiken-lang.org/).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.coinecta.fi/technical-documentation/staking-contracts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
