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.
233 lines
7.1 KiB
233 lines
7.1 KiB
import "@stdlib/ownable"; |
|
import "./messages"; |
|
import "./linker"; |
|
import "./constants"; |
|
|
|
|
|
|
|
@interface("org.ton.jetton.wallet") |
|
contract TONBWallet { |
|
|
|
const minTonsForStorage: Int = ton("0.01"); |
|
const gasConsumption: Int = ton("0.01"); |
|
|
|
balance: Int; |
|
owner: Address; |
|
master: Address; |
|
blacklisted: Bool = false; |
|
linker: Int?; |
|
linker_address: Address?; |
|
|
|
init(master: Address, owner: Address) { |
|
self.balance = 0; |
|
self.owner = owner; |
|
self.master = master; |
|
} |
|
|
|
receive(msg: TokenTransfer) { |
|
require(!self.blacklisted, "Wallet is blacklisted"); |
|
|
|
// Check sender |
|
let ctx: Context = context(); |
|
require(ctx.sender == self.owner, "Invalid sender"); |
|
|
|
// Update balance |
|
self.balance = self.balance - msg.amount; |
|
require(self.balance >= 0, "Invalid balance"); |
|
|
|
// Gas checks |
|
let fwdFee: Int = ctx.readForwardFee(); |
|
let fwdCount: Int = 1; |
|
if (msg.forwardTonAmount > 0) { |
|
fwdCount = 2; |
|
} |
|
require(ctx.value > transfer_gas_consumption, "Invalid value"); |
|
|
|
// Send tokens |
|
let init: StateInit = initOf TONBWallet(self.master, msg.destination); |
|
let walletAddress: Address = contractAddress(init); |
|
send(SendParameters{ |
|
to: walletAddress, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
bounce: true, |
|
body: TokenTransferInternal{ |
|
amount: msg.amount, |
|
queryId: msg.queryId, |
|
from: self.owner, |
|
responseAddress: self.owner, |
|
forwardTonAmount: msg.forwardTonAmount, |
|
forwardPayload: msg.forwardPayload, |
|
setLinker: null, |
|
setLinkerAddress: null |
|
}.toCell(), |
|
code: init.code, |
|
data: init.data |
|
}); |
|
} |
|
|
|
receive(msg: TokenTransferInternal) { |
|
if(self.blacklisted){ |
|
send(SendParameters{ |
|
to: self.master, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
body: TokenBurnNotification{ |
|
queryId: msg.queryId, |
|
amount: msg.amount, |
|
owner: self.owner, |
|
responseAddress: self.owner |
|
}.toCell() |
|
}); |
|
return; |
|
} |
|
|
|
// Check sender |
|
let ctx: Context = context(); |
|
if (self.linker == null) { |
|
if (msg.setLinker != null) { |
|
self.linker = msg.setLinker; |
|
self.linker_address = msg.setLinkerAddress; |
|
} |
|
} |
|
if (ctx.sender != self.master/* && ctx.sender != self.linker_address*/) { |
|
let is_from_linker: Bool = false; |
|
if (self.linker_address != null) { |
|
if (ctx.sender == self.linker_address!!) { |
|
is_from_linker = true; |
|
} |
|
} |
|
if (!is_from_linker) { |
|
let sinit: StateInit = initOf TONBWallet(self.master, msg.from); |
|
require(contractAddress(sinit) == ctx.sender, "Invalid sender"); |
|
} |
|
} |
|
|
|
// Update balance |
|
self.balance = self.balance + msg.amount; |
|
require(self.balance >= 0, "Invalid balance"); |
|
|
|
// Adjust value for gas |
|
let msgValue: Int = ctx.value; |
|
let tonBalanceBeforeMsg: Int = myBalance() - msgValue; |
|
let storageFee: Int = self.minTonsForStorage - min(tonBalanceBeforeMsg, self.minTonsForStorage); |
|
|
|
if (self.linker == null) { |
|
// request a linker |
|
send(SendParameters{ |
|
to: self.master, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
body: RequestLinker { |
|
client: self.owner |
|
}.toCell() |
|
}); |
|
return; |
|
} |
|
msgValue = msgValue - (storageFee + self.gasConsumption); |
|
|
|
// Forward ton |
|
if (msg.forwardTonAmount > 0) { |
|
let fwdFee: Int = ctx.readForwardFee(); |
|
msgValue = msgValue - (msg.forwardTonAmount + fwdFee); |
|
send(SendParameters{ |
|
to: self.owner, |
|
value: msg.forwardTonAmount, |
|
bounce: false, |
|
body: TokenNotification{ |
|
queryId: msg.queryId, |
|
amount: msg.amount, |
|
from: msg.from, |
|
forwardPayload: msg.forwardPayload |
|
}.toCell() |
|
}); |
|
} |
|
|
|
// Cashback |
|
if (msg.responseAddress != null && msgValue > 0) { |
|
send(SendParameters{ |
|
to: msg.responseAddress!!, |
|
value: msgValue, |
|
bounce: false, |
|
body: TokenExcesses{ |
|
queryId: msg.queryId |
|
}.toCell() |
|
}); |
|
} |
|
} |
|
|
|
receive(msg: TokenBurn) { |
|
|
|
// Check sender |
|
let ctx: Context = context(); |
|
require(ctx.sender == self.owner || ctx.sender == self.master || ctx.sender == self.linker_address, "Invalid sender"); |
|
|
|
// Update balance |
|
self.balance = self.balance - msg.amount; |
|
require(self.balance >= 0, "Invalid balance"); |
|
|
|
// // Gas checks |
|
let fwdFee: Int = ctx.readForwardFee(); |
|
require(ctx.value > 2 * self.gasConsumption + self.minTonsForStorage, "Invalid value"); |
|
|
|
// Burn tokens |
|
send(SendParameters{ |
|
to: self.master, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
bounce: true, |
|
body: TokenBurnNotification{ |
|
queryId: msg.queryId, |
|
amount: msg.amount, |
|
owner: self.owner, |
|
responseAddress: self.owner |
|
}.toCell() |
|
}); |
|
} |
|
|
|
receive(_msg: BlacklistWallet) { |
|
// Check sender |
|
let ctx: Context = context(); |
|
require(ctx.sender == self.master || ctx.sender == self.linker_address, "Invalid sender"); |
|
|
|
// Blacklist wallet |
|
self.blacklisted = true; |
|
let amount: Int = self.balance; |
|
self.balance = 0; |
|
|
|
send(SendParameters{ |
|
to: self.master, |
|
value: 0, |
|
mode: SendRemainingValue, |
|
bounce: true, |
|
body: TokenBurnNotification{ |
|
queryId: 0, |
|
amount: amount, |
|
owner: self.owner, |
|
responseAddress: self.owner |
|
}.toCell() |
|
}); |
|
} |
|
|
|
bounced(msg: Slice) { |
|
|
|
// Parse bounced message |
|
msg.skipBits(32); // 0xFFFFFFFF |
|
let op: Int = msg.loadUint(32); |
|
let queryId: Int = msg.loadUint(64); |
|
let jettonAmount: Int = msg.loadCoins(); |
|
require(op == 0x178d4519 || op == 0x7bdd97de, "Invalid bounced message"); |
|
|
|
// Update balance |
|
self.balance = self.balance + jettonAmount; |
|
} |
|
|
|
get fun get_wallet_data(): JettonWalletData { |
|
return JettonWalletData{ |
|
balance: self.balance, |
|
owner: self.owner, |
|
master: self.master, |
|
walletCode: (initOf TONBWallet(self.master, self.owner)).code |
|
}; |
|
} |
|
}
|
|
|