Skip to content
This repository was archived by the owner on May 7, 2025. It is now read-only.
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
9 changes: 9 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Examples

This folder contains examples of Stoffel applications that you can use to get an understanding of Stoffel Lang.

## Demo Applications
- HoneyBadgerSwap: A basic Uniswap-liked automated market maker. We provide two version of this: one in which we want the identities of the traders to be known but not the amounts that they trade and another in which we want both the identities and amounts traded hidden. Similarly, for the liquidity providers. In both scenarios, the assets are public.
- LMSR-based prediction market: Similar to the HoneyBadgerSwap example, except users bet on outcomes instead of trades that are determined by the logarithmic scoring rule by Hansen.
- An orderbook-based exchange: An exchange that uses an orderbook in order to keep track of buys and sell bids from traders and market makers.
- Auction: A basic double auction example based on the original Sugar Beet Auction
84 changes: 84 additions & 0 deletions examples/stoffel/hbs1.stf
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// HBS where we care about the privacy of traders and LPs

program HoneyBadgerSwap {
struct Pool {
assetAID: int,
assetBID: int,
amountA: sint,
amountB: sint,
k: sint
}

struct UserData {
userID: sint,
assets: Map<int, sint>
}

struct LPData {
lpID: sint,
shares: sint,
userData: UserData
}

storage sint totalShares;
storage Pool pool;

storage Map<sint, UserData> userData;
storage Map<sint, LPData> lpData;

fn constructor(assetAID: sint, amountA: sint, assetBID: sint, amountB: sint) {
sint k = amountA * amountB;
pool = Pool {assetAID: assetAID, amountA: amountA, assetBID:assetBID, amountB: amountB, k: k};
}

// Will need to create an unsigned integer type for the language
pub fn Trade(amountA: sint, amountB: sint) -> bool {
// But since we don't have an unsigned type (yet), we need to do a check which is expensive
if amountA < 0 or amount B < 0 {
return false;
}

sint newAmountA = pools[0].amountA - amountA;
sint priceAssetB = pools[0].k / (pools[0].amountA - newAmountA)
sint newAmountB = pools[0].k / priceAssetB

userData[userID].assets[assetA] -= amountA;
userData[userID].assets[assetB] += amountB;

pools[0].amountA = newAmountA;
pools[0].amountB = newAmountB;
}

// Obviously, needs way more input validation. Will be added when we have more details
// about the language for a complete, realistic example.
pub fn AddLiquidity(lpID: sint, amountA: sint, maxAmountB: sint) -> sint {
sint tokenBAmount = (amountA * pool.amountB) / pool.amountA;
sint sharesMinted = (amountA * totalShares) / pool.amountA;

lpData[lpID].shares += sharesMinted;
totalShares += sharesMinted;

lpData[lpID].userData.amountA += amountA;
lpData[lpID].userData.amountB += amountB;

pool.amountA += amountA;
pool.amountB += tokenBAmount;

}

// Again, missing some basic functionality but does what we need to do for basic ideation on syntax
pub fn RemoveLiquidity(lpID: sint, shares: sint) {
sint amountA = (shares * pool.amountA) / totalShares;
sint amountB = (shares * pool.amountB) / totalShares;

lpData[lpID].shares -= shares;
totalShares -= shares;

lpData[lpID].userData.amountA -= amountA;
lpData[lpID].userData.amountB -= amountB;

pool.amountA -= amountA;
pool.amountB -= amountB;
}

}
81 changes: 81 additions & 0 deletions examples/stoffel/hbs2.stf
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// HBS where we only care about trader amounts

program HoneyBadgerSwap {
struct Pool {
assetAID: int,
assetBID: int,
amountA: sint,
amountB: sint
}

struct UserData {
userID: int,
assets: Map<int, sint>
}

struct LPData {
lpID: sint,
shares: sint,
userData: UserData
}

storage Pool pool;

storage Map<int, UserData> userData;
storage Map<int, LPData> lpData;

fn constructor(assetAID: sint, amountA: sint, assetBID: sint, amountB: sint) {
sint k = amountA * amountB;
pool = Pool {assetAID: assetAID, amountA: amountA, assetBID:assetBID, amountB: amountB, k: k};
}

// Will need to create an unsigned integer type for the language
pub fn Trade(userID: int, amountA: sint, amountB: sint) -> bool {
if amountA < 0 or amount B < 0 {
return false;
}

sint newAmountA = pools[0].amountA - amountA;
sint priceAssetB = pools[0].k / (pools[0].amountA - newAmountA)
sint newAmountB = pools[0].k / priceAssetB

userData[userID].assets[assetA] -= amountA;
userData[userID].assets[assetB] += amountB;

pools[0].amountA = newAmountA;
pools[0].amountB = newAmountB;
}


// Obviously, needs way more input validation. Will be added when we have more details
// about the language for a complete, realistic example.
pub fn AddLiquidity(lpID: int, amountA: sint, maxAmountB: sint) -> sint {
sint tokenBAmount = (amountA * pool.amountB) / pool.amountA;
sint sharesMinted = (amountA * totalShares) / pool.amountA;

lpData[lpID].shares += sharesMinted;
totalShares += sharesMinted;

lpData[lpID].userData.amountA += amountA;
lpData[lpID].userData.amountB += amountB;

pool.amountA += amountA;
pool.amountB += tokenBAmount;

}

// Again, missing some basic functionality but does what we need to do for basic ideation on syntax
pub fn RemoveLiquidity(lpID: int, shares: sint) {
sint amountA = (shares * pool.amountA) / totalShares;
sint amountB = (shares * pool.amountB) / totalShares;

lpData[lpID].shares -= shares;
totalShares -= shares;

lpData[lpID].userData.amountA -= amountA;
lpData[lpID].userData.amountB -= amountB;

pool.amountA -= amountA;
pool.amountB -= amountB;
}
}