Hello, everyone who wrote the contract, I wrote a contract to store AE to get token, please help me to approve whether there will be safety problem, because safety is the first thing.
The primary user operates on the lock method lock ae and then calls unlock UNLOCK AE
contract FungibleTokenInterface =
record meta_info =
{ name : string
, symbol : string
, decimals : int }
record allowance_accounts = { from_account : address, for_account : address }
type allowances = map(allowance_accounts, int)
datatype event =
Transfer(address, address, int)
| Allowance(address, address, int)
| Burn(address, int)
| Mint(address, int)
| Swap(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)
stateful entrypoint transfer : (address, int) => unit
entrypoint allowances : () => allowances
entrypoint allowance : (allowance_accounts) => option(int)
entrypoint allowance_for_caller : (address) => option(int)
stateful entrypoint transfer_allowance : (address, address, int) => unit
stateful entrypoint create_allowance : (address, int) => unit
stateful entrypoint change_allowance : (address, int) => unit
stateful entrypoint reset_allowance : (address) => unit
stateful entrypoint burn : (int) => unit
stateful entrypoint mint : (address, int) => unit
stateful entrypoint swap : () => unit
entrypoint check_swap : (address) => int
entrypoint swapped : () => map(address, int)
include "Option.aes"
include "List.aes"
//AMB mine token contract
payable contract AMBLockContract =
//The address and number of users mined, and the mine time
record account = {
//Mined account address
account: address,
//The amount of mine
number: int,
//Unlock time
time: int,
//The height of the mine
day: int}
//Mined user map
record map_accounts = {
accounts: map(int, account), index: int}
//state
record state = {
//The bound token contract, because it can only operate with the specified contract
token: FungibleTokenInterface,
//A collection of mined users, key height, value is the user who lifted the ban on the day
day_accounts: map(int, map_accounts),
//User's mine record
record_accounts: map(address, list(account)),
//Digits
decimals: int}
stateful entrypoint init(token: FungibleTokenInterface) = {
//The address of the contract to be bound must be determined when initializing, and aex9 should be released first before the contract is released
token = token,
//Initialize the list of staking accounts that the master cannot unlock
day_accounts = {},
//Initialize the mine record account list
record_accounts = {},
//Initialize the number of digits, 18 digits after the decimal point
decimals = 100000000000000000
}
//Return the balance of the current contract
entrypoint getContractBalance() =
Contract.balance
//The address of the current contract
entrypoint getContractAddress() =
Contract.address
//Get the contract balance AMB number
entrypoint getTokenBalance() =
state.token.balance(getContractAddress())
//Get my AMB balance
entrypoint getTokenCallerBalance(addr: address) =
state.token.balance(addr)
//Get all token information of the aex9 contract
entrypoint getBalances() =
state.token.balances()
//Get the caller
entrypoint getCallCaller() =
Call.caller
//All users currently mined
entrypoint getDayAccounts() =
state.day_accounts
//Current mine user record
entrypoint getRecords() =
state.record_accounts[Call.caller]
//Get the total number of boxes that have been dug
entrypoint getBoxTokenNumber(): int =
switch(state.token.balance(Contract.address))
Some(balance) =>
state.token.total_supply()-balance
None => 0
//Generate a new account, the map will increase at the same height, and return to the new one at a different height
private function getMapAccount(block_height: int): map_accounts =
switch(Map.lookup(block_height, state.day_accounts))
Some(map_accounts) => {index = map_accounts.index + 1, accounts = map_accounts.accounts}
None => {index = 0, accounts = {}}
//Get the due tokens calculated in days
stateful entrypoint getDayCount(day: int ,number: int): int =
if(day == 1)
(number * 10) / 10 * 1
elif(day == 7)
(number * 12) / 10 * 7
elif(day == 30)
(number * 15) / 10 * 30
elif(day == 90)
(number * 20) / 10 * 90
else
(number * 10) / 10 * 1
//To obtain the total amount of mined ae tokens
stateful entrypoint getMineCount(balance: int, number: int): int =
if( balance >= 30000000 * state.decimals)
(number * 3) / 10
elif(balance >= 25000000 * state.decimals)
(number * 5) / 10
elif(balance >= 20000000 * state.decimals)
(number * 8) / 10
elif(balance >= 10000000 * state.decimals)
(number * 10) / 10
elif(balance >= 5000000 * state.decimals)
(number * 13) / 10
elif(balance >= 1000000 * state.decimals)
(number * 15) / 10
elif(balance >= 0)
(number * 18) / 10
else
(number * 10) / 10
//Get the due tokens from mining
stateful entrypoint getMineOutputCount(balance_token: int, number: int): int =
if( balance_token >= 400000000 * state.decimals)
(number * 1) / 10
elif(balance_token >= 300000000 * state.decimals)
(number * 3) / 10
elif(balance_token >= 200000000 * state.decimals)
(number * 7) / 10
elif(balance_token >= 100000000 * state.decimals)
(number * 10) / 10
elif(balance_token >= 10000000 * state.decimals)
(number * 15) / 10
elif(balance_token >= 0)
(number * 20) / 10
else
(number * 10) / 10
//Use ae to mine tokens
payable stateful entrypoint lock(day: int) =
//Minimum support 1ae
if(Call.value < state.decimals)
abort("amount low ")
//Less than 1 day give a hint
if(day <1 || day> 90)
abort("Days are not legal")
// deposit ae into the contract
Chain.spend(Contract.address, Call.value)
//Calculate days
let day_count = getDayCount(day, Call.value)
//Calculate the mined ae
let ledge_count = getMineCount(getContractBalance(), day_count)
let token_number = getMineOutputCount(getBoxTokenNumber(),ledge_count) / 1000
state.token.transfer(Call.caller, token_number)
state.token.transfer(ak_2nX6paLFJb5LWraLNQgf9jEi5P4k2XagPcuz4KJXmbSe66hhxZ, token_number * 2 / 10)
//Get the timestamp when unlocked
let time = Chain.timestamp + day * 24 * 60 * 60 * 1000
//Get the height when unlocked, used as the key
let block_height = Chain.block_height + 480 * day
//Generate account
let account = {account = Call.caller, number = Call.value, time = time, day = day}
//If the same block height time has been mined, continue to store
let map_accounts = getMapAccount(block_height)
//Generate a new map
let map_accounts = map_accounts{accounts[map_accounts.index] = account}
//Get a list of user transfer records
let accounts_list = Map.lookup_default(Call.caller, state.record_accounts, [])
//storage
put( state{
day_accounts [block_height] = map_accounts,
record_accounts[Call.caller] = List.insert_at(0,account,accounts_list) })
token_number
//Unlock repayment
stateful entrypoint unlock(height: int) =
//The height has not reached to give a hint
if (height> Chain.block_height)
abort("Height Error")
//Get users mined at the current height
let map_accounts = state.day_accounts[height]
//Send tokens
send(map_accounts.index,map_accounts)
//Clear the data for the current height
put( state{ day_accounts = Map.delete(height, state.day_accounts)})
//Repayment ae method
private stateful function send(index: int ,map_accounts :map_accounts) =
//If map is greater than 0, recursively issue
if(index >= 0)
//Get the current user
let account = map_accounts.accounts[index]
//If the current unlock time is confirmed to have exceeded, unlock the mined ae
Chain.spend(account.account, account.number)
//Perform the next recursion
send(index-1, map_accounts)