You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
7.3 KiB
241 lines
7.3 KiB
|
|
import "@stdlib/ownable"; |
|
import "./wallet"; |
|
import "./linker"; |
|
import "./constants"; |
|
import "./staking"; |
|
|
|
|
|
@interface("org.ton.jetton.master") |
|
trait TONBTrait with Ownable, StakingTrait { |
|
|
|
// |
|
// Storage |
|
// |
|
|
|
totalSupply: Int; |
|
mintable: Bool; |
|
owner: Address; |
|
content: Cell?; |
|
first_linker: Address?; |
|
last_linker: Address?; |
|
n_linkers: Int = 0; |
|
staking_pool: Address?; |
|
in_the_pool: Int = 0; |
|
withdrawal_requests: WithdrawalRequests; |
|
requested_withdrawal: Int = 0; |
|
|
|
|
|
// |
|
// Receivers |
|
// |
|
|
|
receive(msg: TokenUpdateContent) { |
|
|
|
// Allow changing content only by owner |
|
self.requireOwner(); |
|
|
|
// Update content |
|
self.content = msg.content; |
|
} |
|
|
|
receive(msg: TokenBurnNotification) { |
|
|
|
// Check wallet |
|
self.requireWallet(msg.owner); |
|
|
|
// Update supply |
|
self.totalSupply = self.totalSupply - msg.amount; |
|
let available: Int = myBalance() - tonb_floor - withdraw_gas_consumption; |
|
if (available < msg.amount) { |
|
/* if not enough tokens, withdraw what we have, send some tokens to the owner, add a withdrawal request (-withdrawal_gas) */ |
|
let diff: Int = msg.amount - available; |
|
send(SendParameters{ |
|
to: msg.owner, |
|
value: myBalance() - tonb_floor, |
|
bounce: false |
|
}); |
|
let body: Cell = TokenTransferInternal{ |
|
amount: diff, |
|
queryId: 0, |
|
from: myAddress(), |
|
responseAddress: myAddress(), |
|
forwardTonAmount: 0, |
|
forwardPayload: emptySlice(), |
|
setLinker: null, |
|
setLinkerAddress: null |
|
}.toCell(); |
|
let walletAddress: Address = self.get_wallet_address(msg.owner); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: 0, |
|
bounce: false, |
|
mode: SendRemainingValue, |
|
body: body |
|
}); |
|
let ctx: Context = context(); |
|
self.requestWithdrawal(ctx.sender, diff); |
|
return; |
|
} |
|
|
|
// Withdraw |
|
send(SendParameters{ |
|
to: msg.owner, |
|
value: msg.amount - withdraw_gas_consumption, |
|
bounce: false |
|
}); |
|
} |
|
|
|
receive(msg: BlacklistWallet) { |
|
// Allow blacklisting only by owner |
|
self.requireOwner(); |
|
|
|
// Blacklist wallet |
|
let winit: StateInit = self.getJettonWalletInit(msg.wallet); |
|
let walletAddress: Address = contractAddress(winit); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
bounce: false, |
|
body: msg.toCell() |
|
}); |
|
} |
|
|
|
// |
|
// Get Methods |
|
// |
|
|
|
get fun get_wallet_address(owner: Address): Address { |
|
let winit: StateInit = self.getJettonWalletInit(owner); |
|
return contractAddress(winit); |
|
} |
|
|
|
get fun get_jetton_data(): JettonData { |
|
let code: Cell = self.getJettonWalletInit(myAddress()).code; |
|
return JettonData{ |
|
totalSupply: self.totalSupply, |
|
mintable: self.mintable, |
|
owner: self.owner, |
|
content: self.content, |
|
walletCode: code |
|
}; |
|
} |
|
|
|
// |
|
// Private Methods |
|
// |
|
|
|
fun mint(to: Address, amount: Int, responseAddress: Address?) { |
|
|
|
// Update total supply |
|
self.totalSupply = self.totalSupply + amount; |
|
|
|
// Create message |
|
let winit: StateInit = self.getJettonWalletInit(to); |
|
let walletAddress: Address = contractAddress(winit); |
|
let linker_init: StateInit = initOf Linker(self.n_linkers, walletAddress, myAddress()); |
|
let linker_address: Address = contractAddress(linker_init); |
|
|
|
send(SendParameters{ |
|
to: linker_address, |
|
value: linker_credit, |
|
bounce: false, |
|
body: SetLinkerNeighbor{ |
|
neighbor: self.last_linker |
|
}.toCell(), |
|
code: linker_init.code, |
|
data: linker_init.data |
|
}); |
|
self.last_linker = linker_address; |
|
self.n_linkers = self.n_linkers + 1; |
|
let wallet_msg_body: Cell = TokenTransferInternal{ |
|
amount: amount, |
|
queryId: 0, |
|
from: myAddress(), |
|
responseAddress: responseAddress, |
|
forwardTonAmount: 0, |
|
forwardPayload: emptySlice(), |
|
setLinker: self.n_linkers - 1, |
|
setLinkerAddress: linker_address |
|
}.toCell(); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: wallet_credit, |
|
bounce: false, |
|
body: wallet_msg_body, |
|
code: winit.code, |
|
data: winit.data |
|
}); |
|
} |
|
|
|
receive(msg: RequestLinker) { |
|
let ctx: Context = context(); |
|
let winit: StateInit = self.getJettonWalletInit(msg.client); |
|
let walletAddress: Address = contractAddress(winit); |
|
require(walletAddress == ctx.sender, "invalid sender"); |
|
let linker_init: StateInit = initOf Linker(self.n_linkers, walletAddress, myAddress()); |
|
let linker_address: Address = contractAddress(linker_init); |
|
send(SendParameters{ |
|
to: linker_address, |
|
value: linker_credit, |
|
bounce: false, |
|
body: SetLinkerNeighbor{ |
|
neighbor: self.last_linker |
|
}.toCell(), |
|
code: linker_init.code, |
|
data: linker_init.data |
|
}); |
|
self.last_linker = linker_address; |
|
self.n_linkers = self.n_linkers + 1; |
|
let wallet_msg_body: Cell = TokenTransferInternal{ |
|
amount: 0, |
|
queryId: 0, |
|
from: myAddress(), |
|
responseAddress: myAddress(), |
|
forwardTonAmount: 0, |
|
forwardPayload: emptySlice(), |
|
setLinker: self.n_linkers - 1, |
|
setLinkerAddress: linker_address |
|
}.toCell(); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: wallet_credit, |
|
bounce: false, |
|
body: wallet_msg_body, |
|
code: winit.code, |
|
data: winit.data |
|
}); |
|
} |
|
|
|
fun burn(from: Address, amount: Int, responseAddress: Address?) { |
|
|
|
// Create message |
|
let winit: StateInit = self.getJettonWalletInit(from); |
|
let walletAddress: Address = contractAddress(winit); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: 0, |
|
bounce: false, |
|
mode: SendRemainingValue, |
|
body: TokenBurn{ |
|
amount: amount, |
|
queryId: 0, |
|
responseAddress: responseAddress, |
|
owner: from |
|
}.toCell(), |
|
code: winit.code, |
|
data: winit.data |
|
}); |
|
} |
|
|
|
fun requireWallet(owner: Address) { |
|
let ctx: Context = context(); |
|
let winit: StateInit = self.getJettonWalletInit(owner); |
|
require(contractAddress(winit) == ctx.sender, "Invalid sender"); |
|
} |
|
|
|
virtual fun getJettonWalletInit(address: Address): StateInit { |
|
return initOf TONBWallet(myAddress(), address); |
|
} |
|
} |