Last active
March 5, 2024 17:43
-
-
Save andytudhope/5728a5acb9cb288ec6f61f4daa09d14c to your computer and use it in GitHub Desktop.
A memecoin for ao which illustrates a different way of using the token.lua blueprint with hopefully more prosocial outcomes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- import the necessaries | |
local json = require('json') | |
CRED = "Sa0iBLPNyJQrwpTTG-tWLQU-1QeUAJA73DdxGGiKoJc" | |
if not Balances then Balances = { [ao.id] = 0 } end | |
if not CredSent then CredSent = { [ao.id] = 0 } end | |
if Name ~= 'aoWifHat' then Name = 'aoWifHat' end | |
if Ticker ~= 'WHAT' then Ticker = 'WHAT' end | |
if Denomination ~= 1000 then Denomination = 1000 end | |
if not Logo then Logo = 'OVJ2EyD3dKFctzANd0KX_PCgg8IQvk0zYqkWIj-aeaU' end | |
-- This function may seem strange at first, but it's worth thinking about. | |
-- We want a community meme coin, which is used to vote on what appears in an iframe | |
-- on a "community" web property. Therefore, it is likely that we want to | |
-- incentivise lots of small holders, with roughly equal amounts, such that we | |
-- have a greater chance of creating a vibrant ecosystem of regular voters, | |
-- rather than a stale one which tends towards a few whales over time. | |
-- How do we achieve such a thing? | |
-- We mint 1WHAT:1CRED for the first CRED you send in, and then implement | |
-- a linear decay function such that you get 0 WHAT for the 10000th CRED you send. | |
-- This actively disincentivises people sending in lots of CRED in order to get | |
-- more power over what appears on the community website, and allows us to go | |
-- along with the rather simple schemes in the voting + staking blueprints without | |
-- causing too many power imbalances (hopefully). | |
local function calcCoin(quantity, process) | |
local maxCred = 10000 * 1000 | |
local whatToMint | |
if CredSent[process] == nil then | |
-- this is the first time this process has sent CRED | |
CredSent[process] = quantity | |
if quantity <= maxCred then | |
-- Linear decay formula: starts with 1 at first CRED and linearly decreases to 0 at 10000th CRED | |
whatToMint = (maxCred - CredSent[process] + 1000) / maxCred | |
else | |
-- they've sent more than 10000 CRED immediately. | |
-- Mint the max WHAT (which is 5000 (1/2b x h) and send it to them) | |
whatToMint = 5000 * 1000 | |
end | |
else | |
local whatMinted = (maxCred - CredSent[process]) / maxCred | |
local totalWhat = (maxCred - CredSent[process] + quantity) / maxCred | |
whatToMint = totalWhat - whatMinted | |
end | |
-- Ensure the returned value is a string and does not exceed 1000 units (for the first token) | |
return tostring(math.floor(whatToMint)) | |
end | |
-- Handler for incoming messages | |
Handlers.add('info', Handlers.utils.hasMatchingTag('Action', 'Info'), function(m) | |
ao.send( | |
{ Target = m.From, Tags = { Name = Name, Ticker = Ticker, Logo = Logo, Denomination = tostring(Denomination) } }) | |
end) | |
-- Handlers for token balances and info | |
Handlers.add('balance', Handlers.utils.hasMatchingTag('Action', 'Balance'), function(m) | |
local bal = '0' | |
-- If not Target is provided, then return the Senders balance | |
if (m.Tags.Target and Balances[m.Tags.Target]) then | |
bal = tostring(Balances[m.Tags.Target]) | |
elseif Balances[m.From] then | |
bal = tostring(Balances[m.From]) | |
end | |
ao.send({ | |
Target = m.From, | |
Tags = { Target = m.From, Balance = bal, Ticker = Ticker, Data = json.encode(tonumber(bal)) } | |
}) | |
end) | |
Handlers.add('balances', Handlers.utils.hasMatchingTag('Action', 'Balances'), | |
function(m) ao.send({ Target = m.From, Data = json.encode(Balances) }) end) | |
-- Handler for transfers | |
Handlers.add('transfer', Handlers.utils.hasMatchingTag('Action', 'Transfer'), function(m) | |
assert(type(m.Tags.Recipient) == 'string', 'Recipient is required!') | |
assert(type(m.Tags.Quantity) == 'string', 'Quantity is required!') | |
if not Balances[m.From] then Balances[m.From] = 0 end | |
if not Balances[m.Tags.Recipient] then Balances[m.Tags.Recipient] = 0 end | |
local qty = tonumber(m.Tags.Quantity) | |
assert(type(qty) == 'number', 'qty must be number') | |
if Balances[m.From] >= qty then | |
Balances[m.From] = Balances[m.From] - qty | |
Balances[m.Tags.Recipient] = Balances[m.Tags.Recipient] + qty | |
--[[ | |
Only Send the notifications to the Sender and Recipient | |
if the Cast tag is not set on the Transfer message | |
]] -- | |
if not m.Tags.Cast then | |
-- Send Debit-Notice to the Sender | |
ao.send({ | |
Target = m.From, | |
Tags = { Action = 'Debit-Notice', Recipient = m.Tags.Recipient, Quantity = tostring(qty) } | |
}) | |
-- Send Credit-Notice to the Recipient | |
ao.send({ | |
Target = m.Tags.Recipient, | |
Tags = { Action = 'Credit-Notice', Sender = m.From, Quantity = tostring(qty) } | |
}) | |
end | |
else | |
ao.send({ | |
Target = m.Tags.From, | |
Tags = { Action = 'Transfer-Error', ['Message-Id'] = m.Id, Error = 'Insufficient Balance!' } | |
}) | |
end | |
end) | |
-- Handler for processes that want to buy WHAT | |
Handlers.add( | |
"buy", | |
function(m) | |
return | |
m.Tags.Action == "Credit-Notice" and | |
m.From == CRED and | |
m.Tags.Quantity >= "1000" and "continue" -- 1 CRED == 1000 CRED Units | |
end, | |
function(m) | |
local memes = calcCoin(tonumber(m.Tags.Quantity), m.Tags.Sender) | |
-- rather that mint a massive balance using the token blueprint, we just mint here as needed. | |
-- again, this is in service of a provably fair community system. | |
Balances[ao.id] = tonumber(memes) | |
ao.send({Target = ao.id, Action = "Transfer", Recipient = m.Tags.Sender, Quantity = memes }) | |
end | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment