Skip to content

Commit

Permalink
feat: add maxSupply extension for jetton
Browse files Browse the repository at this point in the history
  • Loading branch information
ZigBalthazar committed Jul 5, 2024
1 parent 0928592 commit d024c30
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 1 deletion.
88 changes: 88 additions & 0 deletions contracts/mocks/tokens/jetton/maxSupply.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import "../../../traits/tokens/jetton/basic/master.tact";
import "../../../traits/tokens/jetton/basic/wallet.tact";
import "../../../traits/tokens/jetton/extensions/maxSupply.tact";
message Mint {
amount: Int;
receiver: Address;
}

contract MaxSupplyJettonImp with Jetton,JettonMaxSupply {
totalSupply: Int as coins;
maxSupply:Int;
owner: Address;
content: Cell;
mintable: Bool;

init(owner: Address, content: Cell, maxSupply:Int){
self.maxSupply = maxSupply;
self.totalSupply = 0;
self.owner = owner;
self.mintable = true;
self.content = content;
}

receive(msg: Mint){
let ctx: Context = context();
require(ctx.sender == self.owner, "Not Owner");
self.requireMaxSupply(msg.amount);
require(self.mintable, "Can't Mint Anymore");
let toWinit: StateInit = self.getJettonWalletInit(msg.receiver); // Create message
self.mint(msg.receiver, msg.amount, self.owner, toWinit); // (to, amount, response_destination)
}

receive("Owner: MintClose"){
let ctx: Context = context();
require(ctx.sender == self.owner, "Not Owner");
self.mintable = false;
}

receive(msg: TokenBurnNotification){
let toWinit: StateInit = self.getJettonWalletInit(msg.owner); // Create message
self.tokenBurnNotification(msg, toWinit);
}

fun getJettonWalletInit(address: Address): StateInit {
return initOf JettonSampleWalletImp(myAddress(), address);
}

get fun get_jetton_data(): JettonData {
let winit: StateInit = self.getJettonWalletInit(myAddress());
return self.get_jetton_data_handler(winit);
}

get fun get_wallet_address(owner: Address): Address {
let winit: StateInit = self.getJettonWalletInit(owner);
return self.get_wallet_address_handler(winit);
}
}

contract JettonSampleWalletImp with JettonDefaultWallet {
balance: Int;
owner: Address;
master: Address;
init(_master: Address, _owner: Address){
self.balance = 0;
self.master = _master;
self.owner = _owner;
}

receive(msg: TokenTransfer){
let init: StateInit = initOf JettonSampleWalletImp(self.master, msg.destination);
self.tokenTrnasfer(msg, init);
}

receive(msg: TokenBurn){
self.tokenBurn(msg);
}

receive(msg: TokenTransferInternal){
// 0x178d4519
let sinit: StateInit = initOf JettonSampleWalletImp(self.master, msg.from);
self.tokenTransferInternal(msg, sinit);
}

get fun get_wallet_data(): JettonWalletData {
let sinit: Cell = initOf JettonSampleWalletImp(self.master, self.owner).code;
return self.get_wallet_data_handler(sinit);
}
}
1 change: 0 additions & 1 deletion contracts/traits/tokens/jetton/basic/master.tact
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ trait Jetton with Ownable {
mintable: Bool;
owner: Address;
content: Cell;
//! max_supply: Int; // This is not in the TEP-74 interface

fun tokenBurnNotification(msg: TokenBurnNotification, winit:StateInit) {
self.requireWallet(msg.owner, winit); // Check wallet
Expand Down
18 changes: 18 additions & 0 deletions contracts/traits/tokens/jetton/extensions/maxSupply.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
trait JettonMaxSupply {
maxSupply: Int;
totalSupply: Int;

fun requireMaxSupply(mintAmount: Int) {
if(self.maxSupply >= (self.totalSupply + mintAmount)){
throw(7878);
}
}

fun checkMaxSupply(mintAmount: Int): Bool {
return self.maxSupply >= (self.totalSupply + mintAmount);
}

get fun isMaxSupplyReached(): Bool {
return self.maxSupply == self.totalSupply;
}
}
73 changes: 73 additions & 0 deletions tests/tokens/jetton/extensions/maxsupply.behavior.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox';
import { beginCell, Cell, Dictionary, toNano } from '@ton/core';
import '@ton/test-utils';
import { buildOnchainMetadata } from '../jettonHelper';
import { JettonSampleWalletImp, TokenTransfer } from '../../../../build/BasicJetton/tact_JettonSampleWalletImp';
import { MaxSupplyJettonImp } from '../../../../build/MaxSupplyJetton/tact_MaxSupplyJettonImp';

export function shouldBehaveLikeBasicJetton(): void {
let blockchain: Blockchain;
let jetton: SandboxContract<MaxSupplyJettonImp>;
let alice: SandboxContract<TreasuryContract>;
let bob: SandboxContract<TreasuryContract>;

const jettonParams = {
name: 'open gem max supply',
description: 'This is description of open gem Jetton Token in Tact-lang',
symbol: 'OG',
image: 'https://avatars.githubusercontent.com/u/173614477?s=96&v=4',
};

const jettonContent = buildOnchainMetadata(jettonParams);

beforeEach(async () => {
blockchain = await Blockchain.create();
alice = await blockchain.treasury('ALICE');
bob = await blockchain.treasury('BOB');
const Jetton = await MaxSupplyJettonImp.fromInit(alice.address, jettonContent, BigInt('1000000000'));
jetton = blockchain.openContract<MaxSupplyJettonImp>(Jetton);

await jetton.send(
alice.getSender(),
{ value: toNano('1') },
{ $$type: 'Mint', amount: BigInt('1000000000'), receiver: bob.address },
);
});

it('should init correctly', async () => {
const owner = await jetton.getOwner();
expect(owner.toString()).toBe(alice.address.toString());

const jettonData = await jetton.getGetJettonData();
const wallet = await JettonSampleWalletImp.init(jetton.address, bob.address);
expect(jettonData.$$type).toBe('JettonData');
expect(jettonData.mintable).toBe(true);
expect(jettonData.totalSupply).toBe(BigInt('1000000000'));
expect(jettonData.owner.toString()).toBe(alice.address.toString());
expect(jettonData.walletCode.toString()).toBe(wallet.code.toString());
});

it('should revert for mint more jetton correctly', async () => {
const mintMessage = await jetton.send(
alice.getSender(),
{ value: toNano('1') },
{ $$type: 'Mint', amount: BigInt('1'), receiver: bob.address },
);

expect(mintMessage.transactions).toHaveTransaction({
success: false,
from: alice.address,
to: jetton.address,
exitCode: 7878,
});
});

it('should check maxSupply correctly', async () => {
// TODO
});

it('should return is reached maxSupply correctly', async () => {
const isReachedMaxSupply = await jetton.getIsMaxSupplyReached();
expect(isReachedMaxSupply).toBe(true);
});
}
9 changes: 9 additions & 0 deletions wrappers/MaxSupplyJetton.compile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { CompilerConfig } from '@ton/blueprint';

export const compile: CompilerConfig = {
lang: 'tact',
target: 'contracts/mocks/tokens/jetton/maxSupply.tact',
options: {
debug: true,
},
};

0 comments on commit d024c30

Please sign in to comment.