import { Address , constant , Contract , createEventNotifier , Fixed , ForwardValue , MapStorage , SmartContract , } from '@neo-one/smart-contract' ; const notifyTransfer = createEventNotifier < Address | undefined , Address | undefined , Fixed < 8 > > ( 'transfer' , 'from' , 'to' , 'amount' ) ; const notifyApproveSendTransfer = createEventNotifier < Address , Address , Fixed < 8 > > ( 'approveSendTransfer' , 'from' , 'to' , 'amount' ) ; const notifyRevokeSendTransfer = createEventNotifier < Address , Address , Fixed < 8 > > ( 'revokeSendTransfer' , 'from' , 'to' , 'amount' ) ; interface CoinPayableContract { readonly approveReceiveTransfer : ( from : Address , amount : Fixed < 8 > , asset : Address , ... args : ForwardValue [ ] ) => boolean ; readonly onRevokeSendTransfer : ( from : Address , amount : Fixed < 8 > , asset : Address ) => void ; } export class Coin extends SmartContract { public readonly properties = { codeVersion : '1.0' , author : 'dicarlo2' , email : 'alex.dicarlo@neotracker.io' , description : 'NEO•ONE Coin' , } ; public readonly name = 'Eno' ; public readonly symbol = 'ENO' ; public readonly decimals = 8 ; private readonly balances = MapStorage . for < Address , Fixed < 8 > > ( ) ; private readonly approvedTransfers = MapStorage . for < [ Address , Address ] , Fixed < 8 > > ( ) ; private mutableSupply : Fixed < 8 > = 0 ; @ constant public get totalSupply ( ) : Fixed < 8 > { return this . mutableSupply ; } @ constant public balanceOf ( address ) { const balance = this . balances . get ( address ) ; return balance === undefined ? 0 : balance ; } @ constant public approvedTransfer ( from , to ) { const approved = this . approvedTransfers . get ( [ from , to ] ) ; return approved === undefined ? 0 : approved ; } public transfer ( from , to , amount , ... approveArgs ) { if ( amount < 0 ) { throw new Error ( `Amount must be greater than 0: ${ amount }` ) ; } const fromBalance = this . balanceOf ( from ) ; if ( fromBalance < amount ) { return false ; } const approved = this . approvedTransfer ( from , to ) ; const reduceApproved = approved >= amount && Address . isCaller ( to ) ; if ( ! reduceApproved && ! Address . isCaller ( from ) ) { return false ; } const contract = Contract . for ( to ) ; if ( contract !== undefined && ! Address . isCaller ( to ) ) { const smartContract = SmartContract . for < CoinPayableContract > ( to ) ; if ( ! smartContract . approveReceiveTransfer ( from , amount , this . address , ... approveArgs ) ) { return false ; } } const toBalance = this . balanceOf ( to ) ; this . balances . set ( from , fromBalance - amount ) ; this . balances . set ( to , toBalance + amount ) ; notifyTransfer ( from , to , amount ) ; if ( reduceApproved ) { this . approvedTransfers . set ( [ from , to ] , approved - amount ) ; } return true ; } public approveSendTransfer ( from , to , amount ) { if ( amount < 0 ) { throw new Error ( `Amount must be greater than 0: ${ amount }` ) ; } if ( ! Address . isCaller ( from ) ) { return false ; } this . approvedTransfers . set ( [ from , to ] , this . approvedTransfer ( from , to ) + amount ) ; notifyApproveSendTransfer ( from , to , amount ) ; return true ; } public approveReceiveTransfer ( _from , _amount , _asset ) { return false ; } public revokeSendTransfer ( from , to , amount ) { if ( amount < 0 ) { throw new Error ( `Amount must be greater than 0: ${ amount }` ) ; } if ( ! Address . isCaller ( from ) ) { return false ; } const approved = this . approvedTransfer ( from , to ) ; if ( approved < amount ) { return false ; } this . approvedTransfers . set ( [ from , to ] , approved - amount ) ; notifyRevokeSendTransfer ( from , to , amount ) ; const contract = Contract . for ( to ) ; if ( contract !== undefined ) { const smartContract = SmartContract . for < CoinPayableContract > ( to ) ; smartContract . onRevokeSendTransfer ( from , amount , this . address ) ; } return true ; } public onRevokeSendTransfer ( _from , _amount , _asset ) { } public issue ( to , amount ) { if ( amount < 0 ) { throw new Error ( `Amount must be greater than 0: ${ amount }` ) ; } const toBalance = this . balanceOf ( to ) ; this . balances . set ( to , toBalance + amount ) ; notifyTransfer ( undefined , to , amount ) ; this . mutableSupply += amount ; return true ; } }