@aurigami/sdk 1.2.6 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ import { BlockchainEntityRead } from "./BlockchainEntity";
2
+ import { NetworkConnection } from "./types";
3
+ import { AuToken } from "@aurigami/contracts/typechain";
4
+ import { BigNumber as BN } from "ethers";
5
+ declare type SimpleTransfer = {
6
+ from: string;
7
+ to: string;
8
+ amount: BN;
9
+ blockNumber: number;
10
+ };
11
+ export declare class TransferEventQuery extends BlockchainEntityRead {
12
+ auToken: AuToken;
13
+ constructor(tokenAddr: string, networkConnection: NetworkConnection);
14
+ queryERC20TransfersOf(address: string, fromBlock: number, toBlock: number): Promise<SimpleTransfer[]>;
15
+ queryERC20BalanceAt(address: string, endBlock: number): Promise<BN>;
16
+ }
17
+ export {};
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.2.6",
2
+ "version": "1.3.1",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -211,7 +211,7 @@ export class MoneyMarketRead extends BlockchainEntityRead {
211
211
 
212
212
  private getDepositNEARRewardPerWeek(): TokenAmount {
213
213
  const NEARToken = new Token(networkAddresses.tokens.WNEAR, getDecimal(networkAddresses.tokens.WNEAR));
214
- const rewardStopTime = 1649858400;
214
+ const rewardStopTime = 1649253600;
215
215
  if (isSameAddress(this.underlying.address, networkAddresses.tokens.USDC) && getCurrentTimestamp() <= rewardStopTime) {
216
216
  return new TokenAmount(NEARToken, "1250", false);
217
217
  } else {
@@ -221,7 +221,7 @@ export class MoneyMarketRead extends BlockchainEntityRead {
221
221
 
222
222
  private getBorrowNEARRewardPerWeek(): TokenAmount {
223
223
  const NEARToken = new Token(networkAddresses.tokens.WNEAR, getDecimal(networkAddresses.tokens.WNEAR));
224
- const rewardStopTime = 1649858400;
224
+ const rewardStopTime = 1649253600;
225
225
  if (isSameAddress(this.underlying.address, networkAddresses.tokens.USDC) && getCurrentTimestamp() <= rewardStopTime) {
226
226
  return new TokenAmount(NEARToken, "3750", false);
227
227
  } else {
@@ -0,0 +1,229 @@
1
+ import { Provider } from "@ethersproject/abstract-provider";
2
+ import { BlockchainEntity, BlockchainEntityRead } from "./BlockchainEntity";
3
+ import { NetworkConnection } from "./types";
4
+ import { BigNumber as BN } from "ethers";
5
+ import { TransferEventQuery } from "./transfer-event-query";
6
+ import { AIRDROP_START_TIMESTAMP, AIRDROP_KEEP_THRESHOLD, AIRDROP_END_TIMESTAMP } from "./constants";
7
+ import { getBlockBeforeTimestamp, getCurrentTimestamp } from "./helpers";
8
+ import AIRDROP_AUTOKEN_INFO from "./airdrop_misc/auTokensInfo.json"
9
+ import AIRDROP_WHITELIST_ADDRESSES from "./airdrop_misc/whitelist.json"
10
+
11
+ type AirdropUnderlyingInfo = {
12
+ minDeposit: BN,
13
+ }
14
+
15
+ type AirdropAuTokenInfo = {
16
+ address: string,
17
+ exchangeRate: BN,
18
+ deploymentBlock: number,
19
+ underlying: AirdropUnderlyingInfo
20
+ }
21
+
22
+ class AirdropSettings {
23
+ private static _instance: AirdropSettings;
24
+
25
+ airdropStartBlock: number = 0;
26
+ airdropEndBlock: number = 0;
27
+ airdropStartTimestamp: number = AIRDROP_START_TIMESTAMP;
28
+ airdropEndTimestamp: number = AIRDROP_END_TIMESTAMP;
29
+ airdropThreshold: number = AIRDROP_KEEP_THRESHOLD;
30
+ private constructor() {}
31
+
32
+ public static async getSettings(provider: Provider): Promise<AirdropSettings> {
33
+ if (this._instance)
34
+ return this._instance;
35
+
36
+ let settings: AirdropSettings = new AirdropSettings();
37
+
38
+ settings.airdropStartBlock = await getBlockBeforeTimestamp(
39
+ provider,
40
+ settings.airdropStartTimestamp,
41
+ 63317969, //block number at the time I was writing this line, it's sure to be before the start of the airdrop
42
+ );
43
+
44
+ settings.airdropEndBlock = await getBlockBeforeTimestamp(
45
+ provider,
46
+ settings.airdropEndTimestamp,
47
+ settings.airdropStartBlock,
48
+ );
49
+
50
+ this._instance = settings;
51
+ return settings;
52
+ }
53
+ }
54
+
55
+ class AirdropAuTokenKeepTracker extends BlockchainEntityRead {
56
+ private _transferQuery: TransferEventQuery;
57
+ private _airdropAuTokenInfo: AirdropAuTokenInfo;
58
+ public constructor(networkConnection: NetworkConnection, airdropAuTokenInfo: AirdropAuTokenInfo) {
59
+ super(networkConnection);
60
+ this._transferQuery = new TransferEventQuery(airdropAuTokenInfo.address, networkConnection);
61
+ this._airdropAuTokenInfo = airdropAuTokenInfo;
62
+
63
+ // exchangeRate = 102% * exchangeRate, see why in the comment of _toUnderlyingValue
64
+ this._airdropAuTokenInfo.exchangeRate = this._airdropAuTokenInfo.exchangeRate.add(
65
+ this._airdropAuTokenInfo.exchangeRate.div(50)
66
+ )
67
+ }
68
+
69
+ /**
70
+ * Convert the given amount of auToken to the underlying value with the stored exchange rate
71
+ *
72
+ * Why we need to do this?
73
+ *
74
+ * By transfer event, we cannot know the exact underlying, the only
75
+ * info that we can keep track of via transfer is event is the auToken amount. So we need to
76
+ * convert it to the underlying value with the stored exchange rate.
77
+ *
78
+ * However, we cannot just simply use auTokenAmount * exchangeRate, because the exchange rate
79
+ * is changing over time. As advice of the contract team, use fixed exchangeRate * 102% is good enough.
80
+ *
81
+ */
82
+ private _toUnderlyingValue(auTokenAmount: BN): BN {
83
+ return auTokenAmount.mul(
84
+ this._airdropAuTokenInfo.exchangeRate
85
+ ).div(BN.from(10).pow(18));
86
+ }
87
+
88
+ /**
89
+ * Check if the user has been deposit at least (minDeposit) and keep it for
90
+ * more than AIRDROP_KEEP_THRESHOLD milliseconds
91
+ *
92
+ * How it works:
93
+ * Whenever the user balance is exceed minDeposit, we will record the timestamp,
94
+ * and when the balance is below minDeposit, we will compare with the saved timestamp to see
95
+ * whether it has been keep for more than AIRDROP_KEEP_THRESHOLD milliseconds.
96
+ *
97
+ */
98
+ public async isEligible(address: string): Promise<boolean> {
99
+ const settings = await AirdropSettings.getSettings(this._networkConnection.provider);
100
+ const minDeposit = this._airdropAuTokenInfo.underlying.minDeposit;
101
+
102
+ // Get user balance at the time of Airdrop start
103
+ let balance = await this._transferQuery.queryERC20BalanceAt(
104
+ address,
105
+ settings.airdropStartBlock - 1
106
+ );
107
+
108
+ const [BELOW, ABOVE] = [false, true];
109
+ let flag = BELOW;
110
+ // variable to store the last timestamp that, from it to "current" timestamp,
111
+ // the balance is always above minDeposit
112
+ let lastEligibleBalanceTimestamp = 0;
113
+
114
+ if (this._toUnderlyingValue(balance).gte(minDeposit)) {
115
+ lastEligibleBalanceTimestamp = settings.airdropStartTimestamp;
116
+ flag = ABOVE;
117
+ }
118
+
119
+ let events = await this._transferQuery.queryERC20TransfersOf(
120
+ address,
121
+ settings.airdropStartBlock,
122
+ settings.airdropEndBlock
123
+ );
124
+
125
+ for (let { from, to, amount, blockNumber } of events) {
126
+ if (from == address) {
127
+ balance = balance.sub(amount);
128
+ }
129
+ if (to == address) {
130
+ balance = balance.add(amount);
131
+ }
132
+
133
+ // if it is different from the flag, that means the balance is changing
134
+ if (this._toUnderlyingValue(balance).gte(minDeposit) != flag) {
135
+ flag = !flag;
136
+ const timestamp = (await this._networkConnection.provider.getBlock(blockNumber)).timestamp;
137
+
138
+ // if this txn make the balance below the minDeposit,
139
+ // check whether it has been keep for more than AIRDROP_KEEP_THRESHOLD
140
+ if (flag == BELOW) {
141
+ if (timestamp - lastEligibleBalanceTimestamp >= settings.airdropThreshold) {
142
+ return true;
143
+ }
144
+ lastEligibleBalanceTimestamp = 0;
145
+ }
146
+ else {
147
+ // record the timestamp when the balance is above minDeposit
148
+ lastEligibleBalanceTimestamp = timestamp;
149
+ }
150
+ }
151
+ }
152
+
153
+ // if after the last txn, the balance is still above minDeposit,
154
+ // we should check from the last timestamp to "now"
155
+ if (flag == ABOVE) {
156
+ const timestamp = Math.min(settings.airdropEndTimestamp, getCurrentTimestamp());
157
+ return timestamp - lastEligibleBalanceTimestamp >= settings.airdropThreshold;
158
+ }
159
+
160
+ return false;
161
+ }
162
+ }
163
+
164
+ export class AirdropRead extends BlockchainEntityRead {
165
+ private _whitelistedAddresses: Set<string>;
166
+ private keepTrackers: AirdropAuTokenKeepTracker[] = [];
167
+ public constructor(networkConnection: NetworkConnection) {
168
+ super(networkConnection);
169
+
170
+ this._whitelistedAddresses = new Set(AIRDROP_WHITELIST_ADDRESSES as string[]);
171
+
172
+ let auTokens: any = AIRDROP_AUTOKEN_INFO;
173
+
174
+ for (let auToken in auTokens) {
175
+ let { address, exchangeRate, deploymentBlock, underlying } = auTokens[auToken];
176
+
177
+ let airdropInfo: AirdropAuTokenInfo = {
178
+ address: address,
179
+ exchangeRate: BN.from(exchangeRate),
180
+ deploymentBlock: parseInt(deploymentBlock),
181
+ underlying: {
182
+ minDeposit: BN.from(underlying.minDeposit),
183
+ }
184
+ }
185
+
186
+ this.keepTrackers.push(
187
+ new AirdropAuTokenKeepTracker(
188
+ networkConnection,
189
+ airdropInfo
190
+ )
191
+ )
192
+ }
193
+ }
194
+
195
+ public countWhitelistedAddresses(): number {
196
+ return this._whitelistedAddresses.size;
197
+ }
198
+
199
+ public isWhitelisted(user: string): boolean {
200
+ return this._whitelistedAddresses.has(user);
201
+ }
202
+
203
+ public async hasCompletedChallenge(user: string): Promise<boolean> {
204
+ const settings = await AirdropSettings.getSettings(this._networkConnection.provider);
205
+
206
+ if (getCurrentTimestamp() < settings.airdropStartTimestamp) {
207
+ return false;
208
+ }
209
+
210
+ if (!this.isWhitelisted(user)) {
211
+ return false;
212
+ }
213
+
214
+ // iterate for all the market and check if the user has completed the challenge
215
+ return (await Promise.all(this.keepTrackers.map(async (keepTracker) => {
216
+ return keepTracker.isEligible(user);
217
+ }))).includes(true);
218
+ }
219
+ }
220
+
221
+ export class Airdrop extends BlockchainEntity {
222
+ constructor() {
223
+ super();
224
+ }
225
+ public read(networkConnection: NetworkConnection): AirdropRead {
226
+ return new AirdropRead(networkConnection);
227
+ }
228
+
229
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "auUSDC": {
3
+ "address": "0x4f0d864b1ABf4B701799a0b30b57A22dFEB5917b",
4
+ "exchangeRate": "200810680770707",
5
+ "deploymentBlock": "60501576",
6
+ "underlying": {
7
+ "minDeposit": "1000000000"
8
+ }
9
+ },
10
+ "auETH": {
11
+ "address": "0xca9511B610bA5fc7E311FDeF9cE16050eE4449E9",
12
+ "exchangeRate": "200390813218617347858934298",
13
+ "deploymentBlock": "60501625",
14
+ "underlying": {
15
+ "minDeposit": "300000000000000000"
16
+ }
17
+ },
18
+ "auWBTC": {
19
+ "address": "0xCFb6b0498cb7555e7e21502E0F449bf28760Adbb",
20
+ "exchangeRate": "20050472926613996",
21
+ "deploymentBlock": "60501670",
22
+ "underlying": {
23
+ "minDeposit": "2000000"
24
+ }
25
+ },
26
+ "auUSDT": {
27
+ "address": "0xaD5A2437Ff55ed7A8Cad3b797b3eC7c5a19B1c54",
28
+ "exchangeRate": "200868369820223",
29
+ "deploymentBlock": "60501723",
30
+ "underlying": {
31
+ "minDeposit": "1000000000"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,4 @@
1
+ 0x2b285e1b49ba0cb6f71d8b0d9cafdfbf9868fda9
2
+ 0xe8e9a0a2571299a0dabcaae98608352faf533e6a
3
+ 0xb3539af6596d8e08f75e96452d92bc17e3cdffc0
4
+ 0x0c5a5bd45078916ff5ff3acafeb19fe96fd747dc