Skip to content

Feature/crowdfund script #662

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement in core mesh repo `mesh-contract`
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# This file was generated by Aiken
# You typically do not need to edit this file

[[requirements]]
name = "aiken-lang/stdlib"
version = "v2.2.0"
source = "github"

[[requirements]]
name = "sidan-lab/vodka"
version = "0.1.13"
source = "github"

[[packages]]
name = "aiken-lang/stdlib"
version = "v2.2.0"
requirements = []
source = "github"

[[packages]]
name = "sidan-lab/vodka"
version = "0.1.13"
requirements = []
source = "github"

[etags]
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name = "sidan-lab/crowdfund"
version = "0.0.0"
compiler = "v1.1.16"
plutus = "v3"
license = "Apache-2.0"
description = "Aiken contracts for project 'sidan-lab/crowdfund'"

[repository]
user = "sidan-lab"
project = "crowdfund"
platform = "github"

[[dependencies]]
name = "aiken-lang/stdlib"
version = "v2.2.0"
source = "github"

[[dependencies]]
name = "sidan-lab/vodka"
version = "0.1.13"
source = "github"

[config]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use cardano/address.{Address}

pub type MintPolarity {
RMint
RBurn
}

pub type CrowdfundRedeemer {
ContributeFund
CompleteCrowdfund
ContributorWithdrawal
RemoveEmptyInstance
}

