more renaming

This commit is contained in:
2026-06-02 01:58:40 -07:00
parent 270f192f0c
commit 55a56753c1
37 changed files with 12 additions and 6 deletions
+116
View File
@@ -0,0 +1,116 @@
/*
* Aegora Base Contract
*
* Author: Craig Everett <ceverett@tsuriai.jp>
* Copyright: Tsuriai Corporation (2022)
* License: GPLv3
* Version: 1
*
* This is the base contract for the market.
* It is responsible for:
* - A library of valid contracts by type (sales offers, auctions, etc.)
* - Managing the authorized key list of market masters
* - Providing a single known endpoint to discover deployed, active contracts
* - Managing the lifecycle of a contract
*
* Lifecycle of a sales offer:
* 1. The seller calls AegoraBase.post_sale() to create his SalesOffer
* 2. Sale proceeds
* IF it is succesful, the contract calls AegoraBase.close()
* IF it is revoked by seller, the contract calls AegoraBase.close()
* IF it times out or is killed by the maester, one calls AegoraBase.kill()
*
* Calls to this contract can come from one of five sources:
* 1. The Maester (essentially the administrator)
* - init(template : SalesOffer // Posts the initial contract
* maester : address // with a reference to a template
* tsuriai : address)
* - update_template(contract : SalesOffer) // Update the template address
* - epstein(id : bool) // Force a contract to close
* 2. Sellers
* - post_sale(id : int, price : int) // Create a new sale contract clone
* 3. The Aegora site (or anyone really, but mainly useful for the site backend)
* - lookup(id) // Looks up a sale contract's address
* - template() // Looks up the current sales contract template
* 4. A sales contract
* - close(id : int) // A closing sale contract may call to remove itself from the active index
* 5. The Tsuriai master Key
* - update_maester(key : address) // Change the Maester key for operational reasons
*/
@compiler == 7.0.1
payable contract interface SalesOffer =
entrypoint init : (address, address, address, int, address, int, int) => void
payable entrypoint do_a_backflip : () => bool
contract AegoraBase =
record state =
{contracts : map(int, SalesOffer),
template : SalesOffer,
maester : address,
tsuriai : address}
stateful entrypoint init(template : SalesOffer,
maester : address,
tsuriai : address) : state =
{contracts = {},
template = template,
maester = maester,
tsuriai = tsuriai}
public entrypoint template() : SalesOffer =
state.template
public stateful entrypoint update_template(source : SalesOffer) : unit =
require(Call.caller == state.maester, "Nuh, uh uh! You didn't say the magic word!")
put(state{template = source})
public entrypoint lookup(id: int) : SalesOffer =
switch(Map.lookup(id, state.contracts))
Some(target) =>
target
None =>
abort("Bad ID!")
public stateful entrypoint post_sale(agent : address, portion : int, seller : address, id: int, price: int) : SalesOffer =
require(price > 0, "You cannot pay someone to buy things, Mr. Keynes.")
require(!Map.member(id, state.contracts), "People don't think it be like it is, but it do.")
switch(Chain.clone(ref = state.template,
protected = true,
state.tsuriai,
Contract.address,
agent,
portion,
seller,
id,
price))
Some(posted) =>
put(state{contracts = state.contracts{[id] = posted}})
posted
None =>
abort("Bad sale!")
public stateful entrypoint close(id: int) : bool =
switch(Map.lookup(id, state.contracts))
Some(target) =>
require(target.address == Call.caller, "Bad caller")
put(state{contracts = Map.delete(id, state.contracts)})
true
None =>
false
public stateful entrypoint update_maester(key: address) : unit =
require(Call.caller == state.tsuriai, "Nuh, uh uh! You didn't say the magic word!")
put(state{maester = key})
public stateful entrypoint epstein(id: int) : bool =
require(Call.caller == state.maester, "C'mon, man! You only got the husband and son!")
switch(Map.lookup(id, state.contracts))
Some(target) =>
put(state{contracts = Map.delete(id, state.contracts)})
target.do_a_backflip()
true
None =>
false
+235
View File
@@ -0,0 +1,235 @@
/*
* Aegora Sales Offer
*
* Author: Craig Everett <ceverett@tsuriai.jp>
* Copyright: Tsuriai Corporation (2022)
* License: GPLv3
* Version: 1
*
* Sale offers at Aegora (aegora.psychobitch.party) are clones of this contract.
* (The name might be a little weird, but who looks at domain names anymore anyway?)
* When a sale offer is created on the site, the seller signs a contract call to
*
*
* Calls to clones of this contract can come from five sources:
* 1. The base contract (that cloned it in the first place)
* - init(tsuriai : address, // Service fee destination
* aegora : AegoraBase, // Get born
* agent : address, // Deployment agent address
* portion : int, // Deploying agent's fee portion
* seller : address, // Address of the seller
* id : int,
* price : int)
* - do_a_backflip() // Get the opposite of born
* 2. Sellers who posted clones of this contract
* - adjust(price : int) // update price
* - accept() // Sale is DONE
* - refuse() // Cancel a negotation
* - revoke() // Invalidate and disable this offer
* 3. Buyers who are interested in buying through this contract
* - bid(price : int) // Update the bid amout in negotiation
* - hold() // Set HOLD for price negotiation
* - cancel() // Back out of a purchase
* 4. Aegora (the base contract)
* - reassign(tsuriai : address) // Reset Tsuriai's payable address
* 5. The market's network service (or the public)
* - price() // Check current contract price
* - status() // Check contract status
* - agent() // Retrieve the agent's public key (usually the same as the seller)
* - seller() // Retrieve the seller's public key
* - buyer() // Retrieve the buyer's public key
*/
@compiler == 7.0.1
include "Option.aes"
contract interface AegoraBase =
stateful entrypoint close : (int) => bool
payable contract SalesOffer =
record state =
{id : int,
aegora : address,
agent : address,
portion : int,
price : int,
seller : address,
buyer : option(address),
status : status,
tsuriai : address}
datatype status = OPEN | NEGO | HOLD | DONE
// Seller Interface
stateful entrypoint init(tsuriai : address,
aegora : address,
agent : address,
portion : int,
seller : address,
id : int,
price : int) : state =
{id = id,
aegora = aegora,
agent = Call.origin,
portion = portion,
price = price,
seller = seller,
buyer = None,
status = OPEN,
tsuriai = tsuriai}
public stateful entrypoint adjust(price : int) : unit =
require(state.status != DONE, "HiLlArY wUz HeRe.")
require(Call.caller == state.seller, "Nacho shop!")
require(price > 0, "You can't pay people to buy things, Mr. Keynes.")
switch(state.buyer)
Some(buyer) =>
if(Contract.balance > price)
Chain.spend(buyer, Contract.balance - price)
true
else
false
None =>
dead_claim()
put(state{price = price})
public stateful entrypoint accept() : bool =
require(state.status == NEGO, "Sale is not under negotiation.")
require(Call.caller == state.seller, "Nacho shop!")
require(Contract.balance >= state.price, "Insufficient funds!")
let buyer = Option.force(state.buyer)
if(Contract.balance > state.price)
Chain.spend(buyer, Contract.balance - state.price)
Chain.spend(state.tsuriai, calc_fee())
if(state.portion > 0)
Chain.spend(state.agent, (Contract.balance / state.portion))
Chain.spend(state.seller, Contract.balance)
put(state{status = DONE})
Address.to_contract(state.aegora).close(state.id)
public stateful entrypoint refuse() : unit =
require(state.status == NEGO || state.status == HOLD, "Sale is not under negotiation.")
require(Call.caller == state.seller, "Nacho shop!")
refund()
put(state{buyer = None})
put(state{status = OPEN})
public stateful entrypoint revoke() : bool =
require(state.status != DONE, "HiLlArY wUz HeRe.")
require(Call.caller == state.seller, "Nacho shop!")
switch(state.status)
OPEN => dead_claim()
NEGO => refund()
HOLD => refund()
put(state{status = DONE})
Address.to_contract(state.aegora).close(state.id)
// Buyer Interface
public stateful payable entrypoint bid(amount: int) : unit =
require(state.status != DONE, "HiLlArY wUz HeRe.")
require(amount >= state.price, "Stop being poor.")
switch(state.status)
OPEN =>
require(Call.value >= state.price, "Stop being poor.")
put(state{status = NEGO})
put(state{buyer = Some(Call.caller)})
NEGO =>
switch(state.buyer)
Some(buyer) =>
require(Call.caller == buyer, "Nacho bid.")
require(Contract.balance >= state.price, "Stop being poor.")
if(Contract.balance > amount)
Chain.spend(buyer, Contract.balance - amount)
HOLD =>
switch(state.buyer)
Some(buyer) =>
require(Call.caller == buyer, "Nacho bid.")
require(Contract.balance >= state.price, "Stop being poor.")
if(Contract.balance > amount)
Chain.spend(buyer, Contract.balance - amount)
put(state{status = NEGO})
public stateful entrypoint hold() : unit =
require(state.status == NEGO, "Sale is not in negotiation")
switch(state.buyer)
Some(buyer) =>
require(Call.caller == buyer, "Nacho bid!")
put(state{status = HOLD})
None =>
abort("Nacho bid!")
public stateful entrypoint cancel() : unit =
require(state.status == NEGO || state.status == HOLD, "Wrong status")
switch(state.buyer)
Some(buyer) =>
require(Call.caller == buyer, "Nacho bid!")
Chain.spend(state.tsuriai, calc_fee())
put(state{buyer = None})
put(state{status = OPEN})
Chain.spend(buyer, Contract.balance)
None =>
abort("Nacho bid!")
// Aegora Interface
public stateful entrypoint reassign(tsuriai : address) : unit =
require(Call.caller == state.aegora || Call.origin == state.tsuriai, "Knock it off, stinky")
put(state{tsuriai = tsuriai})
public stateful entrypoint sweep_the_table() : bool =
require(state.status == DONE, "Hillary has not yet arrived.")
require(Call.caller == state.tsuriai, "Nope.")
dead_claim()
public stateful entrypoint do_a_backflip() : bool =
require(Call.caller == state.aegora, "Too late, Nathan.")
put(state{status = DONE})
dead_claim()
// Service/Public Network Interface
public entrypoint price() : int =
state.price
public entrypoint status() : string =
switch(state.status)
OPEN => "open"
NEGO => "nego"
HOLD => "hold"
DONE => "done"
public entrypoint agent() : address =
state.agent
public entrypoint seller() : address =
state.seller
public entrypoint buyer() : address =
require(state.status != OPEN, "No buyer!")
Option.force(state.buyer)
// Utilities
function calc_fee() : int =
Contract.balance / 50
private stateful function refund() : bool =
if(Contract.balance > 0)
switch(state.buyer)
Some(buyer) =>
Chain.spend(buyer, Contract.balance)
true
None =>
false
else
false
private stateful function dead_claim() : bool =
if(Contract.balance > 0)
Chain.spend(state.tsuriai, Contract.balance)
true
else
false
+354
View File
@@ -0,0 +1,354 @@
include "List.aes"
include "Pair.aes"
namespace Miner =
type package_code = string
record package = {
daily_cap : int,
price : int}
record aggregated_package = {
daily_cap : int,
count : int}
record worker = {
daily_cap : int,
can_withdraw_payout : bool,
packages : map(package_code, aggregated_package),
joined_pool_tmst : int}
record transfer_packs =
{
worker : address,
packages_to_move : list(string * int),
new_address : address
}
datatype approvable_action = Transfer(transfer_packs)
function new_package(price : int, cap : int) : package =
{daily_cap = cap,
price = price}
function claim(ps : list(package_code * (package * int)), joined_tmst : int) : worker =
let daily_cap = daily_cap_from_packs_list(ps)
let packs : map(package_code, aggregated_package) =
List.foldl(
(accum, t) =>
let pack_id = Pair.fst(t)
let (pack, cnt) = Pair.snd(t)
let val =
switch(Map.lookup(pack_id, accum))
None => {daily_cap = pack.daily_cap, count = cnt}
Some(v) => v{count = v.count + cnt}
accum{[pack_id] = val},
{},
ps)
{daily_cap = daily_cap,
can_withdraw_payout = false,
packages = packs,
joined_pool_tmst = joined_tmst}
function split_packages(w : worker, split : transfer_packs) : worker * worker =
let (packages_left, packages_collected) =
List.foldl(
(accum, p) =>
let accum_left = Pair.fst(accum)
let accum_collected = Pair.snd(accum)
let code = Pair.fst(p)
let count = Pair.snd(p)
switch(Map.lookup(code, accum_left))
None => abort("Does not own enough packages")
Some(owned_packs) =>
let left_packs = owned_packs.count - count
require(left_packs > -1, "Does not own enough packages")
(accum_left{[code] = owned_packs{count = left_packs}}, (code, owned_packs{count = count}) :: accum_collected),
(w.packages, []),
split.packages_to_move)
let daily_cap_delta = List.sum(List.map((t) => Pair.snd(t).daily_cap * Pair.snd(t).count, packages_collected))
let new_w = {daily_cap = daily_cap_delta,
can_withdraw_payout = false,
packages = Map.from_list(packages_collected),
joined_pool_tmst = Chain.block_height}
require(Map.size(new_w.packages) == List.length(packages_collected), "Do not split counts of the same package code")
(w{daily_cap = w.daily_cap - daily_cap_delta, packages = packages_left}, new_w)
function merge_workers(w1 : worker, w2: worker) =
let packages =
List.foldl(
(accum, t) =>
let code = Pair.fst(t)
let aggr_pack = Pair.snd(t)
let updated_pack =
switch(Map.lookup(code, accum))
None => aggr_pack
Some(p) => p{count = p.count + aggr_pack.count}
accum{[code] = updated_pack},
w1.packages,
Map.to_list(w2.packages))
// if one of them is allowed to withdraw, so is the resulting new account
let oldest_tmst =
switch(w1.joined_pool_tmst < w2.joined_pool_tmst)
true => w1.joined_pool_tmst
false => w2.joined_pool_tmst
let can_withdraw_payout = w1.can_withdraw_payout || w2.can_withdraw_payout
let daily_cap = daily_cap_from_packages(packages)
{daily_cap = daily_cap,
can_withdraw_payout = can_withdraw_payout,
packages = packages,
joined_pool_tmst = oldest_tmst}
function daily_cap_from_packs_list(ps : list(package_code * (package * int))) =
List.sum(List.map((t) => Pair.fst(Pair.snd(t)).daily_cap * Pair.snd(Pair.snd(t)), ps))
function daily_cap_from_packages(ps : map(package_code, aggregated_package)) =
List.sum(List.map((t) => Pair.snd(t).daily_cap * Pair.snd(t).count, Map.to_list(ps)))
contract interface Data =
stateful entrypoint set_pool : (address) => unit
stateful entrypoint add : (address, Miner.worker) => unit
stateful entrypoint remove : (address) => unit
payable stateful entrypoint give_rewards : (list(address * int)) => unit
entrypoint balance : (address) => int
entrypoint assert_is_payable : (address) => unit
stateful entrypoint payout : () => unit
stateful entrypoint payout_without_payable_check : (address) => unit
entrypoint all_balances : () => list(address * int)
entrypoint all_daily_caps : () => list(address * int)
entrypoint all : () => list(address)
entrypoint all_detailed : () => map(address, Miner.worker)
entrypoint member : (address) => bool
entrypoint get : (address) => Miner.worker
stateful entrypoint rename : (address, address) => unit
stateful entrypoint make_payable : (address) => unit
stateful entrypoint make_non_payable : (address) => unit
stateful entrypoint split_packages : (Miner.transfer_packs) => unit
entrypoint all_balances_and_daily_caps : () => list(address * int * int)
contract interface Pool =
entrypoint leader : () => address
stateful entrypoint enroll : (address, Miner.worker) => unit
entrypoint member : (address) => bool
stateful entrypoint remove : (address) => unit
entrypoint get : (address) => Miner.worker
stateful entrypoint set_locked : (bool) => unit
stateful entrypoint set_leader : (address) => unit
entrypoint can_be_destroyed : () => bool
entrypoint info : () => address * string * address * string * string * string * string * list(string)
stateful entrypoint make_payable : (address) => unit
stateful entrypoint make_non_payable : (address) => unit
entrypoint assert_worker_is_payable : (address) => unit
stateful entrypoint force_payout : (address) => unit
stateful entrypoint change_worker_address : (address, address) => unit
entrypoint balance : (address) => int
stateful entrypoint set_data_ct : (Data) => unit
stateful entrypoint move_data_and_coins_to_new_pool : (Pool) => Data
payable entrypoint receive_coins : () => unit
stateful entrypoint evacuate_coins : (int, address) => unit
stateful entrypoint split_packages : (Miner.transfer_packs) => unit
include "Set.aes"
include "List.aes"
include "Pair.aes"
main contract PoolInstance:Pool =
datatype pool_status = OPEN | LOCKED | MIGRATED
datatype event
= Enroll(address)
| Remove(address)
record state =
{
status : pool_status,
leader : address,
main_contract : address,
connect_addresses : Set.set(string), // IP addresses and ports
leader_name : string,
leader_url: string,
leader_avatar_url : string,
leader_description : string,
data_ct : Data
}
entrypoint init(main_contract : address, leader : address, data_ct : Data) =
{status = OPEN,
leader = leader,
main_contract = main_contract,
connect_addresses = Set.new(),
leader_name = "",
leader_url = "",
leader_avatar_url = "",
leader_description = "",
data_ct = data_ct}
entrypoint status() =
switch(state.status)
OPEN => "open"
LOCKED => "locked"
MIGRATED => "migrated"
entrypoint info() =
(Contract.address, status(), state.leader, state.leader_name, state.leader_url, state.leader_avatar_url, state.leader_description, Set.to_list(state.connect_addresses))
entrypoint data_contract() =
state.data_ct
entrypoint main_contract() =
state.main_contract
entrypoint can_be_destroyed() : bool =
(empty() && state.status == LOCKED && Contract.balance == 0) || state.status == MIGRATED
entrypoint leader() =
state.leader
entrypoint miners() =
state.data_ct.all()
entrypoint miners_detailed() =
state.data_ct.all_detailed()
entrypoint miner_balances() : list(address * int) =
state.data_ct.all_balances()
entrypoint miner_daily_caps() : list(address * int) =
state.data_ct.all_daily_caps()
entrypoint miner_balances_and_caps() : list(address * int * int) =
state.data_ct.all_balances_and_daily_caps()
entrypoint empty() : bool =
List.is_empty(miners())
stateful entrypoint enroll(worker_address : address, worker : Miner.worker) =
assert_caller_is_main_contract()
require(state.status == OPEN, "Pool is locked, can not join it")
Chain.event(Enroll(worker_address))
add_worker(worker_address, worker)
entrypoint member(worker_address : address) : bool =
state.data_ct.member(worker_address)
/* deletes a worker from the pool if present. Currently the accumulated coins remain in
pool. */
stateful entrypoint remove(worker_address : address) =
assert_caller_is_main_contract()
Chain.event(Remove(worker_address))
state.data_ct.remove(worker_address)
entrypoint get(worker_address : address) =
state.data_ct.get(worker_address)
// this can overwrite a MIGRATED state
stateful entrypoint set_locked(val : bool) =
assert_caller_is_main_contract()
let s =
switch(val)
true => LOCKED
false => OPEN
put(state{status = s})
stateful entrypoint set_leader(new_leader : address) =
assert_caller_is_main_contract()
put(state{leader = new_leader})
stateful entrypoint add_connect_address(conn_address : string) =
assert_leader()
put(state{connect_addresses = Set.insert(conn_address, state.connect_addresses)})
stateful entrypoint rm_connect_address(conn_address : string) =
assert_leader()
put(state{connect_addresses = Set.delete(conn_address, state.connect_addresses)})
stateful entrypoint set_name(name : string) =
assert_leader()
put(state{leader_name = name})
stateful entrypoint set_url(url : string) =
assert_leader()
put(state{leader_url = url})
stateful entrypoint set_avatar_url(avatar_url : string) =
assert_leader()
put(state{leader_avatar_url = avatar_url})
stateful entrypoint set_description(description : string) =
assert_leader()
put(state{leader_description = description})
/* NB: does not take into account one's daily limits! */
stateful entrypoint simply_reward_work(amounts : list(address * int), _ : string) =
assert_leader()
let total_reward = List.sum(List.map((t) => Pair.snd(t), amounts))
require(Contract.balance >= total_reward, "Not enough GAJU for that reward")
state.data_ct.give_rewards(amounts, value = total_reward)
payable entrypoint receive_coins() =
()
// for Eureka
entrypoint balance(addr : address) =
state.data_ct.balance(addr)
entrypoint daily_cap(addr : address) =
let worker = get(addr)
worker.daily_cap
stateful entrypoint payout() : unit =
state.data_ct.payout()
stateful entrypoint force_payout(worker_addr : address) =
assert_caller_is_main_contract()
state.data_ct.payout_without_payable_check(worker_addr)
stateful entrypoint change_worker_address(old_addr : address, new_addr : address) =
assert_caller_is_main_contract()
state.data_ct.rename(old_addr, new_addr)
stateful entrypoint evacuate_coins(amount : int, safeheaven : address) =
assert_caller_is_main_contract()
Chain.spend(safeheaven, amount)
stateful entrypoint make_payable(worker_address : address) =
assert_caller_is_main_contract()
state.data_ct.make_payable(worker_address)
stateful entrypoint make_non_payable(worker_address : address) =
assert_caller_is_main_contract()
state.data_ct.make_non_payable(worker_address)
stateful entrypoint set_data_ct(data_ct : Data) =
assert_caller_is_main_contract()
put(state{data_ct = data_ct})
stateful entrypoint move_data_and_coins_to_new_pool(new_pool : Pool) =
assert_caller_is_main_contract()
state.data_ct.set_pool(new_pool.address)
new_pool.receive_coins(value = Contract.balance)
put(state{status = MIGRATED})
state.data_ct
entrypoint assert_worker_is_payable(worker_address : address) =
state.data_ct.assert_is_payable(worker_address)
stateful entrypoint split_packages(split : Miner.transfer_packs) =
assert_caller_is_main_contract()
state.data_ct.split_packages(split)
// private functions
function assert_caller_is_main_contract() =
require(Call.caller == state.main_contract, "Call it through the main pool contract")
function assert_leader() =
require(Call.origin == state.leader, "Must be called by the leader")
stateful function add_worker(worker_address, worker) =
state.data_ct.add(worker_address, worker)
+145
View File
@@ -0,0 +1,145 @@
/**
* Example gym subscription contract
*
* Copyright (C) 2025, QPQ AG. All Rights Reserved.
*
* Owner can
* - run "tick" to collect monthly fees -> spent to owner
* - unsubscribe anyone
*
* Anyone can
* - subscribe for a period of N months (debit system - all money paid up front)
* - extend their subscription for K months
* - cancel their subscription and withdraw any future money
*
* Owner must issue new contract if he wants to change monthly fee; otherwise
* data structure is too fucking complicated.
*/
include "List.aes"
payable contract Gym =
type pucks = int
type n_months = int
record state = {owner : address,
members : map(address, n_months),
monthly_fee : pucks}
// SFP accessors
entrypoint
get_state : () => state
get_state() = state
stateful entrypoint
put_state : state => unit
put_state(s) = put(s)
entrypoint
is_member : address => bool
is_member(whomst) = Map.member(whomst, state.members)
entrypoint
owner : () => address
owner() = state.owner
entrypoint
members : () => map(address, pucks)
members() = state.members
entrypoint
monthly_fee : () => pucks
monthly_fee() = state.monthly_fee
// actual things
entrypoint
init : (pucks) => state
init(monthly_rate) =
require(monthly_rate >= 0, "monthly rate must be non-negative")
{owner = Call.caller,
members = {},
monthly_fee = monthly_rate}
//------------------------------------------------
// OWNER ENTRYPOINTS: tick/ban
//------------------------------------------------
stateful entrypoint
tick : () => unit
tick() | Call.caller != state.owner =
abort("you are not allowed to do ticks!")
tick() =
// collect fees
// 1 monthly charge per member
let total_charge = state.monthly_fee * Map.size(state.members)
Chain.spend(state.owner, total_charge)
// update members list (clean out everyone with just 1 month left)
let old_members_list : list(address * n_months) = Map.to_list(state.members)
let new_members_list : list(address * n_months) = List.foldl(deduct_month, [], old_members_list)
let new_members : map(address, n_months) = Map.from_list(new_members_list)
let new_state : state = state{members = new_members}
put(new_state)
function
deduct_month : (list(address*n_months), address*n_months) => list(address*n_months)
// n>1 months left -> subtract a month but keep in membership list
deduct_month(acc, (patron, months_left)) | months_left > 1 =
(patron, months_left-1) :: acc
// only 1 month left -> remove from membership list
deduct_month(acc, (patron, 1)) =
acc
stateful entrypoint
ban : (address) => unit
ban(_) | Call.caller != state.owner =
abort("you are not allowed to ban people!")
ban(patron) =
refund(patron)
//------------------------------------------------
// PUBLIC ENTRYPOINTS: subscribe/cancel
//------------------------------------------------
payable stateful entrypoint
subscribe : (n_months) => unit
subscribe(n) | n < 1 =
abort("must subscribe for at least 1 month")
subscribe(n) | Call.value < n*state.monthly_fee =
abort("not enough money to subscribe for that many months!")
subscribe(n) =
let charge: pucks = n * state.monthly_fee
// call will be successful
// refund caller extra money
let extra_money: pucks = Call.value - charge
Chain.spend(Call.caller, extra_money)
// update membership
let old_months : n_months = Map.lookup_default(Call.caller, state.members, 0)
let new_months : n_months = old_months + n
let new_members : map(address, n_months) = state.members{[Call.caller] = new_months}
let new_state : state = state{members = new_members}
put(new_state)
stateful entrypoint
cancel : () => unit
cancel() =
refund(Call.caller)
//------------------------------------------------
// INTERNAL: refund people
//------------------------------------------------
stateful function
refund : (address) => unit
refund(patron) =
let patron_months : n_months =
switch (Map.lookup(patron, state.members))
None => abort("already not a member!")
Some(remaining_months) => remaining_months
let patron_balance : pucks = patron_months * state.monthly_fee
// update membership
let new_members : map(address, n_months) = Map.delete(patron, state.members)
let new_state : state = state{members = new_members}
put(new_state)
// refund balance to patron
Chain.spend(patron, patron_balance)
+10
View File
@@ -0,0 +1,10 @@
// Hello World Contract
// Copyright (c) 2025 QPQ AG
contract Hello =
type state = unit
entrypoint init(): state =
()
entrypoint hello(): string =
"hello, world"
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_ABC'x'
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_ABC0DEF
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_AB0I'x'bar
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_AB0xDEF
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_ABClet
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_foolbar
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_ABC'foo
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ct_fooObar
()
+4
View File
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
let _ = #deadbeef
42
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
let _ = '\xab'
42
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
let _ = '\x{ff}'
42
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : string =
"hello
world"
@@ -0,0 +1,4 @@
contract Test =
type state = unit
entrypoint init() : state =
() /*
@@ -0,0 +1,3 @@
contract Test =
entrypoint main() : int =
1 + /* unclosed
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
/* outer /* inner */ outer still open
42
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
/* unclosed block comment
42
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : string =
"hello\
world"
@@ -0,0 +1,5 @@
contract Test =
type state = unit
entrypoint init() : state =
let _ = 'é'
()
@@ -0,0 +1,4 @@
contract Test =
entrypoint main() : int =
let c = 'Ā'
Char.to_int(c)
@@ -0,0 +1,3 @@
contract Test =
entrypoint greet() : string =
"∑∆∏"
@@ -0,0 +1,3 @@
contract Col2Byte =
entrypoint greet() : string =
"Héllo" + " world"
@@ -0,0 +1,3 @@
contract Col3Byte =
entrypoint price() : string =
"Price: €10" + " incl."
@@ -0,0 +1,3 @@
contract Col4Byte =
entrypoint celebrate() : string =
"Hello 🎉" + " world"
@@ -0,0 +1,3 @@
contract ColBcom =
entrypoint compute(x : int) : int =
/* résultat */ x + 1
@@ -0,0 +1,3 @@
contract ColMulti =
entrypoint unicode_str() : string =
"Ünïcödé" + " ok"
+8
View File
@@ -0,0 +1,8 @@
main contract Foo =
type state = unit
entrypoint init(): state =
()
entrypoint foo'(): unit = ()
entrypoint foo'bar'(): unit = ()
+5
View File
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = ak_ABC123
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = sg_foo_bar
()
@@ -0,0 +1,5 @@
contract Foo =
type state = unit
entrypoint init(): state =
let _ = sg_GHI
()
+6
View File
@@ -0,0 +1,6 @@
main contract Foo =
type state = unit
type foo = bar // id
type foo = Bar.baz // qid
type foo = 'bar // tvar
type foo = () => bar