-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add test for AEX-9 FungibleToken contraect
- Loading branch information
Showing
6 changed files
with
332 additions
and
4 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
@compiler >= 4 | ||
|
||
contract CryptoHamster = | ||
datatype event = NewHamster(indexed int, string, hash) | ||
|
||
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// ISC License | ||
// | ||
// Copyright (c) 2017, aeternity developers | ||
// | ||
// Permission to use, copy, modify, and/or distribute this software for any | ||
// purpose with or without fee is hereby granted, provided that the above | ||
// copyright notice and this permission notice appear in all copies. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | ||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
// PERFORMANCE OF THIS SOFTWARE. | ||
|
||
|
||
// THIS IS NOT SECURITY AUDITED | ||
// DO NEVER USE THIS WITHOUT SECURITY AUDIT FIRST | ||
|
||
@compiler >= 4 | ||
|
||
/// @title - Fungible token basic | ||
contract FungibleToken = | ||
|
||
// This defines the state of type record encapsulating the conract's mutable state | ||
record state = | ||
{ owner : address // the smart contract's owner address | ||
, total_supply : int // total token supply | ||
, balances : balances // balances for each account | ||
, meta_info : meta_info } // token meta info (name, symbol, decimals) | ||
|
||
// This is the meta information record type | ||
record meta_info = | ||
{ name : string | ||
, symbol : string | ||
, decimals : int } | ||
|
||
// This is a type alias for the balances map | ||
type balances = map(address, int) | ||
|
||
// Declaration and structure of datatype event | ||
// and events that will be emitted on changes | ||
datatype event = Transfer(address, address, int) | ||
|
||
// List of implemented extensions for the deployed contract | ||
entrypoint aex9_extensions() : list(string) = [] | ||
|
||
// Create a fungible token with | ||
// the following `name` `symbol` and `decimals` | ||
// and set the inital smart contract state | ||
entrypoint init(name: string, decimals : int, symbol : string) = | ||
// If the `name` lenght is less than 1 symbol abort the execution | ||
require(String.length(name) >= 1, "STRING_TOO_SHORT_NAME") | ||
// If the `symbol` length is less than 1 symbol abort the execution | ||
require(String.length(symbol) >= 1, "STRING_TOO_SHORT_SYMBOL") | ||
// If the provided value for `decimals` is negative abort the execution | ||
require_non_negative_value(decimals) | ||
{ owner = Call.caller, | ||
total_supply = 21000000000000000000000000, | ||
balances = {[Call.caller] = 21000000000000000000000000}, | ||
meta_info = { name = name, symbol = symbol, decimals = decimals } } | ||
|
||
// Get the token meta info | ||
entrypoint meta_info() : meta_info = | ||
state.meta_info | ||
|
||
// Get the token total supply | ||
entrypoint total_supply() : int = | ||
state.total_supply | ||
|
||
// Get the token owner address | ||
entrypoint owner() : address = | ||
state.owner | ||
|
||
// Get the balances state | ||
entrypoint balances() : balances = | ||
state.balances | ||
|
||
// Get balance for address of `owner` | ||
// returns option(int) | ||
// If the `owner` address haven't had any token balance | ||
// in this smart contract the return value is None | ||
// Otherwise Some(int) is returned with the current balance | ||
entrypoint balance(owner: address) : option(int) = | ||
Map.lookup(owner, state.balances) | ||
|
||
/// Transfer the balance of `value` from `Call.caller` to `to_account` account | ||
stateful entrypoint transfer(to_account: address, value: int) = | ||
internal_transfer(Call.caller, to_account, value) | ||
|
||
// INTERNAL FUNCTIONS | ||
|
||
function require_owner() = | ||
require(Call.caller == state.owner, "ONLY_OWNER_CALL_ALLOWED") | ||
|
||
function require_non_negative_value(value : int) = | ||
require(value >= 0, "NON_NEGATIVE_VALUE_REQUIRED") | ||
|
||
function require_balance(account : address, value : int) = | ||
switch(balance(account)) | ||
Some(balance) => | ||
require(balance >= value, "ACCOUNT_INSUFFICIENT_BALANCE") | ||
None => abort("BALANCE_ACCOUNT_NOT_EXISTENT") | ||
|
||
stateful function internal_transfer(from_account: address, to_account: address, value: int) = | ||
require_non_negative_value(value) | ||
require_balance(from_account, value) | ||
put(state{ balances[from_account] @ b = b - value }) | ||
put(state{ balances[to_account = 0] @ b = b + value }) | ||
Chain.event(Transfer(from_account, to_account, value)) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
@compiler >= 4 | ||
|
||
contract FungibleTokenInterface = | ||
record meta_info = | ||
{ name : string | ||
, symbol : string | ||
, decimals : int } | ||
|
||
datatype event = | ||
Transfer(address, address, int) | ||
|
||
entrypoint aex9_extensions : () => list(string) | ||
entrypoint meta_info : () => meta_info | ||
entrypoint total_supply : () => int | ||
entrypoint owner : () => address | ||
entrypoint balances : () => map(address, int) | ||
entrypoint balance : (address) => option(int) | ||
entrypoint transfer : (address, int) => unit |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// ISC License | ||
// | ||
// Copyright (c) 2019, kryptokrauts.com | ||
// | ||
// Permission to use, copy, modify, and/or distribute this software for any | ||
// purpose with or without fee is hereby granted, provided that the above | ||
// copyright notice and this permission notice appear in all copies. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE | ||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
// PERFORMANCE OF THIS SOFTWARE. | ||
// | ||
|
||
@compiler >= 4 | ||
|
||
payable contract PaymentSplitter = | ||
record state = | ||
{ owner: address, | ||
recipientConditions: map(address, int), // map of recipients with percentage to receive (value between 1 and 100) | ||
totalAmountSplitted: int } | ||
|
||
// CONTRACT EVENTS | ||
datatype event = AddingInitialRecipients() | ||
| RecipientAdded(indexed address, indexed int) | ||
| AddressUpdated(indexed address, indexed address) | ||
| UpdatingAllRecipients() | ||
| PaymentReceivedAndSplitted(indexed address, indexed int, indexed int) | ||
|
||
// INIT FUNCTION | ||
entrypoint init(recipientConditions: map(address, int)) : state = | ||
require(sumWeights(recipientConditions) == 100, "sum of weights needs to be 100") | ||
Chain.event(AddingInitialRecipients) | ||
{ owner = Call.caller, | ||
recipientConditions = recipientConditions, | ||
totalAmountSplitted = 0} | ||
|
||
// READ ONLY FUNCTIONS | ||
|
||
entrypoint getOwner() : address = | ||
state.owner | ||
|
||
entrypoint getRecipientsCount() : int = | ||
Map.size(state.recipientConditions) | ||
|
||
entrypoint isRecipient(who: address) : bool = | ||
Map.member(who, state.recipientConditions) | ||
|
||
entrypoint getWeight(recipient: address) : int = | ||
Map.lookup_default(recipient, state.recipientConditions, 0) | ||
|
||
entrypoint getTotalAmountSplitted() : int = | ||
state.totalAmountSplitted | ||
|
||
// PAY-AND-SPLIT FUNCTION | ||
stateful payable entrypoint payAndSplit() = | ||
require(Contract.balance > 0, "contract didn't receive any payment") | ||
let recipientConditions: list(address * int) = Map.to_list(state.recipientConditions) | ||
put(state{totalAmountSplitted = Contract.balance + state.totalAmountSplitted}) | ||
split(recipientConditions, Contract.balance) | ||
Chain.event(PaymentReceivedAndSplitted(Call.caller, Call.value, Contract.balance)) | ||
|
||
// STATEFUL FUNCTIONS | ||
|
||
stateful entrypoint transferOwnership(newOwner: address) = | ||
onlyOwner() | ||
put(state{owner = newOwner}) | ||
|
||
stateful entrypoint updateAddress(oldAddress: address, newAddress: address) = | ||
onlyOwnerOrRecipient(oldAddress) | ||
let weight: int = state.recipientConditions[oldAddress] | ||
put(state{recipientConditions @ rc = Map.delete(oldAddress, rc)}) // remove old address | ||
put(state{recipientConditions[newAddress] = weight}) // add new address | ||
Chain.event(AddressUpdated(oldAddress, newAddress)) | ||
|
||
stateful entrypoint updateRecipientConditions(recipients: map(address, int)) = | ||
onlyOwner() | ||
Chain.event(UpdatingAllRecipients) | ||
require(sumWeights(recipients) == 100, "sum of weights needs to be 100") | ||
put(state{recipientConditions = recipients}) | ||
fireRecipientAddedEvents(Map.to_list(state.recipientConditions)) | ||
|
||
// PRIVATE FUNCTIONS | ||
|
||
function onlyOwner() = | ||
require(Call.caller == state.owner, "caller must be the owner") | ||
|
||
function onlyOwnerOrRecipient(recipient: address) = | ||
require(Call.caller == state.owner || Call.caller == recipient, "caller must be the owner or the recipient") | ||
|
||
function sumWeights(recipients: map(address, int)) : int = | ||
let recipientList: list(address * int) = Map.to_list(recipients) | ||
let intList: list(int) = map(pair_second, recipientList) | ||
sum(intList, (x) => x) | ||
|
||
function fireRecipientAddedEvents(recipientConditions: list(address * int)) = | ||
switch(recipientConditions) | ||
[] => () | ||
(recipient, weight) :: l' => | ||
Chain.event(RecipientAdded(recipient, weight)) | ||
|
||
stateful function split(recipientConditions: list(address * int), totalValue: int) = | ||
switch(recipientConditions) | ||
[] => () | ||
(recipient, weight) :: l' => | ||
Chain.spend(recipient, totalValue / 100 * weight) | ||
split(l', totalValue) | ||
|
||
// GENERIC HELPER FUNCTIONS | ||
|
||
function map(f : 'a => 'b, l : list('a)) : list('b) = | ||
switch(l) | ||
[] => [] | ||
e :: l' => f(e) :: map(f, l') | ||
|
||
function foldr(f : (('a, 'b) => 'b), z: 'b, l : list('a)) : 'b = | ||
switch(l) | ||
[] => z | ||
e :: l' => f(e, foldr(f, z, l')) | ||
|
||
function sum(l : list('a), f : 'a => int) : int = | ||
foldr((x, y) => x + y, 0, map(f, l)) | ||
|
||
function pair_second(tuple) = | ||
switch(tuple) | ||
(_, e) => e |