Created
May 8, 2018 09:07
-
-
Save dicarlo2/e5b8bc499b3b94f4618dee87fd738585 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 { | |
Address, | |
Event, | |
Fixed, | |
SmartContract, | |
notify, | |
verifySender, | |
} from '@neo-one/smart-contract'; | |
class Transfer<Decimals extends number> extends Event { | |
constructor(from: Address, to: Address, amount: Fixed<Decimals>) { | |
super(from, to, amount); | |
} | |
} | |
class Approve<Decimals extends number> extends Event { | |
constructor(owner: Address, spender: Address, amount: Fixed<Decimals>) { | |
super(owner, spender, amount); | |
} | |
} | |
export abstract class Token<Decimals extends number> extends SmartContract { | |
public abstract readonly name: string; | |
public abstract readonly decimals: Decimals; | |
public abstract readonly symbol: string; | |
protected readonly owner: Address; | |
private supply: Fixed<Decimals> = 0; | |
private readonly balances: Map<Address, Fixed<Decimals>> = new Map(); | |
private readonly allowances: Map<Address, Map<Address, Fixed<Decimals>>> = new Map(); | |
constructor(owner: Address) { | |
super(); | |
this.owner = owner; | |
} | |
public transfer( | |
from: Address, | |
to: Address, | |
amount: Fixed<Decimals>, | |
): void { | |
verifySender(from); | |
this.doTransfer(from, to, amount); | |
} | |
public transferFrom( | |
from: Address, | |
to: Address, | |
amount: Fixed<Decimals>, | |
): void { | |
const available = this.allowance(from, to); | |
if (available < amount) { | |
throw new Error('Insufficient funds approved'); | |
} | |
this.doTransfer(from, to, amount); | |
this.setAllowance(from, to, available - amount); | |
} | |
public approve( | |
owner: Address, | |
spender: Address, | |
amount: Fixed<Decimals>, | |
): void { | |
verifySender(owner); | |
const fromValue = this.balanceOf(owner); | |
if (fromValue < amount) { | |
throw new Error('Insufficient funds'); | |
} | |
this.setAllowance(owner, spender, this.allowance(owner, spender) + amount); | |
notify(new Approve(owner, spender, amount)); | |
} | |
public balanceOf(addr: Address): Fixed<Decimals> { | |
return this.balances.get(addr) || 0; | |
} | |
public allowance(owner: Address, spender: Address): Fixed<Decimals> { | |
return (this.allowances.get(owner) || new Map()).get(spender) || 0; | |
} | |
public get totalSupply(): Fixed<Decimals> { | |
return this.supply; | |
} | |
protected issue(addr: Address, amount: Fixed<Decimals>): void { | |
this.balances.set(addr, this.balanceOf(addr) + amount); | |
this.supply += amount; | |
notify(new Transfer(this.address, addr, amount)); | |
} | |
private doTransfer( | |
from: Address, | |
to: Address, | |
amount: Fixed<Decimals>, | |
): void { | |
if (amount <= 0) { | |
throw new Error('Invalid amount'); | |
} | |
const fromValue = this.balanceOf(from); | |
if (fromValue < amount) { | |
throw new Error('Insufficient funds'); | |
} | |
this.balances.set(from, fromValue - amount); | |
this.balances.set(to, this.balanceOf(to) + amount); | |
notify(new Transfer(from, to, amount)); | |
} | |
private setAllowance( | |
from: Address, | |
to: Address, | |
amount: Fixed<Decimals>, | |
): void { | |
let allowances = this.allowances.get(from); | |
if (allowances == null) { | |
allowances = new Map(); | |
} | |
allowances.set(to, amount); | |
this.allowances.set(from, allowances); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment