- return to IOTA Rebased Useful Links
FreeBeer Contract Development
The concept is for an onchain contract where you can hit the 'free beer' button and be awarded some IOTA. You incur some gas costs but the free iota exceed that. At the same time your address is written to the chain and everybody is limited from asking for more for about the next hour, or to have more than 3 free beers per address. There is also the ability for anybody to top up the supply of free beer.
[1] Basic steps in building an IOTA Rebased Contract
The contract itself is listed below. In outline though there is a freebeer.move file within a sources folder. At top level there is a Move.toml file like this:
[package]
name = "freebeer"
edition = "2024.beta"
[dependencies]
Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "develop" }
[addresses]
freebeer = "0x0"
Typically the next step is as follows. This creates a build folder.
% iota move build
Next this has to be published to the IOTA Rebased blockchain (Testnet). Here is the CLI call, using a gas CoinId from the live CLI account:
iota client publish \
--gas-budget 60000000 \
--gas 0x034010c356652f1f28e41ef45831aa983f920cbdb799c974fa69ced276454922
[2] IOTA Rebased Testnet Locations.
Transaction Digest: HyNUbYZWoHK1e35dbWmCeBVtC3w3PHpNEo7qoe7bwmvS
PackageID: 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556
Created by account: 0xc196e256a58a1ea07e2cb27887090c3cf6a1ad1ec189c8a40575e7cde6c3dc4a
Created at the time of contract publication:
UpgradeCap 0xf0153c6276ab99a59e0e7d25d19c04099b9dd3dd8641e3aba02147519b5321c2
[3] Initializing the 'freebeer' contract
This is the call used and the resulting Transaction:
Transaction Digest: 6KRyX9KyoqZFywRcc4DYvjwC3nuktAekmpWx1iapkin3
Object changed: GlobalConfig 0x9d8cc06a57a89e63afc48805dde64c8bdd7aee9211f002566e25325b3206b95c
(which now has values now: initialized: false, last_beer_time: 0, cooldown_period: 3600000)
Object changed: AdminCap 0x0d5dc60b506b47bf32fd78f5c6ea755ab1316309f92664cf4028d211ede365b1
(just has this unique Id given)
% iota client call \
--gas-budget 10000000 \
--gas 0x034010c356652f1f28e41ef45831aa983f920cbdb799c974fa69ced276454922 \
--function initialize \
--module beer \
--package 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556
[4] Calling the SETUP function
This is the call used and the resulting Transaction. Note that the two arguments are the Object Ids of two objects given UIDs in the previous step. that is: --args "ADMIN_CAP_ID" "GLOBAL_CONFIG_ID"
Transaction Digest: BcNMCwGTdgSnNmtWRQaj6TBpvT7Go6EV78nSHdGXSoUm
Object created: Registry 0xfe8bae921d2abbb42773c91110bbacb2b353c2d41a1e3b8f9cafa7fcd3956ea9
(which has an empty table with fields 'id' and 'size')
Object created: Treasury 0xba1cb7687c673df83d6a0364ecd76e632b3a3fffedba6b5596d72cfdddb203da
(which has value: beer_funds => 0)
Object changed: GlobalConfig 0x9d8cc06a57a89e63afc48805dde64c8bdd7aee9211f002566e25325b3206b95c
(which now has values now: initialized: true, last_beer_time: 0, cooldown_period: 3600000)
iota client call \
--gas-budget 10000000 \
--gas 0x034010c356652f1f28e41ef45831aa983f920cbdb799c974fa69ced276454922 \
--function setup \
--module beer \
--package 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556 \
--args "0x0d5dc60b506b47bf32fd78f5c6ea755ab1316309f92664cf4028d211ede365b1" "0x9d8cc06a57a89e63afc48805dde64c8bdd7aee9211f002566e25325b3206b95c"
[5] Adding Beer to the Treasury
This is the call used to call the addbeer function using a coinId with 7.298 IOTA value, and the resulting Transaction.
Transaction Digest: 4SG6wEnq6EV9WWrs6bRACQQF8Y1iuf2KejDLX5nxs8yc
Object changed: Treasury 0xba1cb7687c673df83d6a0364ecd76e632b3a3fffedba6b5596d72cfdddb203da
The beer_funds variable now contains 7.298 Iota, the Registry remains empty with no members.
iota client call \
--gas-budget 10000000 \
--gas 0x034010c356652f1f28e41ef45831aa983f920cbdb799c974fa69ced276454922 \
--function addbeer \
--module beer \
--package 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556\
--args 0x36a63f51e2e34f4dd3286b6297c63e7a914fbc20e61a88f4ad671dce5f3d13b7 "0xba1cb7687c673df83d6a0364ecd76e632b3a3fffedba6b5596d72cfdddb203da"
[6] Checking the 'free_beer_status'
This was the call used, with parameters GlobalConfig and Treasury.
Transaction Digest: 4notAgjEkY7yZtBQpPvU5ra3MuucvZw5uTwbGBLnqaCa
iota client call \
--gas-budget 10000000 \
--gas 0x034010c356652f1f28e41ef45831aa983f920cbdb799c974fa69ced276454922 \
--function get_beer_status \
--module beer \
--package 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556 \
--args 0xba1cb7687c673df83d6a0364ecd76e632b3a3fffedba6b5596d72cfdddb203da 0x9d8cc06a57a89e63afc48805dde64c8bdd7aee9211f002566e25325b3206b95c
A parsed JSON was returned.
next_available │ 1735067784714 │
│ │ ├─────────────────┼───────────────┤
│ │ │ status │ 0 │
│ │ ├─────────────────┼───────────────┤
│ │ │ treasury_amount │ 7298019600
[7] Getting your free beer from the Treasury
Need to swop CLI address to test the contract. The following may be useful (with your own addresses substitutued):
% iota client addresses
% iota client switch --address 0xc196e256a58a1ea07e2cb27887090c3cf6a1ad1ec189c8a40575e7cde6c3dc4a
or % iota client switch --address 0xda5f052f5d98d7d6bdbeaff2df40acd1ff7e7e48368de591870d542e2e8eaf48
iota client balance --with-coins
The call below is used to 'get beer' using account 0xda5..
Transaction Digest: DZyA8NAYRCyBPbLJKVc4Xr6Lj6fTCxgTKevqbcDa89Xx
iota client call \
--gas-budget 10000000 \
--gas 0x3050ec46526a091e2cd2c4c6488ecb212863744e0b796b5ea155b11695196fde \
--function getbeer \
--module beer \
--package 0x80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556 \
--args 0xba1cb7687c673df83d6a0364ecd76e632b3a3fffedba6b5596d72cfdddb203da 0xfe8bae921d2abbb42773c91110bbacb2b353c2d41a1e3b8f9cafa7fcd3956ea9 0x9d8cc06a57a89e63afc48805dde64c8bdd7aee9211f002566e25325b3206b95c
Did it work. Well, first gas was paid using 0x3050... Then the transfers showed:
- a coin value 7000000 nano was created owned by the account 0xda5.. (the free beer)
CoinId: 0x17e5ba0530e2019d63d296ec5890c6031559a26bffa31c8bd4c3c11bd4744249
The GlobalConfig was updated.
The Treasury value has decreased by 7000000 nano
A field with the address 0xda5... and value 1 has been created, owned by 0xe452... (see below)
FieldID: 0x706b3cdf6777759317d2ee5ea0aae1e624d85d0f363bffcf52303587ba3b7d87
The Registry has an entry for 0xe4526...(see Field above)
[8] Summary
The 'free beer' contract seems to be working, so time to build a Dapp to make interface generally available and easier to use. This is just draft 1 of course as issues remain including improving security.
[9] Complete contract code
module freebeer::beer {
use iota::object::{Self, UID};
use iota::coin::{Self, Coin};
use iota::tx_context::{Self, TxContext};
use iota::event;
use iota::transfer;
use iota::balance::{Self, Balance};
use iota::table::{Self, Table}; // Add Table import
// ======== Capability and Config ========
public struct AdminCap has key, store {
id: UID
}
public struct GlobalConfig has key {
id: UID,
initialized: bool,
last_beer_time: u64,
cooldown_period: u64
}
// ======== Constants ========
const BEER_AMOUNT: u64 = 7000000; // 7,000,000 nanos
const LOW_FUNDS_THRESHOLD: u64 = 21000000; // 3 beers worth
const BASE_COOLDOWN: u64 = 3600000; // 1 hour in milliseconds
const COOLDOWN_VARIANCE: u64 = 300000; // 5 minutes variance
const MAX_BEERS_PER_ADDRESS: u64 = 3; // Maximum beers per address
// ======== Status Constants ========
const STATUS_AVAILABLE: u8 = 0;
const STATUS_COOLING: u8 = 1;
const STATUS_OUT_OF_BEER: u8 = 2;
// ======== Error Codes ========
const ALREADY_INITIALIZED: u64 = 1;
const MAX_BEERS_RECEIVED: u64 = 2;
const INSUFFICIENT_FUNDS: u64 = 3;
const COOLING_DOWN: u64 = 4;
// ======== Events ========
public struct InitializeEvent has copy, drop {
admin: address,
timestamp: u64
}
public struct BeerAdded has copy, drop {
amount: u64,
from: address,
new_total: u64
}
public struct TreasuryLow has copy, drop {
remaining: u64,
timestamp: u64
}
public struct BeerReceived has copy, drop {
recipient: address,
amount: u64,
beers_remaining: u64, // Added field for beers remaining for this address
timestamp: u64,
remaining_treasury: u64,
next_available: u64
}
public struct BeerAttemptRejected has copy, drop {
recipient: address,
reason: vector,
timestamp: u64,
next_available: u64
}
public struct BeerStatus has copy, drop {
status: u8,
next_available: u64,
treasury_amount: u64
}
// ======== Storage Structures ========
public struct Registry has key, store {
id: UID,
member_counts: Table // Changed to track count per address
}
public struct Treasury has key, store {
id: UID,
beer_funds: Balance
}
// ======== Initialize System ========
public entry fun initialize(ctx: &mut TxContext) {
transfer::share_object(
GlobalConfig {
id: object::new(ctx),
initialized: false,
last_beer_time: 0,
cooldown_period: BASE_COOLDOWN
}
);
transfer::public_transfer(
AdminCap {
id: object::new(ctx)
},
tx_context::sender(ctx)
);
}
// ======== Setup Beer System ========
public entry fun setup(
_admin_cap: &AdminCap,
config: &mut GlobalConfig,
ctx: &mut TxContext
) {
assert!(!config.initialized, ALREADY_INITIALIZED);
let registry = Registry {
id: object::new(ctx),
member_counts: table::new(ctx) // Initialize empty table
};
let treasury = Treasury {
id: object::new(ctx),
beer_funds: balance::zero()
};
config.initialized = true;
transfer::share_object(registry);
transfer::share_object(treasury);
event::emit(InitializeEvent {
admin: tx_context::sender(ctx),
timestamp: tx_context::epoch_timestamp_ms(ctx)
});
}
// ======== Add Beer Funds ========
public entry fun addbeer(
coin: Coin,
treasury: &mut Treasury,
ctx: &mut TxContext
) {
let amount = coin::value(&coin);
balance::join(&mut treasury.beer_funds, coin::into_balance(coin));
let new_total = balance::value(&treasury.beer_funds);
event::emit(BeerAdded {
amount,
from: tx_context::sender(ctx),
new_total
});
if (new_total <= LOW_FUNDS_THRESHOLD) {
event::emit(TreasuryLow {
remaining: new_total,
timestamp: tx_context::epoch_timestamp_ms(ctx)
});
};
}
// ======== Check Beer Status ========
public fun check_status(
treasury: &Treasury,
config: &GlobalConfig,
ctx: &TxContext
): u8 {
let current_time = tx_context::epoch_timestamp_ms(ctx);
let treasury_amount = balance::value(&treasury.beer_funds);
if (treasury_amount < BEER_AMOUNT) {
STATUS_OUT_OF_BEER
} else if (current_time - config.last_beer_time < config.cooldown_period) {
STATUS_COOLING
} else {
STATUS_AVAILABLE
}
}
// ======== Get Beer ========
public entry fun getbeer(
treasury: &mut Treasury,
registry: &mut Registry,
config: &mut GlobalConfig,
ctx: &mut TxContext
) {
let recipient = tx_context::sender(ctx);
let current_time = tx_context::epoch_timestamp_ms(ctx);
// Check beer count for recipient
let count = if (table::contains(®istry.member_counts, recipient)) {
*table::borrow(®istry.member_counts, recipient)
} else {
0
};
// Check if recipient has reached limit
if (count >= MAX_BEERS_PER_ADDRESS) {
event::emit(BeerAttemptRejected {
recipient,
reason: b"Maximum number of beers already received",
timestamp: current_time,
next_available: 0
});
abort MAX_BEERS_RECEIVED
};
// Check if cooling down
if (current_time - config.last_beer_time < config.cooldown_period) {
let next_available = config.last_beer_time + config.cooldown_period;
event::emit(BeerAttemptRejected {
recipient,
reason: b"Beer not available yet - cooling down",
timestamp: current_time,
next_available
});
abort COOLING_DOWN
};
// Check if we have enough funds
let treasury_balance = balance::value(&treasury.beer_funds);
if (treasury_balance < BEER_AMOUNT) {
event::emit(BeerAttemptRejected {
recipient,
reason: b"Insufficient funds in treasury",
timestamp: current_time,
next_available: 0
});
abort INSUFFICIENT_FUNDS
};
// Send beer amount
let beer_payment = coin::from_balance(
balance::split(&mut treasury.beer_funds, BEER_AMOUNT),
ctx
);
transfer::public_transfer(beer_payment, recipient);
// Update recipient's beer count
if (table::contains(&mut registry.member_counts, recipient)) {
let count = table::borrow_mut(&mut registry.member_counts, recipient);
*count = *count + 1;
} else {
table::add(&mut registry.member_counts, recipient, 1);
};
// Update cooldown with slight randomization
let random_variance = (current_time & 0xFF) * COOLDOWN_VARIANCE / 0xFF;
config.cooldown_period = BASE_COOLDOWN + random_variance;
config.last_beer_time = current_time;
// Calculate next available time
let next_available = current_time + config.cooldown_period;
// Get remaining beers for this address
let beers_remaining = MAX_BEERS_PER_ADDRESS - (count + 1);
// Emit success event
event::emit(BeerReceived {
recipient,
amount: BEER_AMOUNT,
beers_remaining,
timestamp: current_time,
remaining_treasury: balance::value(&treasury.beer_funds),
next_available
});
// Emit status for dApp
event::emit(BeerStatus {
status: STATUS_COOLING,
next_available,
treasury_amount: balance::value(&treasury.beer_funds)
});
// Check if funds are low after serving
if (balance::value(&treasury.beer_funds) <= LOW_FUNDS_THRESHOLD) {
event::emit(TreasuryLow {
remaining: balance::value(&treasury.beer_funds),
timestamp: current_time
});
};
}
// ======== Public View Function for dApp ========
public entry fun get_beer_status(
treasury: &Treasury,
config: &GlobalConfig,
ctx: &mut TxContext
) {
let current_time = tx_context::epoch_timestamp_ms(ctx);
let next_available = if (current_time < config.last_beer_time + config.cooldown_period) {
config.last_beer_time + config.cooldown_period
} else {
current_time
};
event::emit(BeerStatus {
status: check_status(treasury, config, ctx),
next_available,
treasury_amount: balance::value(&treasury.beer_funds)
});
}
}
[10] Complete contract MOVE Bytecode
// Move bytecode v6
module 80da07146a4060d7195f81bd25655816f55a465218f4ba7c5d355e10e8759556.beer {
use 0000000000000000000000000000000000000000000000000000000000000002::balance;
use 0000000000000000000000000000000000000000000000000000000000000002::coin;
use 0000000000000000000000000000000000000000000000000000000000000002::event;
use 0000000000000000000000000000000000000000000000000000000000000002::iota;
use 0000000000000000000000000000000000000000000000000000000000000002::object;
use 0000000000000000000000000000000000000000000000000000000000000002::table;
use 0000000000000000000000000000000000000000000000000000000000000002::transfer;
use 0000000000000000000000000000000000000000000000000000000000000002::tx_context;
struct AdminCap has store, key {
id: UID
}
struct GlobalConfig has key {
id: UID,
initialized: bool,
last_beer_time: u64,
cooldown_period: u64
}
struct InitializeEvent has copy, drop {
admin: address,
timestamp: u64
}
struct BeerAdded has copy, drop {
amount: u64,
from: address,
new_total: u64
}
struct TreasuryLow has copy, drop {
remaining: u64,
timestamp: u64
}
struct BeerReceived has copy, drop {
recipient: address,
amount: u64,
beers_remaining: u64,
timestamp: u64,
remaining_treasury: u64,
next_available: u64
}
struct BeerAttemptRejected has copy, drop {
recipient: address,
reason: vector,
timestamp: u64,
next_available: u64
}
struct BeerStatus has copy, drop {
status: u8,
next_available: u64,
treasury_amount: u64
}
struct Registry has store, key {
id: UID,
member_counts: Table
}
struct Treasury has store, key {
id: UID,
beer_funds: Balance
}
entry public initialize(Arg0: &mut TxContext) {
B0:
0: CopyLoc[0](Arg0: &mut TxContext)
1: Call object::new(&mut TxContext): UID
2: LdFalse
3: LdU64(0)
4: LdConst[2](u64: 3600..)
5: Pack[1](GlobalConfig)
6: Call transfer::share_object(GlobalConfig)
7: CopyLoc[0](Arg0: &mut TxContext)
8: Call object::new(&mut TxContext): UID
9: Pack[0](AdminCap)
10: MoveLoc[0](Arg0: &mut TxContext)
11: FreezeRef
12: Call tx_context::sender(&TxContext): address
13: Call transfer::public_transfer(AdminCap, address)
14: Ret
}
entry public setup(Arg0: &AdminCap, Arg1: &mut GlobalConfig, Arg2: &mut TxContext) {
B0:
0: CopyLoc[1](Arg1: &mut GlobalConfig)
1: ImmBorrowField[0](GlobalConfig.initialized: bool)
2: ReadRef
3: Not
4: BrFalse(6)
B1:
5: Branch(12)
B2:
6: MoveLoc[2](Arg2: &mut TxContext)
7: Pop
8: MoveLoc[1](Arg1: &mut GlobalConfig)
9: Pop
10: LdConst[8](u64: 1)
11: Abort
B3:
12: CopyLoc[2](Arg2: &mut TxContext)
13: Call object::new(&mut TxContext): UID
14: CopyLoc[2](Arg2: &mut TxContext)
15: Call table::new(&mut TxContext): Table
16: Pack[8](Registry)
17: StLoc[3](loc0: Registry)
18: CopyLoc[2](Arg2: &mut TxContext)
19: Call object::new(&mut TxContext): UID
20: Call balance::zero(): Balance
21: Pack[9](Treasury)
22: StLoc[4](loc1: Treasury)
23: LdTrue
24: MoveLoc[1](Arg1: &mut GlobalConfig)
25: MutBorrowField[0](GlobalConfig.initialized: bool)
26: WriteRef
27: MoveLoc[3](loc0: Registry)
28: Call transfer::share_object(Registry)
29: MoveLoc[4](loc1: Treasury)
30: Call transfer::share_object(Treasury)
31: CopyLoc[2](Arg2: &mut TxContext)
32: FreezeRef
33: Call tx_context::sender(&TxContext): address
34: MoveLoc[2](Arg2: &mut TxContext)
35: FreezeRef
36: Call tx_context::epoch_timestamp_ms(&TxContext): u64
37: Pack[2](InitializeEvent)
38: Call event::emit(InitializeEvent)
39: Ret
}
entry public addbeer(Arg0: Coin, Arg1: &mut Treasury, Arg2: &mut TxContext) {
B0:
0: ImmBorrowLoc[0](Arg0: Coin)
1: Call coin::value(&Coin): u64
2: StLoc[3](loc0: u64)
3: CopyLoc[1](Arg1: &mut Treasury)
4: MutBorrowField[1](Treasury.beer_funds: Balance)
5: MoveLoc[0](Arg0: Coin)
6: Call coin::into_balance(Coin): Balance
7: Call balance::join(&mut Balance, Balance): u64
8: Pop
9: MoveLoc[1](Arg1: &mut Treasury)
10: ImmBorrowField[1](Treasury.beer_funds: Balance)
11: Call balance::value(&Balance): u64
12: StLoc[4](loc1: u64)
13: MoveLoc[3](loc0: u64)
14: CopyLoc[2](Arg2: &mut TxContext)
15: FreezeRef
16: Call tx_context::sender(&TxContext): address
17: CopyLoc[4](loc1: u64)
18: Pack[3](BeerAdded)
19: Call event::emit(BeerAdded)
20: CopyLoc[4](loc1: u64)
21: LdConst[1](u64: 2100..)
22: Le
23: BrFalse(31)
B1:
24: MoveLoc[4](loc1: u64)
25: MoveLoc[2](Arg2: &mut TxContext)
26: FreezeRef
27: Call tx_context::epoch_timestamp_ms(&TxContext): u64
28: Pack[4](TreasuryLow)
29: Call event::emit(TreasuryLow)
30: Branch(33)
B2:
31: MoveLoc[2](Arg2: &mut TxContext)
32: Pop
B3:
33: Ret
}
public check_status(Arg0: &Treasury, Arg1: &GlobalConfig, Arg2: &TxContext): u8 {
B0:
0: MoveLoc[2](Arg2: &TxContext)
1: Call tx_context::epoch_timestamp_ms(&TxContext): u64
2: StLoc[5](loc2: u64)
3: MoveLoc[0](Arg0: &Treasury)
4: ImmBorrowField[1](Treasury.beer_funds: Balance)
5: Call balance::value(&Balance): u64
6: LdConst[0](u64: 7000..)
7: Lt
8: BrFalse(14)
B1:
9: MoveLoc[1](Arg1: &GlobalConfig)
10: Pop
11: LdConst[7](u8: 2)
12: StLoc[4](loc1: u8)
13: Branch(31)
B2:
14: MoveLoc[5](loc2: u64)
15: CopyLoc[1](Arg1: &GlobalConfig)
16: ImmBorrowField[2](GlobalConfig.last_beer_time: u64)
17: ReadRef
18: Sub
19: MoveLoc[1](Arg1: &GlobalConfig)
20: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
21: ReadRef
22: Lt
23: BrFalse(27)
B3:
24: LdConst[6](u8: 1)
25: StLoc[3](loc0: u8)
26: Branch(29)
B4:
27: LdConst[5](u8: 0)
28: StLoc[3](loc0: u8)
B5:
29: MoveLoc[3](loc0: u8)
30: StLoc[4](loc1: u8)
B6:
31: MoveLoc[4](loc1: u8)
32: Ret
}
entry public getbeer(Arg0: &mut Treasury, Arg1: &mut Registry, Arg2: &mut GlobalConfig, Arg3: &mut TxContext) {
L0: loc4: u64
L1: loc5: u64
L2: loc6: u64
L3: loc7: u64
L4: loc8: address
B0:
0: CopyLoc[3](Arg3: &mut TxContext)
1: FreezeRef
2: Call tx_context::sender(&TxContext): address
3: StLoc[12](loc8: address)
4: CopyLoc[3](Arg3: &mut TxContext)
5: FreezeRef
6: Call tx_context::epoch_timestamp_ms(&TxContext): u64
7: StLoc[8](loc4: u64)
8: CopyLoc[1](Arg1: &mut Registry)
9: ImmBorrowField[4](Registry.member_counts: Table)
10: CopyLoc[12](loc8: address)
11: Call table::contains(&Table, address): bool
12: BrFalse(20)
B1:
13: CopyLoc[1](Arg1: &mut Registry)
14: ImmBorrowField[4](Registry.member_counts: Table)
15: CopyLoc[12](loc8: address)
16: Call table::borrow(&Table, address): &u64
17: ReadRef
18: StLoc[4](loc0: u64)
19: Branch(22)
B2:
20: LdU64(0)
21: StLoc[4](loc0: u64)
B3:
22: MoveLoc[4](loc0: u64)
23: StLoc[6](loc2: u64)
24: CopyLoc[6](loc2: u64)
25: LdConst[4](u64: 3)
26: Ge
27: BrFalse(44)
B4:
28: MoveLoc[0](Arg0: &mut Treasury)
29: Pop
30: MoveLoc[1](Arg1: &mut Registry)
31: Pop
32: MoveLoc[3](Arg3: &mut TxContext)
33: Pop
34: MoveLoc[2](Arg2: &mut GlobalConfig)
35: Pop
36: MoveLoc[12](loc8: address)
37: LdConst[11](vector: "Max..)
38: MoveLoc[8](loc4: u64)
39: LdU64(0)
40: Pack[6](BeerAttemptRejected)
41: Call event::emit(BeerAttemptRejected)
42: LdConst[9](u64: 2)
43: Abort
B5:
44: CopyLoc[8](loc4: u64)
45: CopyLoc[2](Arg2: &mut GlobalConfig)
46: ImmBorrowField[2](GlobalConfig.last_beer_time: u64)
47: ReadRef
48: Sub
49: CopyLoc[2](Arg2: &mut GlobalConfig)
50: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
51: ReadRef
52: Lt
53: BrFalse(76)
B6:
54: MoveLoc[0](Arg0: &mut Treasury)
55: Pop
56: MoveLoc[1](Arg1: &mut Registry)
57: Pop
58: MoveLoc[3](Arg3: &mut TxContext)
59: Pop
60: CopyLoc[2](Arg2: &mut GlobalConfig)
61: ImmBorrowField[2](GlobalConfig.last_beer_time: u64)
62: ReadRef
63: MoveLoc[2](Arg2: &mut GlobalConfig)
64: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
65: ReadRef
66: Add
67: StLoc[9](loc5: u64)
68: MoveLoc[12](loc8: address)
69: LdConst[12](vector: "Bee..)
70: MoveLoc[8](loc4: u64)
71: MoveLoc[9](loc5: u64)
72: Pack[6](BeerAttemptRejected)
73: Call event::emit(BeerAttemptRejected)
74: LdConst[10](u64: 4)
75: Abort
B7:
76: CopyLoc[0](Arg0: &mut Treasury)
77: ImmBorrowField[1](Treasury.beer_funds: Balance)
78: Call balance::value(&Balance): u64
79: LdConst[0](u64: 7000..)
80: Lt
81: BrFalse(98)
B8:
82: MoveLoc[0](Arg0: &mut Treasury)
83: Pop
84: MoveLoc[1](Arg1: &mut Registry)
85: Pop
86: MoveLoc[3](Arg3: &mut TxContext)
87: Pop
88: MoveLoc[2](Arg2: &mut GlobalConfig)
89: Pop
90: MoveLoc[12](loc8: address)
91: LdConst[13](vector: "Ins..)
92: MoveLoc[8](loc4: u64)
93: LdU64(0)
94: Pack[6](BeerAttemptRejected)
95: Call event::emit(BeerAttemptRejected)
96: LdConst[4](u64: 3)
97: Abort
B9:
98: CopyLoc[0](Arg0: &mut Treasury)
99: MutBorrowField[1](Treasury.beer_funds: Balance)
100: LdConst[0](u64: 7000..)
101: Call balance::split(&mut Balance, u64): Balance
102: MoveLoc[3](Arg3: &mut TxContext)
103: Call coin::from_balance(Balance, &mut TxContext): Coin
104: CopyLoc[12](loc8: address)
105: Call transfer::public_transfer>(Coin, address)
106: CopyLoc[1](Arg1: &mut Registry)
107: MutBorrowField[4](Registry.member_counts: Table)
108: FreezeRef
109: CopyLoc[12](loc8: address)
110: Call table::contains(&Table, address): bool
111: BrFalse(124)
B10:
112: MoveLoc[1](Arg1: &mut Registry)
113: MutBorrowField[4](Registry.member_counts: Table)
114: CopyLoc[12](loc8: address)
115: Call table::borrow_mut(&mut Table, address): &mut u64
116: StLoc[7](loc3: &mut u64)
117: CopyLoc[7](loc3: &mut u64)
118: ReadRef
119: LdU64(1)
120: Add
121: MoveLoc[7](loc3: &mut u64)
122: WriteRef
123: Branch(129)
B11:
124: MoveLoc[1](Arg1: &mut Registry)
125: MutBorrowField[4](Registry.member_counts: Table)
126: CopyLoc[12](loc8: address)
127: LdU64(1)
128: Call table::add(&mut Table, address, u64)
B12:
129: CopyLoc[8](loc4: u64)
130: LdU64(255)
131: BitAnd
132: LdConst[3](u64: 300000)
133: Mul
134: LdU64(255)
135: Div
136: StLoc[11](loc7: u64)
137: LdConst[2](u64: 3600..)
138: MoveLoc[11](loc7: u64)
139: Add
140: CopyLoc[2](Arg2: &mut GlobalConfig)
141: MutBorrowField[3](GlobalConfig.cooldown_period: u64)
142: WriteRef
143: CopyLoc[8](loc4: u64)
144: CopyLoc[2](Arg2: &mut GlobalConfig)
145: MutBorrowField[2](GlobalConfig.last_beer_time: u64)
146: WriteRef
147: CopyLoc[8](loc4: u64)
148: MoveLoc[2](Arg2: &mut GlobalConfig)
149: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
150: ReadRef
151: Add
152: StLoc[10](loc6: u64)
153: LdConst[4](u64: 3)
154: MoveLoc[6](loc2: u64)
155: LdU64(1)
156: Add
157: Sub
158: StLoc[5](loc1: u64)
159: MoveLoc[12](loc8: address)
160: LdConst[0](u64: 7000..)
161: MoveLoc[5](loc1: u64)
162: CopyLoc[8](loc4: u64)
163: CopyLoc[0](Arg0: &mut Treasury)
164: ImmBorrowField[1](Treasury.beer_funds: Balance)
165: Call balance::value(&Balance): u64
166: CopyLoc[10](loc6: u64)
167: Pack[5](BeerReceived)
168: Call event::emit(BeerReceived)
169: LdConst[6](u8: 1)
170: MoveLoc[10](loc6: u64)
171: CopyLoc[0](Arg0: &mut Treasury)
172: ImmBorrowField[1](Treasury.beer_funds: Balance)
173: Call balance::value(&Balance): u64
174: Pack[7](BeerStatus)
175: Call event::emit(BeerStatus)
176: CopyLoc[0](Arg0: &mut Treasury)
177: ImmBorrowField[1](Treasury.beer_funds: Balance)
178: Call balance::value(&Balance): u64
179: LdConst[1](u64: 2100..)
180: Le
181: BrFalse(189)
B13:
182: MoveLoc[0](Arg0: &mut Treasury)
183: ImmBorrowField[1](Treasury.beer_funds: Balance)
184: Call balance::value(&Balance): u64
185: MoveLoc[8](loc4: u64)
186: Pack[4](TreasuryLow)
187: Call event::emit(TreasuryLow)
188: Branch(191)
B14:
189: MoveLoc[0](Arg0: &mut Treasury)
190: Pop
B15:
191: Ret
}
entry public get_beer_status(Arg0: &Treasury, Arg1: &GlobalConfig, Arg2: &mut TxContext) {
B0:
0: CopyLoc[2](Arg2: &mut TxContext)
1: FreezeRef
2: Call tx_context::epoch_timestamp_ms(&TxContext): u64
3: StLoc[4](loc1: u64)
4: CopyLoc[4](loc1: u64)
5: CopyLoc[1](Arg1: &GlobalConfig)
6: ImmBorrowField[2](GlobalConfig.last_beer_time: u64)
7: ReadRef
8: CopyLoc[1](Arg1: &GlobalConfig)
9: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
10: ReadRef
11: Add
12: Lt
13: BrFalse(23)
B1:
14: CopyLoc[1](Arg1: &GlobalConfig)
15: ImmBorrowField[2](GlobalConfig.last_beer_time: u64)
16: ReadRef
17: CopyLoc[1](Arg1: &GlobalConfig)
18: ImmBorrowField[3](GlobalConfig.cooldown_period: u64)
19: ReadRef
20: Add
21: StLoc[3](loc0: u64)
22: Branch(25)
B2:
23: MoveLoc[4](loc1: u64)
24: StLoc[3](loc0: u64)
B3:
25: MoveLoc[3](loc0: u64)
26: StLoc[5](loc2: u64)
27: CopyLoc[0](Arg0: &Treasury)
28: MoveLoc[1](Arg1: &GlobalConfig)
29: MoveLoc[2](Arg2: &mut TxContext)
30: FreezeRef
31: Call check_status(&Treasury, &GlobalConfig, &TxContext): u8
32: MoveLoc[5](loc2: u64)
33: MoveLoc[0](Arg0: &Treasury)
34: ImmBorrowField[1](Treasury.beer_funds: Balance)
35: Call balance::value(&Balance): u64
36: Pack[7](BeerStatus)
37: Call event::emit(BeerStatus)
38: Ret
}
Constants [
0 => u64: 7000000
1 => u64: 21000000
2 => u64: 3600000
3 => u64: 300000
4 => u64: 3
5 => u8: 0
6 => u8: 1
7 => u8: 2
8 => u64: 1
9 => u64: 2
10 => u64: 4
11 => vector: "Maximum number of beers already received" // interpreted as UTF8 string
12 => vector: "Beer not available yet - cooling down" // interpreted as UTF8 string
13 => vector: "Insufficient funds in treasury" // interpreted as UTF8 string
]
}