Fan fiction lore courtesy of Bri Wylde
Caution
This contract has not been audited nor has it been thoroughly tested, it is – as the kids say – a meme coin. Take this into consideration.
KALE
is a Stellar asset that can only be created by mining it through this contract. Only one unit (1_0000000
) of the asset can be farmed every minute.
Network | TESTNET |
MAINNET |
---|---|---|
Contract | CDBG4XY2T5RRPH7HKGZIWMR2MFPLC6RJ453ITXQGNQXG6LNVL4375MRJ |
CDL74RF5BLYR2YBLCCI7F5FB6TPSCLKEJUBSD2RSVWZ4YHF3VMFAIGWA |
Asset | KALE:GDLN4SLKCSXKBPABPSAH2TOQVCCU6LJAMFMGA6NNMDR6HMB5DQZEFCZH |
KALE:GBDVX4VELCDSQ54KQJYTNHXAHFLBCA77ZY2USQBM4CSHTTV7DME7KALE |
SAC | CDQKZ76ZS7LYDOZ2E7OG5LUJEWDDUNYBVYRJTBJK6645DZBNJWA7DXCR |
CB23WRDQWGSP6YPMY4UV5C4OW5CBTXKYN3XEATG7KJEZCXMJBYEHOUOV |
- This is not a winner takes all mining contract. The block reward is distributed to all working farmers based off contributions both to a staking step and a working step.
- The block reward amount will vary up from a
BLOCK_REWARD
base to include any unclaimedKALE
staked by farmers who were unable to to callwork
for the block. - The block reward is calculated by the minute but blocks close every
BLOCK_INTERVAL
seconds. This likely will be greater than a minute to ensure an appropriate balance between blockchain load and hash difficulty distribution. Close too quickly and the blockchain could be overwhelmed with requests. Close too slowly and the hash difficulty could be too high for the average CPU miner to participate. - Block rewards must be claimed passively after the next block has its first
plant
invocation. - All storage other than a few protocol items is temporary. This keeps things cheap af but also introduces an interesting "risk" mechanic in that if you're tardy to claim your rewards you might just miss out entirely. Don't let those veggies rot!
In order to successfully farm KALE
into your account you must invoke 3 contract functions:
- Start with the
plant
staking function. - Next input your proof of work by calling the
work
function. - Finally you can harvest your
KALE
by calling theharvest
function.
Let's look at each of these steps in more detail.
Step one of all bountiful harvests is planting. In our case planting is the staking step. In order to both commit your interest in mining a block and to multiply your bounty you must stake some amount of KALE
. Please note that a stake of 0
is permitted and is in fact the only way to get started farming in The KALEpail Project.
The amount you stake will be included in the block reward calculation alongside the prefix zeros you submit in your hash
during the work
step and the number of ledgers you let pass between when you called plant
and work
.
The math is relatively simple however as we don't have floating point numbers in Soroban things end up looking a little intimidating. However the basic idea is there are three variables that affect your share of the block reward: gap
, stake
and zeros
.
gap
is the number of ledgers that have passed between when you calledplant
andwork
. The longer you wait the higher this value will contribute to your share of the block reward. The risk is if you wait too long you might miss the block entirely and thus forfeit your stake.stake
is the amount ofKALE
you've staked. The more you stake the higher this value will contribute to your share of the block reward. Pretty simple. The risk is if you stake too much and then cannot for whatever reason submit a valid hash in thework
step you'll forfeit this stake.zeros
is the number of prefix zeros you were able to generate in yourhash
. The more zeros you can generate the higher this value will contribute to your share of the block reward. The risk is more zeros either takes longer or more hashing power.
In the end these values are all normalized across a common base value and then just added together to arrive at your total contribution to the block which will be used to calculate your share of the block reward during the harvest
step.
The aim of this mathematical algorithm is to try and strike a balance between timing, risk, staking power and hashing power where no one value is too overly preferred against the other. As time progresses I expect we'll need to continue to refine the algorithm in order to find the appropriate balance of power between OG farmers, power users and new players.
To dig more deeply into the math here explore the generate_normalizations()
function.
Once you've successfully staked your claim planted your garden you can move on to the actual mining step. The goal here is to attempt to generate a valid hash with the maximum number of prefix zeros. The more zeros you can generate the more KALE
you'll be able to harvest in the end.
Hashes will be verified via the following function:
fn generate_hash(
env: &Env,
index: &u32,
nonce: &u64,
entropy: &BytesN<32>,
farmer: &Address,
) -> BytesN<32> {
let mut hash_array = [0u8; 76];
let mut farmer_array = [0u8; 32];
let farmer_bytes = farmer.to_xdr(env);
farmer_bytes
.slice(farmer_bytes.len() - 32..)
.copy_into_slice(&mut farmer_array);
hash_array[..4].copy_from_slice(&index.to_be_bytes());
hash_array[4..12].copy_from_slice(&nonce.to_be_bytes());
hash_array[12..44].copy_from_slice(&entropy.to_array());
hash_array[44..].copy_from_slice(&farmer_array);
env.crypto()
.keccak256(&Bytes::from_array(env, &hash_array))
.to_bytes()
}
A couple things to note:
- You can get the
index
value from the instance storageFarmIndex
key. - Entropy is the
hash
value of the previous block. - We only take the last 32 bytes of the
farmer
address. This allows us to keep the hash generation process as small, compact and cheap as possible while still supporting both G- and C-farmer
addresses. (G- addresses are 44 bytes while C- addresses are just 40 when breaking them down to their raw XDR)
I've tried to keep the hash as tight and simple as possible to make it easier and faster to build hashing algorithms without having to fiddle with XDR headers.
Note: you can update your work
submission if you happen to find a hash with more zeros than your previous submission just keep in mind transaction submissions aren't free (the XLM transaction submission fee) so choose your timing wisely. Submit too soon and you might find a larger zero prefix before the block closes. Submit too late and you might miss the block entirely and thus forfeit your stake.
Once you've put in a solid block's work you can finally harvest your KALE
. The harvest
function will calculate your share of the block reward based on your contribution to the block against the total contributions of all other hard working farmers.
The total available reward will be the base BLOCK_REWARD
+ any stake that wasn't reclaimed during a subsequent work
invocation.
You are always guaranteed to receive back at least as much as you staked assuming you were able to submit a valid hash for the block in the work
step.
Keep in mind block's are stored as temporary entries so you either need to act fast to claim your rewards or bump the entry's ttl to keep it from being evicted. Once it's gone, it, your rewards, and your stake are all gone with it.
- Of
plant
,work
andharvest
onlyplant
callsrequire_auth
on thefarmer
argument. This would allow other accounts to callwork
andharvest
on behalf of the farmer. This could be useful in joint mining pools where a service could create a separate contract or service which could collect on a portion ofKALE
or some other asset in exchange for performing thework
andharvest
functions for other farmers. - Write a harvest contract that can harvest multiple blocks at a time. Temporary ttl lasts 24 hrs atm so there’s quite a bit of headroom to bundle blocks into single super claim transactions.
- Build a service that harvests other folks blocks for them (for a fee)
- Build a service that bumps ttl on blocks (for a fee) to ensure there's time to claim rewards.
Want to submit mainnet transactions for free? Use Launchtube! I'll be handing out 100 XLM API tokens to anyone who asks in our Discord channel.
Come chat it up in the KALE
forum discussion on the Stellar Global Discord server.
The KALEpail project wouldn't have been possible without the initial innovation of the FCM project or the subsequent community efforts spearheaded by Frederic 경진 Rezeau.