-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathxpr-reward-pool.contract.ts
131 lines (121 loc) · 5.23 KB
/
xpr-reward-pool.contract.ts
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
120
121
122
123
124
125
126
127
128
129
130
131
import {
Asset,
Contract,
Name,
Singleton,
TableStore,
check,
currentTimeSec,
getSender,
requireAuth,
requireRecipient,
} from 'proton-tsc';
import { Developer, Global } from './xpr-reward-pool.tables';
import { sendTransferToken } from 'proton-tsc/token';
import { XPR_CONTRACT, XPR_SYMBOL } from 'proton-tsc/system';
import { sendCanClaim } from './xpr-reward-pool.inline';
@contract
class XprRewardPool extends Contract {
contract: Name = this.receiver;
developers: TableStore<Developer> = new TableStore<Developer>(this.receiver);
globalSingleton: Singleton<Global> = new Singleton<Global>(this.receiver);
@action('regdev')
registerDev(account: Name): void {
requireAuth(this.contract);
const global = this.globalSingleton.get();
check(!global.claimEnabled, 'claiming period started, cannot add more devs');
global.devCount++;
this.globalSingleton.set(global, this.contract);
this.developers.store(new Developer(account), this.contract);
}
@action('removedev')
removeDev(account: Name): void {
requireAuth(this.contract);
const global = this.globalSingleton.get();
check(!global.claimEnabled, 'claiming period started, cannot remove devs');
const dev = this.developers.requireGet(account.N, 'unknown dev');
global.devCount--;
this.globalSingleton.set(global, this.contract);
this.developers.remove(dev);
}
// every developer MUST define the claim contract which is used to trigger the claim
@action('setcontract')
setContract(account: Name, claimContract: Name): void {
requireAuth(account);
const global = this.globalSingleton.get();
check(currentTimeSec() <= global.claimPeriodEnd, 'claim period expired');
const dev = this.developers.requireGet(account.N, 'unknown dev');
check(!dev.rewardClaimed, 'not allowed, reward already claimed');
dev.claimContract = claimContract;
this.developers.set(dev, this.contract);
}
@action('enableclaim')
enableClaimPeriod(): void {
requireAuth(this.contract);
const global = this.globalSingleton.get();
global.claimEnabled = true;
this.globalSingleton.set(global, this.contract);
}
// entrypoint for homework contract to be called via InlineAction
@action('initclaim')
initClaim(account: Name): void {
const global = this.globalSingleton.get();
check(global.claimEnabled, 'claim period not started');
check(currentTimeSec() <= global.claimPeriodEnd, 'claim period expired');
const dev = this.developers.requireGet(account.N, 'unknown dev');
// getSender() = claim contract (homework) that calls this contract via InlineAction
const claimContract = getSender();
check(dev.claimContract == claimContract, 'invalid sender contract');
// store timestamp in dev table
dev.timestamp = currentTimeSec();
this.developers.set(dev, this.contract);
// InlineAction to send notification to calling contract
sendCanClaim(this.contract, account, claimContract);
}
// action to send notification to claimContract
@action('canclaim')
canClaim(account: Name, claimContract: Name): void {
requireAuth(this.contract);
requireRecipient(claimContract);
}
@action('claimreward', notify)
onClaimReward(account: Name, timestamp: u64): void {
const dev = this.developers.requireGet(account.N, 'unknown dev');
check(!dev.rewardClaimed, 'reward already claimed');
// firstReceiver = claimContract that sent the notification
check(dev.claimContract == this.firstReceiver, 'invalid notifier contract');
check(timestamp == dev.timestamp && timestamp == currentTimeSec(), 'invalid timestamp');
const global = this.globalSingleton.get();
const equalSharePerDev = global.totalReward.amount / global.devCount;
dev.rewardClaimed = true;
this.developers.set(dev, this.contract);
global.claimCount++;
this.globalSingleton.set(global, this.contract);
sendTransferToken(
XPR_CONTRACT,
this.contract,
dev.account,
new Asset(equalSharePerDev, XPR_SYMBOL),
'SDC 2024 Workshop Homework Reward',
);
}
// return unclaimed funds of reward pool back to "xprgrants" contract
// can be called by anybody once the 30 days claim period is over
@action('returnxpr')
returnXpr(): void {
const global = this.globalSingleton.get();
check(currentTimeSec() > global.claimPeriodEnd, '30 day claim period still running');
check(!global.fundsReturned, 'funds already returned to xprgrants');
const equalSharePerDev = global.totalReward.amount / global.devCount;
const remainingAmount = global.totalReward.amount - equalSharePerDev * global.claimCount;
global.fundsReturned = true;
this.globalSingleton.set(global, this.contract);
sendTransferToken(
XPR_CONTRACT,
this.contract,
Name.fromString('xprgrants'),
new Asset(remainingAmount, XPR_SYMBOL),
'SDC 2024 Workshop: Return Unclaimed Funds',
);
}
}