-
Notifications
You must be signed in to change notification settings - Fork 112
/
payouts.tact
119 lines (97 loc) · 3.28 KB
/
payouts.tact
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import "@stdlib/ownable";
message CanPayout {
amount: Int;
}
message CanPayoutResponse {
amount: Int;
address: Address;
ok: Bool;
}
contract Beacon with Ownable {
master: Address;
owner: Address;
completed: Bool;
init(master: Address, owner: Address) {
self.master = master;
self.owner = owner;
self.completed = false;
}
receive(msg: CanPayout) {
// Check context
let ctx: Context = context();
require(ctx.sender == self.master, "Invalid sender");
// Reserve funds
nativeReserve(ton("0.1"), ReserveExact);
// Send response
if (self.completed) {
self.completed = true;
self.reply(CanPayoutResponse{ok: true, amount: msg.amount, address: self.owner}.toCell());
} else {
self.reply(CanPayoutResponse{ok: false, amount: msg.amount, address: self.owner}.toCell());
}
}
bounced(msg: Slice) {
// Reset completed flag is our message bounced
self.completed = false;
}
}
contract Payouts with OwnableTransferable {
owner: Address;
publicKey: Int;
init(owner: Address, publicKey: Int) {
self.owner = owner;
self.publicKey = publicKey;
}
receive(msg: String) {
// Check context
let ctx: Context = context();
require(ctx.value >= ton("1"), "Invalid value");
// Parse message
let data: Slice = msg.fromBase64();
let amount: Int = data.loadCoins();
let signature: Slice = data.loadBits(512);
// Verify signature
let dataToSign: Builder = beginCell();
dataToSign = dataToSign.storeAddress(ctx.sender);
dataToSign = dataToSign.storeCoins(amount);
let hash: Int = dataToSign.asCell().hash();
require(checkSignature(hash, signature, self.publicKey), "Invalid signature");
// Request funds transfer
let init: StateInit = initOf Beacon(myAddress(), ctx.sender);
let address: Address = contractAddress(init);
send(SendParameters{
to: address,
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
bounce: true,
body: CanPayout{amount: amount}.toCell()
});
}
receive(msg: CanPayoutResponse) {
// Check context
let ctx: Context = context();
let init: StateInit = initOf Beacon(myAddress(), msg.address);
let address: Address = contractAddress(init);
require(ctx.sender == address, "Invalid sender");
if (msg.ok) {
// Check that we have enough funds
require(myBalance() - ctx.value - ton("1") - msg.amount > 0, "Invalid balance");
// Send response
send(SendParameters{
to: msg.address,
value: msg.amount,
mode: SendRemainingValue | SendIgnoreErrors,
bounce: false,
body: "Success".asComment()
});
} else {
send(SendParameters{
to: msg.address,
value: 0,
mode: SendRemainingValue | SendIgnoreErrors,
bounce: false,
body: "Already paid".asComment()
});
}
}
}