Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: various fixes #10

Merged
merged 12 commits into from
Mar 26, 2024
76 changes: 35 additions & 41 deletions src/token.ts → src/fungibleToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,63 @@

import {
AccountUpdate,
Bool,
method,
PublicKey,
UInt64,
Account,
state,
State,
VerificationKey,
TokenContract,
AccountUpdateForest,
DeployArgs,
} from 'o1js';

import errors from './errors';
import {
type Burnable,
type Mintable,
type Upgradable,
} from './interfaces/token/adminable';
import type Viewable from './interfaces/token/viewable';
import type { Transferable } from './interfaces';
import Approvable from './interfaces/token/approvable';

class Token
class FungibleToken
extends TokenContract
implements
Approvable,
Mintable,
Burnable,
Viewable,
Transferable,
Upgradable
Transferable
{
@state(PublicKey) public adminAccount = State<PublicKey>();
@state(UInt64) public totalSupply = State<UInt64>();
@state(UInt64) public circulatingSupply = State<UInt64>();

public decimals: UInt64 = UInt64.from(9);

@method
public initialize(adminPublicKey: PublicKey, totalSupply: UInt64) {
this.account.provedState.requireEquals(Bool(false));

this.adminAccount.set(adminPublicKey);
this.totalSupply.set(totalSupply);
deploy(args: DeployArgs & {
adminPublicKey: PublicKey,
totalSupply: UInt64,
tokenSymbol: string}) {
super.deploy();
this.adminAccount.set(args.adminPublicKey);
this.totalSupply.set(args.totalSupply);
this.circulatingSupply.set(UInt64.from(0));
this.account.tokenSymbol.set(args.tokenSymbol);
}

requireAdminSignature(): AccountUpdate {
const adminAccount = this.adminAccount.getAndRequireEquals();
const adminAccountUpdate = AccountUpdate.createSigned(adminAccount);
return adminAccountUpdate;
}

@method setAdminAccount(adminAccount: PublicKey) {
this.requireAdminSignature();
this.adminAccount.set(adminAccount);
}

/**
* Mintable
*/
Expand All @@ -65,24 +70,26 @@ class Token
public mint(address: PublicKey, amount: UInt64): AccountUpdate {
this.requireAdminSignature();

const totalSupply = this.getTotalSupply();
const circulatingSupply = this.getCirculatingSupply();
const totalSupply = this.totalSupply.getAndRequireEquals();
const circulatingSupply = this.circulatingSupply.getAndRequireEquals();

const newCirculatingSupply = circulatingSupply.add(amount);
newCirculatingSupply.assertLessThanOrEqual(
totalSupply,
errors.mintAmountExceedsTotalSupply
);
this.circulatingSupply.set(newCirculatingSupply);

// eslint-disable-next-line no-warning-comments
// TODO: find out why amount can't be Int64, also for burn
return this.internal.mint({ address, amount });
}

@method
public setTotalSupply(amount: UInt64) {
this.requireAdminSignature();

this.getCirculatingSupply()
.assertLessThanOrEqual(amount);

this.totalSupply.set(amount);
}

Expand All @@ -95,19 +102,12 @@ class Token
// If you want to disallow burning without approval from
// the token admin, you could require a signature here:
// this.requireAdminSignature();

return this.internal.burn({ address: from, amount });
}

/**
* Upgradable
*/
this.circulatingSupply.set(
this.circulatingSupply.getAndRequireEquals()
.sub(amount));

@method
public setVerificationKey(verificationKey: VerificationKey) {
this.requireAdminSignature();

this.account.verificationKey.set(verificationKey);
return this.internal.burn({ address: from, amount });
}

/**
Expand All @@ -123,35 +123,29 @@ class Token
* Viewable
*/

public getAccountOf(address: PublicKey): ReturnType<typeof Account> {
return Account(address, this.deriveTokenId());
}

@method
public getBalanceOf(address: PublicKey): UInt64 {
const account = this.getAccountOf(address);
const account = Account(address, this.deriveTokenId());
const balance = account.balance.get();
account.balance.requireEquals(balance);

return balance;
}

@method
public getTotalSupply(): UInt64 {
const totalSupply = this.totalSupply.get();
this.totalSupply.requireEquals(totalSupply);

return totalSupply;
return (this.totalSupply.getAndRequireEquals());
}

@method
public getCirculatingSupply(): UInt64 {
const circulatingSupply = this.circulatingSupply.get();
this.circulatingSupply.requireEquals(circulatingSupply);

return circulatingSupply;
return(this.circulatingSupply.getAndRequireEquals());
}

@method
public getDecimals(): UInt64 {
return this.decimals;
}
}

export default Token;
export default FungibleToken;
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'reflect-metadata';
import 'core-js';
export * from './interfaces';
export * from './token';
export * from './fungibleToken';
export * from './errors';
10 changes: 0 additions & 10 deletions src/interfaces/admin/admin.ts

This file was deleted.

3 changes: 0 additions & 3 deletions src/interfaces/admin/index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions src/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'reflect-metadata';
import 'core-js';
export * from './admin';
export * from './tokenAccount';
export * from './token';
7 changes: 1 addition & 6 deletions src/interfaces/token/adminable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
type State,
Struct,
Field,
VerificationKey,
} from 'o1js';

class AdminAction extends Struct({
Expand Down Expand Up @@ -36,9 +35,5 @@ interface Burnable {
burn: (from: PublicKey, amount: UInt64) => AccountUpdate;
}

interface Upgradable {
setVerificationKey: (verificationKey: VerificationKey) => void;
}

export type { Mintable, Burnable, Upgradable };
export type { Mintable, Burnable };
export { AdminAction };
5 changes: 1 addition & 4 deletions src/interfaces/token/viewable.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
/* eslint-disable @typescript-eslint/prefer-readonly-parameter-types */
import { PublicKey, Account, UInt64 } from 'o1js';
import { PublicKey, UInt64 } from 'o1js';

interface Viewable {
// eslint-disable-next-line no-warning-comments
// TODO: is there a better return type for `Account`?
getAccountOf: (address: PublicKey) => ReturnType<typeof Account>;
getBalanceOf: (address: PublicKey) => UInt64;
getTotalSupply: () => UInt64;
getCirculatingSupply: () => UInt64;
Expand Down
8 changes: 0 additions & 8 deletions src/interfaces/tokenAccount/depositable.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/interfaces/tokenAccount/index.ts

This file was deleted.

8 changes: 0 additions & 8 deletions src/interfaces/tokenAccount/withdrawable.ts

This file was deleted.

11 changes: 3 additions & 8 deletions test/ThirdParty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,14 @@ import {
Int64,
} from 'o1js';

import Token from '../src/token';
import Depositable from '../src/interfaces/tokenAccount/depositable';
import Withdrawable from '../src/interfaces/tokenAccount/withdrawable';
import FungibleToken from '../src/fungibleToken';

class ThirdParty extends SmartContract implements Depositable, Withdrawable {
class ThirdParty extends SmartContract {
@state(PublicKey) ownerAddress = State<PublicKey>();

public get tokenOwner() {
this.ownerAddress.requireEquals(this.ownerAddress.get());
if(!this.ownerAddress.get()) {
throw new Error('Token owner address has not been set')
}
return new Token(this.ownerAddress.get())
return new FungibleToken(this.ownerAddress.get())
}

deploy(args: DeployArgs & {ownerAddress: PublicKey}) {
Expand Down
Loading
Loading