pub type CrowdfundDatum {
completion_script: ByteArray,
share_token: ByteArray,
crowdfund_address: Address,
fundraise_target: Int,
current_fundraised_amount: Int,
allow_over_subscription: Bool,
deadline: Int,
expiry_buffer: Int,
fee_address: Address,
min_charge: Int,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use aiken/collection/list
use aiken/collection/pairs
use cardano/address.{Address}
use cardano/assets.{Lovelace, from_lovelace}
use cardano/transaction.{Input, Output, Redeemer, ScriptPurpose, Spend}

pub fn redeemer_with_input(
redeemers: Pairs<ScriptPurpose, Redeemer>,
input: Input,
) -> Option<Data> {
let output_reference = input.output_reference
redeemers |> pairs.get_first(Spend(output_reference))
}

pub fn check_fundraise_target(
allow_over_subscription: Bool,
fundraise_target: Int,
current_fundraised_amount: Int,
) -> Bool {
if allow_over_subscription {
True
} else {
current_fundraised_amount <= fundraise_target
}
}

pub fn outputs_at_with_lovelace(
outputs: List<Output>,
address: Address,
lovelace: Lovelace,
) -> List<Output> {
list.filter(
outputs,
fn(output) {
let is_lovelace_match = output.value == from_lovelace(lovelace)
is_lovelace_match && output.address == address
},
)
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Auth Token - One Shot

## Parameter

- `utxo_ref`: UTxO to be spent at minting

## User Action

1. Mint - Redeemer `RMint`

- Transaction hash as parameterized is included in input

2. Burn - Redeemer `RBurn`

- The current policy id only has negative minting value in transaction body.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Share Token

## Parameter

- `auth_token`: The policy id of `AuthToken`

## User Action

1. Mint - Redeemer `RMint`

- There is input with `auth_token` with redeemer `ContributeFund`

2. Burn - Redeemer `RBurn`

- The current policy id only has negative minting value in transaction body.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Specification - Crowdfund

## Parameter

- `auth_token`: The policy id of `AuthToken`
- `proposer_key_hash`: ByteArray

## Datum

- `completion_script`: ByteArray
- `share_token`: ByteArray
- `crowdfund_address`: Address
- `fundraise_target`: Int
- `current_fundraised_amount`: Int
- `allow_over_subscription`: Bool
- `deadline`: Int
- `expiry_buffer`: Int
- `fee_address`: Address
- `min_charge`: Int

## User Action

1. ContributeFund

- There is only 1 input with `auth_token` from current address, and 1 output with `auth_token` and to current_address
- Not allowed other token deposit in output. Min contribution 2 ADA
- The value increase in current respending utxo equal to the increase in `current_fundraised_amount`, comparing input output datum
- If `allow_over_scription` is False, check whether `current_fundraised_amount` <= `fundraise_target`
- `deadline` is not passed
- `Shares` - Minted exactly the amount of `share_token` that lovelave contributed, with token name of `completion_script`

2. CompleteCrowdfund

- `min_charge` goes to `fee_address`
- utxo value >= `min_charge` + `current_fundraised_amount`
- `current_fundraised_amount` >= `fundraise_target`
- `completion_script` withdrawal script is executed
- `auth_token` from current input is burnt

3. ContributorWithdrawal

- Either one of below conditions
- `deadline` + `expiry_buffer` is passed
- `current_fundraised_amount` <= `fundraise_target`
- There is only 1 input with `auth_token` from current address, and 1 output with `auth_token` and to current_address
- The lovelace unlocking from `crowdfund_address` equal exactly the amount that the `share_token` with token name of `completion_script` is burnt

4. RemoveEmptyInstance

- `deadline` is passed
- share token with token name `completion_script` burning in current tx == `current_fundraised_amount`
- `auth_token` from current input is burnt
- signed by `proposer_key_hash`
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Aiken Crowdfunding

## 1. Auth Token

The token that represent distinct crowdfunding campaign, attaching with distinct `completion_script`

## 2. Shares

The token that represents lovelace contributed to current crowdfunding campaign

## 3. Crowdfund

The validator that handles the crowdfunding campaign

## Param dependency tree

1. First layer

- `auth_token` - `utxo_ref`

2. Second layer

- `shares` - param `auth_token`
- `crowdfund` - param `auth_token`
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Application Setup Documentation

## Setup

The are 2 steps of setting up the applications:

1. Minting `auth_token`, one time minting policy with empty token name with quantity of 1.

- Validation: 1.1

2. Sending the the `auth_token` to `crowdfund`

- With inline datum `CrowdfundDatum` of proposal details, `completion_script` set to be `2_start` script hash from `gov_crowdfund`, `share_token` set to be `2_share` script hash, `crowdfund` set to be `3_crowdfund` script hash and `current_fundraised_amount` set to be the lovelace value of output
- Validation: N/A
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# User Actions Documentation

## Normal Users

1. Contribute fund. Minting `share_token`

- Validation: 2.1, 3.1

2. Withdraw fund. Burning `share_token`

- Validation: 2.2, 3.3

## Proposer

1. Contribute fund. Minting `share_token`

- Validation: 2.1, 3.1

2. Withdraw fund. Burning `share_token`

- Validation: 2.2, 3.3

3. Complete Crowdfund. Sending `auth_token` and `fundraised_amount` to `1_spend` from `gov-aiken`. Proposer is required to add `min_charge` to `auth_token` utxo

- Validation: 3.2, 2.1 `Withdraw`, 2.1 `Mint` from `gov_crowdfund`

4. Remove Crowdfund. Burning the `auth_token`

- Validation: 1.2, 2.2, 3.4
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use aiken/collection/dict
use aiken/collection/list
use cardano/assets.{PolicyId}
use cardano/transaction.{OutputReference, Transaction}
use types.{MintPolarity, RBurn, RMint}

validator auth_token(utxo_ref: OutputReference) {
mint(redeemer: MintPolarity, policy_id: PolicyId, self: Transaction) {
expect [Pair(_asset_name, quantity)] =
self.mint
|> assets.tokens(policy_id)
|> dict.to_pairs()
let Transaction { inputs, .. } = self
when redeemer is {
RMint -> {
let is_output_consumed =
list.any(inputs, fn(input) { input.output_reference == utxo_ref })
is_output_consumed? && quantity == 1
}
RBurn -> quantity == -1
}
}

else(_) {
fail
}
}
Loading