Skip to content

Instantly share code, notes, and snippets.

@mariano-aguero
Created April 23, 2020 14:31
Show Gist options
  • Save mariano-aguero/db3f6c47c256fecbdd5bc607424ee64d to your computer and use it in GitHub Desktop.
Save mariano-aguero/db3f6c47c256fecbdd5bc607424ee64d to your computer and use it in GitHub Desktop.
Change amount
// This is an implementation of the FA1.2 specification in PascaLIGO
type amountNat is nat;
type account is record
balance : amountNat;
allowances: map(address, amountNat);
end
type action is
| Transfer of (address * address * amountNat)
| Mint of (amountNat)
| Burn of (amountNat)
| Approve of (address * amountNat)
| GetAllowance of (address * address * contract(amountNat))
| GetBalance of (address * contract(amountNat))
| GetTotalSupply of (unit * contract(amountNat))
type contract_storage is record
owner: address;
totalSupply: amountNat;
ledger: big_map(address, account);
end
function isAllowed (const accountFrom : address ; const value : amountNat ; var s : contract_storage) : bool is
begin
var allowed: bool := False;
if sender =/= accountFrom then block {
// Checking if the sender is allowed to spend in name of accountFrom
const src: account = get_force(accountFrom, s.ledger);
const allowanceAmount: amountNat = get_force(sender, src.allowances);
allowed := allowanceAmount >= value;
};
else allowed := True;
end with allowed
// Transfer a specific amount of tokens from accountFrom address to a destination address
// Preconditions:
// The sender address is the account owner or is allowed to spend x in the name of accountFrom
// The accountFrom account has a balance higher than the amount
// Postconditions:
// The balance of accountFrom is decreased by the amount
// The balance of destination is increased by the amount
function transfer (const accountFrom : address ; const destination : address ; const value : amountNat ; var s : contract_storage) : contract_storage is
begin
// If accountFrom = destination transfer is not necessary
if accountFrom = destination then skip;
else block {
// Is sender allowed to spend value in the name of accountFrom
case isAllowed(accountFrom, value, s) of
| False -> failwith ("Sender not allowed to spend token from source")
| True -> skip
end;
// Fetch src account
const src: account = get_force(accountFrom, s.ledger);
// Check that the accountFrom can spend that much
if value > src.balance
then failwith ("Source balance is too low");
else skip;
// Update the accountFrom balance
// Using the abs function to convert int to nat
src.balance := abs(src.balance - value);
s.ledger[accountFrom] := src;
// Fetch dst account or add empty dst account to ledger
var dst: account := record
balance = 0n;
allowances = (map end : map(address, amountNat));
end;
case s.ledger[destination] of
| None -> skip
| Some(n) -> dst := n
end;
// Update the destination balance
dst.balance := dst.balance + value;
// Decrease the allowance amount if necessary
case src.allowances[sender] of
| None -> skip
| Some(dstAllowance) -> src.allowances[sender] := abs(dstAllowance - value) // ensure non negative
end;
s.ledger[accountFrom] := src;
s.ledger[destination] := dst;
}
end with s
// Mint tokens into the owner balance
// Preconditions:
// The sender is the owner of the contract
// Postconditions:
// The minted tokens are added in the balance of the owner
// The totalSupply is increased by the amountNat of minted token
function mint (const value : amountNat ; var s : contract_storage) : contract_storage is
begin
// If the sender is not the owner fail
if sender =/= s.owner then failwith("You must be the owner of the contract to mint tokens");
else block {
var ownerAccount: account := record
balance = 0n;
allowances = (map end : map(address, amountNat));
end;
case s.ledger[s.owner] of
| None -> skip
| Some(n) -> ownerAccount := n
end;
// Update the owner balance
ownerAccount.balance := ownerAccount.balance + value;
s.ledger[s.owner] := ownerAccount;
s.totalSupply := abs(s.totalSupply + 1);
}
end with s
// Burn tokens from the owner balance
// Preconditions:
// The owner have the required balance to burn
// Postconditions:
// The burned tokens are subtracted from the balance of the owner
// The totalSupply is decreased by the amountNat of burned token
function burn (const value : amountNat ; var s : contract_storage) : contract_storage is
begin
// If the sender is not the owner fail
if sender =/= s.owner then failwith("You must be the owner of the contract to burn tokens");
else block {
var ownerAccount: account := record
balance = 0n;
allowances = (map end : map(address, amountNat));
end;
case s.ledger[s.owner] of
| None -> skip
| Some(n) -> ownerAccount := n
end;
// Check that the owner can spend that much
if value > ownerAccount.balance
then failwith ("Owner balance is too low");
else skip;
// Update the owner balance
// Using the abs function to convert int to nat
ownerAccount.balance := abs(ownerAccount.balance - value);
s.ledger[s.owner] := ownerAccount;
s.totalSupply := abs(s.totalSupply - 1);
}
end with s
// Approve an amount to be spent by another address in the name of the sender
// Preconditions:
// The spender account is not the sender account
// Postconditions:
// The allowance of spender in the name of sender is value
function approve (const spender : address ; const value : amountNat ; var s : contract_storage) : contract_storage is
begin
// If sender is the spender approving is not necessary
if sender = spender then skip;
else block {
const src: account = get_force(sender, s.ledger);
src.allowances[spender] := value;
s.ledger[sender] := src; // Not sure if this last step is necessary
}
end with s
// View function that forwards the allowance amountNat of spender in the name of owner to a contract
// Preconditions:
// None
// Postconditions:
// The state is unchanged
function getAllowance (const owner : address ; const spender : address ; const contr : contract(amountNat) ; var s : contract_storage) : list(operation) is
begin
const src: account = get_force(owner, s.ledger);
const destAllowance: amountNat = get_force(spender, src.allowances);
end with list [transaction(destAllowance, 0tz, contr)]
// View function that forwards the balance of source to a contract
// Preconditions:
// None
// Postconditions:
// The state is unchanged
function getBalance (const accountFrom : address ; const contr : contract(amountNat) ; var s : contract_storage) : list(operation) is
begin
const src: account = get_force(accountFrom, s.ledger);
end with list [transaction(src.balance, 0tz, contr)]
// View function that forwards the totalSupply to a contract
// Preconditions:
// None
// Postconditions:
// The state is unchanged
function getTotalSupply (const contr : contract(amountNat) ; var s : contract_storage) : list(operation) is
list [transaction(s.totalSupply, 0tz, contr)]
function main (const p : action ; const s : contract_storage) :
(list(operation) * contract_storage) is
block {
// Reject any transaction that try to transfer token to this contract
if amount =/= 0tz then failwith ("This contract do not accept token");
else skip;
} with case p of
| Transfer(n) -> ((nil : list(operation)), transfer(n.0, n.1, n.2, s))
| Approve(n) -> ((nil : list(operation)), approve(n.0, n.1, s))
| GetAllowance(n) -> (getAllowance(n.0, n.1, n.2, s), s)
| GetBalance(n) -> (getBalance(n.0, n.1, s), s)
| GetTotalSupply(n) -> (getTotalSupply(n.1, s), s)
| Mint(n) -> ((nil : list(operation)), mint(n, s))
| Burn(n) -> ((nil : list(operation)), burn(n, s))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment