Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Just a quick sketch of the idea
  • Loading branch information
Quantumplation committed Feb 24, 2024
0 parents commit e0b7d87
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Tests

on:
push:
branches: ["main"]
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: aiken-lang/[email protected]
with:
version: v1.0.24-alpha

- run: aiken fmt --check
- run: aiken check -D
- run: aiken build
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Aiken compilation artifacts
artifacts/
# Aiken's project working directory
build/
# Aiken's default documentation export
docs/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# cosponsor

This is a script that allows a collective co-sponsor protocol for governance actions.

Users can deposit ADA, earmarked to cosponsor a specific governance proposal.
In return, they get a temporary tracking token, which they can burn to retrieve their ADA if the proposal hasn't reached the minimum amount.

These ADA pots can be aggregated into larger pots if needed, or if the proposal amount is reached, can be used to cover the deposit and create the appropriate governance proposal.

When the proposal expires, the deposit goes back to the reward account. From there, they can be withdrawn into a UTXO marked as "Done".

Users can burn *any* of the temporary tokens to withdraw from the done state, so you don't have to worry about where the rewards came from.

Note: this doesn't currently handle yield, but we could mint some kind of "yield" token that was able to claim a portion of the staking rewards earned by the funds while they waited for cosponsorship and create a sort of proto-treasury.
14 changes: 14 additions & 0 deletions aiken.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name = "sundae/cosponsor"
version = "0.0.0"
license = "Apache-2.0"
description = "Aiken contracts for project 'sundae/cosponsor'"

[repository]
user = "sundae"
project = "cosponsor"
platform = "github"

[[dependencies]]
name = "aiken-lang/stdlib"
version = "1.7.0"
source = "github"
94 changes: 94 additions & 0 deletions validators/cosponsor.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
type GovernanceAction {
ParameterChange
HardForkInitiation
TreasuryWithdrawals
NoConfidence
UpdateCommittee
NewConstitution
InfoAction
}

type ProposalProcedure {
deposit: Int,
return_addr: Credential,
governance_action: GovernanceAction,
}

type Datum {
// Before the governance action is created, the only people who can withdraw
// are the people who cosponsored the proposal
Before {
// The proposal this UTXO is destined to cosponsor
cosponsored: ProposalProcedure
},
// After the governance action has returend its deposit, anybody can withdraw
After
}

validator {
// The spend script always defers to the observations, which can either aggregate or publish
fn spend(datum: Datum, redeemer: Redeemer, ctx: ScriptContext) {
expect Spend(output_reference) = ctx.purpose
expect Some(
Input{
output: Output{
address: Address(ScriptCredential(own_script_hash), ..)
}
}
) = transaction.find_input(output_reference)

expect Some(self) = transaction.find_input(output_reference)
expect ScriptCredential(own_script_hash) = self.output.address.payment_credential
list.any(ctx.transaction.observations, fn(sh) { sh == own_script_hash })
}

fn govern(_r: Data, ctx: ScriptContext) {
when ctx.purpose is {
// Make sure we're also in the observers, so we can do it all in one pass
Mint(own_policy_id) -> {
list.any(ctx.transaction.observations, fn(sh) { sh == own_policy_id })
}
// If we're withdrawing from the reward account, create the appropriate UTXO
// For now, assume this produces no yield, and ADA in is ADA out
WithdrawFrom(own_credential) -> {
// Find our own script hash
expect Inline(ScriptCredential(own_script_hash)) = own_credential
list.any(ctx.transaction.observations, fn(sh) { sh == own_script_hash })
}
// Allow many UTXOs to be aggregated into one
// Or for the proposal to be published
Observe(own_index) -> {
// Work out a zero-sum game for the inputs, outputs, minting, withdrawal, and deposits

// Sum up all the ADA grouped by the hash of the governance ID on the inputs
// All of this ADA has to "go somewhere"

// Add in each minted self token using token name as the ID
// If the token is minted, this represents *additional ADA* that must end up in that output
// If the token is burned, this represents *less ADA* that must end up in that output

// Add the withdrawal amount of self to the Done category
// This basically says when we withdrawal, we have to do so into a `Done` datum

// Subtract off the governance deposit amount for each proposal created
// Handle change into the done category if we're over 100k?
// Can we over-deposit?
// This is 100k per gov proposal that's going to disappear, so we let it, so long as we have the inputs to cover it

// Subtract off each output by the hash of the governance ID on the outputs, or Done
// This should now bring us down to zero for each one, since that ADA is going into the correct output

// With one exception; maybe we withdrew from the Done category,
// in which case anything that remains now must be negative or zero, and
// the sum of all non-Done categories must be equal to the Done category
// This corresponds to burning a mixed bag of tokens to withdraw the appropriate ADA
}
// For now, disallow delegation, so we don't earn yield
Publish(delegation) -> {
False
}
// Note allowed to register as a dRep or anything like that
_ -> False
}
}
}

0 comments on commit e0b7d87

Please sign in to comment.