-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Started rewriting tests, migraged to tact-template
- Loading branch information
Showing
22 changed files
with
1,299 additions
and
2,677 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
Large diffs are not rendered by default.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import "@stdlib/ownable"; | ||
import "./jetton_wallet"; | ||
import "./messages"; | ||
|
||
asm fun emptyAddress(): Address { b{00} PUSHSLICE } | ||
|
||
struct JettonMasterState { | ||
totalSupply: Int as coins; | ||
mintable: Bool; | ||
adminAddress: Address; | ||
jettonContent: Cell; | ||
jettonWalletCode: Cell; | ||
} | ||
|
||
contract JettonMinter with OwnableTransferable { | ||
totalSupply: Int as coins; | ||
mintable: Bool; | ||
owner: Address; | ||
jettonContent: Cell; | ||
jettonWalletCode: Cell; | ||
|
||
init(owner: Address, jettonContent: Cell) { | ||
self.totalSupply = 0; | ||
self.mintable = true; | ||
self.owner = owner; | ||
self.jettonContent = jettonContent; | ||
self.jettonWalletCode = initOf JettonWallet(self.owner, myAddress()).code; | ||
} | ||
|
||
receive(msg: TokenBurnNotification) { | ||
//Check that the message is from msg.sender's jetton_wallet | ||
require(sender() == self.getJettonWalletByOwner(msg.sender), "Not wallet owner"); | ||
|
||
self.totalSupply -= msg.amount; | ||
if (msg.response_destination != null) { | ||
send(SendParameters{ | ||
to: msg.response_destination!!, | ||
value: 0, | ||
bounce: false, | ||
mode: SendRemainingValue, | ||
body: TokenExcesses{ | ||
query_id: msg.query_id | ||
}.toCell() | ||
}); | ||
} | ||
} | ||
|
||
receive(msg: TokenUpdateContent){ | ||
self.requireOwner(); // Allow changing content only by owner | ||
self.jettonContent = msg.content; // Update content | ||
} | ||
|
||
// https://github.com/ton-blockchain/TEPs/blob/master/text/0089-jetton-wallet-discovery.md | ||
receive(msg: ProvideWalletAddress) { | ||
require(context().value >= ton("0.0061"), "Insufficient gas"); | ||
let includedAddress: Address? = null; | ||
let workchain: Int = parseStdAddress(msg.owner_address.asSlice()).workchain; | ||
//Note, that emptyAddress != null, it is different values. | ||
//We do like that according to TEP above | ||
let targetJettonWallet: Address = emptyAddress(); | ||
|
||
//Here was no such check in Howard's code | ||
if(workchain == 0) { | ||
//Only in this case (address is from basechain) we can calculate the address | ||
targetJettonWallet = contractAddress(initOf JettonWallet(msg.owner_address, myAddress())); | ||
} | ||
if (msg.include_address) { | ||
includedAddress = msg.owner_address; | ||
} | ||
send(SendParameters{ | ||
to: sender(), | ||
value: 0, | ||
mode: SendRemainingValue, | ||
body: TakeWalletAddress{ | ||
query_id: msg.query_id, | ||
wallet_address: targetJettonWallet, | ||
owner_address: includedAddress | ||
}.toCell() | ||
}); | ||
} | ||
receive(msg: Mint) { | ||
self.requireOwner(); // Allow minting only by owner | ||
require(self.mintable, "Not mintable"); | ||
//Maybe we should check that msg.value is enough to cover the gas fees | ||
//Or, maybe we should do self.totalSupply -= msg.amount if bounced. | ||
//But there is no any check in Howard's code and in official funC code, | ||
self.totalSupply += msg.amount; // Update total supply | ||
|
||
let winit: StateInit = self.getJettonWalletInit(msg.receiver); | ||
|
||
send(SendParameters{ | ||
to: contractAddress(winit), | ||
value: 0, | ||
bounce: true, | ||
mode: SendRemainingValue, | ||
body: TokenTransferInternal{ | ||
query_id: 0, | ||
amount: msg.amount, | ||
from: myAddress(), | ||
response_destination: self.owner, // Owner is minting, so send excess to owner | ||
forward_ton_amount: 0, | ||
forward_payload: emptySlice() | ||
}.toCell(), | ||
code: winit.code, | ||
data: winit.data | ||
}); | ||
} | ||
|
||
fun getJettonWalletByOwner(jetton_wallet_owner: Address): Address { | ||
let ctx: Context = context(); | ||
let jwInit: StateInit = self.getJettonWalletInit(jetton_wallet_owner); | ||
return contractAddress(jwInit); | ||
} | ||
|
||
fun getJettonWalletInit(address: Address): StateInit { | ||
return initOf JettonWallet(address, myAddress()); | ||
} | ||
|
||
get fun get_jetton_data(): JettonMasterState { | ||
return JettonMasterState { | ||
totalSupply: self.totalSupply, | ||
mintable: self.mintable, | ||
adminAddress: self.owner, | ||
jettonContent: self.jettonContent, | ||
jettonWalletCode: self.jettonWalletCode | ||
} | ||
} | ||
get fun get_wallet_address(ownerAddress: Address): Address { | ||
return self.getJettonWalletByOwner(ownerAddress); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
asm fun myCode(): Cell { MYCODE } | ||
|
||
@interface("org.ton.jetton.wallet") | ||
contract JettonWallet with Ownable { | ||
balance: Int as coins; | ||
owner: Address; | ||
master: Address; | ||
const minTonsForStorage: Int = ton("0.019"); | ||
const gasConsumption: Int = ton("0.013"); | ||
|
||
init(owner: Address, master: Address) { | ||
self.balance = 0; | ||
self.owner = owner; | ||
self.master = master; | ||
} | ||
|
||
|
||
receive(msg: TokenTransfer) { | ||
self.requireOwner(); | ||
|
||
let final: Int = (((10 * 2 + 2 * self.gasConsumption) + self.minTonsForStorage) + msg.forward_ton_amount); // Gas checks, forward_ton = 0.152 | ||
|
||
//Context() returns Structure with info about incoming message | ||
require(context().value > final, "Unsufficient amount of TON attached"); | ||
|
||
self.balance -= msg.amount; | ||
|
||
//coins type is unsigned type, so | ||
//self.balance is unsigned when storing and loading (msg.amount is unsigned too), | ||
//however when doing calculations it's value may be negative, so the check is correct | ||
require(self.balance >= 0, "Invalid balance"); | ||
let init: StateInit = initOf JettonWallet(msg.destination, self.master); | ||
|
||
let wallet_address: Address = contractAddress(init); | ||
send(SendParameters{ | ||
to: wallet_address, | ||
value: 0, | ||
mode: SendRemainingValue, | ||
bounce: true, | ||
body: TokenTransferInternal { | ||
query_id: msg.query_id, | ||
amount: msg.amount, | ||
from: self.owner, | ||
response_destination: msg.response_destination, | ||
forward_ton_amount: msg.forward_ton_amount, | ||
forward_payload: msg.forward_payload | ||
}.toCell(), | ||
code: init.code, | ||
data: init.data | ||
} | ||
); | ||
} | ||
|
||
receive(msg: TokenTransferInternal) { | ||
// This message should come only from master, or from other JettonWallet | ||
if (sender() != self.master) { | ||
let init: StateInit = initOf JettonWallet(msg.from, self.master); | ||
require(contractAddress(init) == sender(), "Sender is not another JettonWallet or JettonMaster"); | ||
} | ||
// Update balance | ||
self.balance += msg.amount; | ||
|
||
//Commented require() here because self.balance and msg.amount are coins, so they are unsigned | ||
//require(self.balance >= 0, "Invalid balance"); | ||
// Get value for gas | ||
|
||
let ctx: Context = context(); //Context of current message | ||
let msgValue: Int = ctx.value; | ||
let tonBalanceBeforeMsg = myBalance() - msgValue; | ||
let storageFee = self.minTonsForStorage - min(tonBalanceBeforeMsg, self.minTonsForStorage); | ||
msgValue -= (storageFee + self.gasConsumption); | ||
let fwd_fee: Int = ctx.readForwardFee(); | ||
|
||
|
||
if (msg.forward_ton_amount > 0) { | ||
msgValue = ((msgValue - msg.forward_ton_amount) - fwd_fee); | ||
send(SendParameters{ | ||
to: self.owner, | ||
value: msg.forward_ton_amount, | ||
mode: SendPayGasSeparately, | ||
bounce: false, | ||
body: TokenNotification{ // 0x7362d09c -- Remind the new Owner | ||
query_id: msg.query_id, | ||
amount: msg.amount, | ||
from: msg.from, | ||
forward_payload: msg.forward_payload | ||
}.toCell() | ||
}); | ||
} | ||
// 0xd53276db -- Cashback to the original Sender | ||
if (msg.response_destination != null && msgValue > 0) { | ||
send(SendParameters{ | ||
to: msg.response_destination!!, | ||
value: msgValue, | ||
mode: SendIgnoreErrors, // Jetton transfer is already succeeded, Here was PayGasSeparately in Howard's code | ||
bounce: false, | ||
body: TokenExcesses{ | ||
query_id: msg.query_id | ||
}.toCell() | ||
} | ||
); | ||
} | ||
} | ||
|
||
receive(msg: TokenBurn){ | ||
self.requireOwner(); | ||
|
||
let ctx: Context = context(); | ||
self.balance = (self.balance - msg.amount); // Update balance | ||
require(self.balance >= 0, "Invalid balance after burn"); | ||
let fwd_fee: Int = ctx.readForwardFee(); // Gas checks | ||
require(ctx.value > ((fwd_fee + 2 * self.gasConsumption) + self.minTonsForStorage), "Invalid value - Burn"); | ||
// Burn tokens | ||
send(SendParameters{ | ||
to: self.master, | ||
value: 0, | ||
mode: SendRemainingValue, | ||
bounce: true, | ||
body: TokenBurnNotification{ | ||
query_id: msg.query_id, | ||
amount: msg.amount, | ||
sender: self.owner, | ||
response_destination: msg.response_destination | ||
}.toCell() | ||
} | ||
); | ||
} | ||
|
||
bounced(msg: bounced<TokenTransferInternal>){ | ||
self.balance = (self.balance + msg.amount); | ||
} | ||
|
||
bounced(msg: bounced<TokenBurnNotification>){ | ||
self.balance = (self.balance + msg.amount); | ||
} | ||
|
||
get fun get_wallet_data(): JettonWalletData { | ||
return JettonWalletData{ | ||
balance: self.balance, | ||
owner: self.owner, | ||
master: self.master, | ||
code: myCode() //may be raplaced by "initOf JettonDefaultWallet(self.owner, self.master).code" | ||
}; | ||
} | ||
} |
Oops, something went wrong.