@aurigami/sdk 1.6.0-no-src → 1.6.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.
Files changed (39) hide show
  1. package/dist/SDK.d.ts +9 -0
  2. package/dist/contracts/Multicall.d.ts +18 -0
  3. package/dist/contracts/Papermill.d.ts +8 -0
  4. package/dist/sdk.cjs.development.js +102841 -40
  5. package/dist/sdk.cjs.development.js.map +1 -1
  6. package/dist/sdk.cjs.production.min.js +1 -1
  7. package/dist/sdk.cjs.production.min.js.map +1 -1
  8. package/dist/sdk.esm.js +102841 -40
  9. package/dist/sdk.esm.js.map +1 -1
  10. package/package.json +4 -3
  11. package/src/SDK.ts +430 -0
  12. package/src/abis/Faucet.json +157 -0
  13. package/src/abis/IUniswapV2Pair.json +663 -0
  14. package/src/abis/Oracle.json +247 -0
  15. package/src/abis/dummy.json +3 -0
  16. package/src/consts/constants.ts +146 -0
  17. package/src/consts/decimals.ts +24 -0
  18. package/src/consts/deployments.ts +4 -0
  19. package/src/consts/dummy.ts +38 -0
  20. package/src/consts/index.ts +4 -0
  21. package/src/contracts/MoneyMarket.ts +510 -0
  22. package/src/contracts/Multicall.ts +55 -0
  23. package/src/contracts/Papermill.ts +271 -0
  24. package/src/contracts/Staking.ts +183 -0
  25. package/src/contracts/airdrop-lottery.ts +320 -0
  26. package/src/contracts/index.ts +4 -0
  27. package/src/entities/BlockchainEntity.ts +33 -0
  28. package/src/entities/index.ts +3 -0
  29. package/src/entities/token.ts +21 -0
  30. package/src/entities/tokenAmount.ts +42 -0
  31. package/src/helpers/aurora-api-helpers.ts +20 -0
  32. package/src/helpers/helpers.ts +97 -0
  33. package/src/helpers/index.ts +4 -0
  34. package/src/helpers/priceFetcher.ts +317 -0
  35. package/src/helpers/transfer-event-query.ts +70 -0
  36. package/src/index.ts +13 -0
  37. package/src/misc/airdrop_misc/auTokensInfo.json +34 -0
  38. package/src/misc/airdrop_misc/whitelist.json +102629 -0
  39. package/src/types/index.ts +106 -0
@@ -0,0 +1,320 @@
1
+ import AuriAirdropABI from '@aurigami/contracts/artifacts/contracts/AuriAirdrop.sol/AuriAirdrop.json';
2
+ import { AuriAirdrop } from '@aurigami/contracts/typechain';
3
+ import {
4
+ Provider,
5
+ TransactionResponse,
6
+ } from '@ethersproject/abstract-provider';
7
+ import { BigNumber as BN, Contract, utils } from 'ethers';
8
+ import * as consts from '../consts';
9
+ import {
10
+ BlockchainEntity,
11
+ BlockchainEntityRead,
12
+ Token,
13
+ TokenAmount,
14
+ } from '../entities';
15
+ import * as helpers from '../helpers';
16
+ import AIRDROP_AUTOKEN_INFO from '../misc/airdrop_misc/auTokensInfo.json';
17
+ import AIRDROP_WHITELIST_ADDRESSES from '../misc/airdrop_misc/whitelist.json';
18
+ import { Address, NetworkConnection } from '../types';
19
+
20
+ type AirdropUnderlyingInfo = {
21
+ minDeposit: BN;
22
+ };
23
+
24
+ type AirdropAuTokenInfo = {
25
+ address: string;
26
+ exchangeRate: BN;
27
+ deploymentBlock: number;
28
+ underlying: AirdropUnderlyingInfo;
29
+ };
30
+
31
+ class AirdropSettings {
32
+ private static _instance: AirdropSettings;
33
+
34
+ airdropStartBlock: number = 0;
35
+ airdropEndBlock: number = 0;
36
+ airdropStartTimestamp: number = consts.AIRDROP_START_TIMESTAMP;
37
+ airdropEndTimestamp: number = consts.AIRDROP_END_TIMESTAMP;
38
+ airdropThreshold: number = consts.AIRDROP_KEEP_THRESHOLD;
39
+ private constructor() {}
40
+
41
+ public static async getSettings(
42
+ provider: Provider
43
+ ): Promise<AirdropSettings> {
44
+ if (this._instance) return this._instance;
45
+
46
+ let settings: AirdropSettings = new AirdropSettings();
47
+
48
+ settings.airdropStartBlock = await helpers.getBlockBeforeTimestamp(
49
+ provider,
50
+ settings.airdropStartTimestamp
51
+ );
52
+
53
+ settings.airdropEndBlock = await helpers.getBlockBeforeTimestamp(
54
+ provider,
55
+ settings.airdropEndTimestamp
56
+ );
57
+
58
+ this._instance = settings;
59
+ return settings;
60
+ }
61
+ }
62
+
63
+ class AirdropAuTokenKeepTracker extends BlockchainEntityRead {
64
+ private _transferQuery: helpers.TransferEventQuery;
65
+ private _airdropAuTokenInfo: AirdropAuTokenInfo;
66
+ public constructor(
67
+ networkConnection: NetworkConnection,
68
+ airdropAuTokenInfo: AirdropAuTokenInfo
69
+ ) {
70
+ super(networkConnection);
71
+ this._transferQuery = new helpers.TransferEventQuery(
72
+ airdropAuTokenInfo.address,
73
+ networkConnection
74
+ );
75
+ this._airdropAuTokenInfo = airdropAuTokenInfo;
76
+
77
+ // exchangeRate = 102% * exchangeRate, see why in the comment of _toUnderlyingValue
78
+ this._airdropAuTokenInfo.exchangeRate =
79
+ this._airdropAuTokenInfo.exchangeRate.add(
80
+ this._airdropAuTokenInfo.exchangeRate.div(50)
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Convert the given amount of auToken to the underlying value with the stored exchange rate
86
+ *
87
+ * Why we need to do this?
88
+ *
89
+ * By transfer event, we cannot know the exact underlying, the only
90
+ * info that we can keep track of via transfer is event is the auToken amount. So we need to
91
+ * convert it to the underlying value with the stored exchange rate.
92
+ *
93
+ * However, we cannot just simply use auTokenAmount * exchangeRate, because the exchange rate
94
+ * is changing over time. As advice of the contract team, use fixed exchangeRate * 102% is good enough.
95
+ *
96
+ */
97
+ private _toUnderlyingValue(auTokenAmount: BN): BN {
98
+ return auTokenAmount
99
+ .mul(this._airdropAuTokenInfo.exchangeRate)
100
+ .div(BN.from(10).pow(18));
101
+ }
102
+
103
+ /**
104
+ * Check if the user has been deposit at least (minDeposit) and keep it for
105
+ * more than AIRDROP_KEEP_THRESHOLD milliseconds
106
+ *
107
+ * How it works:
108
+ * Whenever the user balance is exceed minDeposit, we will record the timestamp,
109
+ * and when the balance is below minDeposit, we will compare with the saved timestamp to see
110
+ * whether it has been keep for more than AIRDROP_KEEP_THRESHOLD milliseconds.
111
+ *
112
+ */
113
+ public async isEligible(address: string): Promise<boolean> {
114
+ const settings = await AirdropSettings.getSettings(
115
+ this._networkConnection.provider
116
+ );
117
+ const minDeposit = this._airdropAuTokenInfo.underlying.minDeposit;
118
+
119
+ // Get user balance at the time of Airdrop start
120
+ let balance = await this._transferQuery.queryERC20BalanceAt(
121
+ address,
122
+ settings.airdropStartBlock - 1
123
+ );
124
+
125
+ const [BELOW, ABOVE] = [false, true];
126
+ let flag = BELOW;
127
+ // variable to store the last timestamp that, from it to "current" timestamp,
128
+ // the balance is always above minDeposit
129
+ let lastEligibleBalanceTimestamp = 0;
130
+
131
+ if (this._toUnderlyingValue(balance).gte(minDeposit)) {
132
+ lastEligibleBalanceTimestamp = settings.airdropStartTimestamp;
133
+ flag = ABOVE;
134
+ }
135
+
136
+ let events = await this._transferQuery.queryERC20TransfersOf(
137
+ address,
138
+ settings.airdropStartBlock,
139
+ settings.airdropEndBlock
140
+ );
141
+
142
+ for (let { from, to, amount, blockNumber } of events) {
143
+ if (helpers.isSameAddress(from, address)) {
144
+ balance = balance.sub(amount);
145
+ }
146
+ if (helpers.isSameAddress(to, address)) {
147
+ balance = balance.add(amount);
148
+ }
149
+
150
+ // if it is different from the flag, that means the balance is changing
151
+ if (this._toUnderlyingValue(balance).gte(minDeposit) != flag) {
152
+ flag = !flag;
153
+ const timestamp = (
154
+ await this._networkConnection.provider.getBlock(blockNumber)
155
+ ).timestamp;
156
+
157
+ // if this txn make the balance below the minDeposit,
158
+ // check whether it has been keep for more than AIRDROP_KEEP_THRESHOLD
159
+ if (flag == BELOW) {
160
+ if (
161
+ timestamp - lastEligibleBalanceTimestamp >=
162
+ settings.airdropThreshold
163
+ ) {
164
+ return true;
165
+ }
166
+ lastEligibleBalanceTimestamp = 0;
167
+ } else {
168
+ // record the timestamp when the balance is above minDeposit
169
+ lastEligibleBalanceTimestamp = timestamp;
170
+ }
171
+ }
172
+ }
173
+
174
+ // if after the last txn, the balance is still above minDeposit,
175
+ // we should check from the last timestamp to "now"
176
+ if (flag == ABOVE) {
177
+ const timestamp = Math.min(
178
+ settings.airdropEndTimestamp,
179
+ helpers.getCurrentTimestamp()
180
+ );
181
+ return (
182
+ timestamp - lastEligibleBalanceTimestamp >= settings.airdropThreshold
183
+ );
184
+ }
185
+
186
+ return false;
187
+ }
188
+ }
189
+
190
+ export class AirdropRead extends BlockchainEntityRead {
191
+ protected _airDrop: AuriAirdrop;
192
+ private _whitelistedAddresses: Set<string>;
193
+ private keepTrackers: AirdropAuTokenKeepTracker[] = [];
194
+ public constructor(networkConnection: NetworkConnection) {
195
+ super(networkConnection);
196
+ this._airDrop = new Contract(
197
+ consts.networkAddresses.misc.AURI_AIRDROP,
198
+ AuriAirdropABI.abi,
199
+ networkConnection.provider
200
+ ) as AuriAirdrop;
201
+
202
+ this._whitelistedAddresses = new Set(
203
+ (AIRDROP_WHITELIST_ADDRESSES as string[]).map((e) =>
204
+ e.toLocaleLowerCase()
205
+ )
206
+ );
207
+
208
+ let auTokens: any = AIRDROP_AUTOKEN_INFO;
209
+
210
+ for (let auToken in auTokens) {
211
+ let { address, exchangeRate, deploymentBlock, underlying } =
212
+ auTokens[auToken];
213
+
214
+ let airdropInfo: AirdropAuTokenInfo = {
215
+ address: address,
216
+ exchangeRate: BN.from(exchangeRate),
217
+ deploymentBlock: parseInt(deploymentBlock),
218
+ underlying: {
219
+ minDeposit: BN.from(underlying.minDeposit),
220
+ },
221
+ };
222
+
223
+ this.keepTrackers.push(
224
+ new AirdropAuTokenKeepTracker(networkConnection, airdropInfo)
225
+ );
226
+ }
227
+ }
228
+
229
+ public countWhitelistedAddresses(): number {
230
+ return this._whitelistedAddresses.size;
231
+ }
232
+
233
+ public isWhitelisted(user: string): boolean {
234
+ return this._whitelistedAddresses.has(user.toLocaleLowerCase());
235
+ }
236
+
237
+ public async hasCompletedChallenge(user: string): Promise<boolean> {
238
+ const settings = await AirdropSettings.getSettings(
239
+ this._networkConnection.provider
240
+ );
241
+
242
+ if (helpers.getCurrentTimestamp() < settings.airdropStartTimestamp) {
243
+ return false;
244
+ }
245
+
246
+ if (!this.isWhitelisted(user)) {
247
+ return false;
248
+ }
249
+
250
+ // iterate for all the market and check if the user has completed the challenge
251
+ return (
252
+ await Promise.all(
253
+ this.keepTrackers.map(async (keepTracker) => {
254
+ return keepTracker.isEligible(user);
255
+ })
256
+ )
257
+ ).includes(true);
258
+ }
259
+
260
+ /**
261
+ * Get redeemable rewards amount of user
262
+ */
263
+ public async getRedeemableReward(
264
+ campaign: string,
265
+ token: Address,
266
+ user: Address
267
+ ): Promise<TokenAmount> {
268
+ let tokenInstance: Token = new Token(token, helpers.getDecimal(token));
269
+
270
+ let rewards: BN = await this._airDrop.getRedeemableReward(
271
+ utils.formatBytes32String(campaign),
272
+ token,
273
+ user
274
+ );
275
+
276
+ return new TokenAmount(tokenInstance, rewards.toString());
277
+ }
278
+ }
279
+
280
+ export class AirdropReadWrite extends AirdropRead {
281
+ /**
282
+ * Transfer rewards from multiple campaigns to msg.sender
283
+ */
284
+ public async redeemMultiple(
285
+ campaigns: string[],
286
+ tokens: Address[]
287
+ ): Promise<TransactionResponse> {
288
+ helpers.assert(
289
+ campaigns.length == tokens.length,
290
+ 'campaigns and tokens must have the same length'
291
+ );
292
+ return this._airDrop.connect(this._networkConnection.signer!).redeem(
293
+ campaigns.map((e) => utils.formatBytes32String(e)),
294
+ tokens,
295
+ await this._networkConnection.signer!.getAddress()
296
+ );
297
+ }
298
+
299
+ /**
300
+ * Redeem reward from a single campaign
301
+ */
302
+ public async redeemSingle(
303
+ campaign: string,
304
+ token: Address
305
+ ): Promise<TransactionResponse> {
306
+ return this.redeemMultiple([campaign], [token]);
307
+ }
308
+ }
309
+
310
+ export class Airdrop extends BlockchainEntity {
311
+ constructor() {
312
+ super();
313
+ }
314
+ public read(networkConnection: NetworkConnection): AirdropRead {
315
+ return new AirdropRead(networkConnection);
316
+ }
317
+ public readWrite(networkConnection: NetworkConnection): AirdropReadWrite {
318
+ return new AirdropReadWrite(networkConnection);
319
+ }
320
+ }
@@ -0,0 +1,4 @@
1
+ export * from './airdrop-lottery';
2
+ export * from './MoneyMarket';
3
+ export * from './Papermill';
4
+ export * from './Staking';
@@ -0,0 +1,33 @@
1
+ import { Signer } from '@ethersproject/abstract-signer';
2
+ import { NetworkConnection } from '../types';
3
+
4
+ export class BlockchainEntityRead {
5
+ protected _networkConnection: NetworkConnection;
6
+ public constructor(networkConnection: NetworkConnection) {
7
+ this._networkConnection = networkConnection;
8
+ }
9
+ }
10
+
11
+ export class BlockchainEntityReadWrite extends BlockchainEntityRead {
12
+ public constructor(networkConnection: NetworkConnection) {
13
+ if (!(networkConnection.signer instanceof Signer)) {
14
+ throw Error(
15
+ 'Signer is not provided when constructing BlockchainEntityReadWrite'
16
+ );
17
+ }
18
+ super(networkConnection);
19
+ }
20
+ }
21
+
22
+ export class BlockchainEntity {
23
+ constructor() {}
24
+ public read(networkConnection: NetworkConnection): BlockchainEntityRead {
25
+ return new BlockchainEntityRead(networkConnection);
26
+ }
27
+
28
+ public readWrite(
29
+ networkConnection: NetworkConnection
30
+ ): BlockchainEntityReadWrite {
31
+ return new BlockchainEntityReadWrite(networkConnection);
32
+ }
33
+ }
@@ -0,0 +1,3 @@
1
+ export * from './BlockchainEntity';
2
+ export * from './token';
3
+ export * from './tokenAmount';
@@ -0,0 +1,21 @@
1
+ import { getDecimal } from '../helpers/helpers';
2
+ import { networkAddresses } from '../consts/constants';
3
+
4
+ export class Token {
5
+ public readonly address: string;
6
+ public readonly decimals: number;
7
+ public constructor(address: string, decimals: number) {
8
+ this.address = address.toLowerCase();
9
+ this.decimals = decimals;
10
+ }
11
+ }
12
+
13
+ export const PLYToken = new Token(
14
+ networkAddresses.tokens.PLY,
15
+ getDecimal(networkAddresses.tokens.PLY)
16
+ );
17
+
18
+ export const PLYWNEARToken = new Token(
19
+ networkAddresses.tokens.PLYWNEAR,
20
+ getDecimal(networkAddresses.tokens.PLYWNEAR)
21
+ );
@@ -0,0 +1,42 @@
1
+ import { Token } from './token';
2
+ import BigNumber from 'bignumber.js';
3
+ import { decimalFactor, getDecimal } from '../helpers/helpers';
4
+ import { Address } from '../types';
5
+
6
+ export class TokenAmount {
7
+ public readonly token: Token;
8
+ private rawAmnt: string;
9
+
10
+ public constructor(token: Token, amount: string, isRaw: boolean = true) {
11
+ if (isRaw) {
12
+ this.rawAmnt = amount;
13
+ } else {
14
+ this.rawAmnt = new BigNumber(amount)
15
+ .times(decimalFactor(token.decimals))
16
+ .toFixed(0);
17
+ }
18
+ this.token = token;
19
+ }
20
+
21
+ public formattedAmount(): string {
22
+ return new BigNumber(this.rawAmnt)
23
+ .div(decimalFactor(this.token.decimals))
24
+ .toString();
25
+ }
26
+
27
+ public rawAmount(): string {
28
+ return this.rawAmnt;
29
+ }
30
+
31
+ public static fromAddressAndAmount(
32
+ tokenAddress: Address,
33
+ amount: string,
34
+ isRaw: boolean = true
35
+ ): TokenAmount {
36
+ return new TokenAmount(
37
+ new Token(tokenAddress, getDecimal(tokenAddress)),
38
+ amount,
39
+ isRaw
40
+ );
41
+ }
42
+ }
@@ -0,0 +1,20 @@
1
+ import axios from 'axios';
2
+
3
+ const AURORA_API_BASE_URL = 'https://api.aurorascan.dev/api';
4
+
5
+ export async function getQuery(
6
+ module: string,
7
+ action: string,
8
+ params: Record<string, any> = {}
9
+ ): Promise<any> {
10
+ params = { ...params, module: module, action: action };
11
+
12
+ let resp = await axios.get(
13
+ AURORA_API_BASE_URL + '?' + new URLSearchParams(params),
14
+ {
15
+ headers: { 'Content-Type': 'application/json' },
16
+ }
17
+ );
18
+
19
+ return resp.data.result!;
20
+ }
@@ -0,0 +1,97 @@
1
+ import { Provider } from '@ethersproject/abstract-provider';
2
+ import BigNumber from 'bignumber.js';
3
+ import { BigNumber as BN, utils } from 'ethers';
4
+ import { getQuery as getAuroraAPIQuery } from './aurora-api-helpers';
5
+ import { decimalRecords } from '../consts/decimals';
6
+ import { Address } from '../types';
7
+
8
+ export function assert(condition: boolean, message: string = ''): void {
9
+ if (!condition) {
10
+ message = 'Assertion failed' + (message ? ': ' + message : '');
11
+ throw new Error(message);
12
+ }
13
+ }
14
+
15
+ export function formatObject(object: Object) {
16
+ return JSON.stringify(object, null, ' ');
17
+ }
18
+
19
+ export function decimalFactor(decimal: number) {
20
+ return BN.from(10).pow(decimal).toString();
21
+ }
22
+
23
+ export const isSameAddress = (
24
+ address1: Address,
25
+ address2: Address
26
+ ): boolean => {
27
+ return address1.toLowerCase() == address2.toLowerCase();
28
+ };
29
+
30
+ export const getCurrentTimestamp = (): number => {
31
+ return Math.trunc(Date.now() / 1000);
32
+ };
33
+
34
+ export function validateAndParseAddress(address: Address): Address {
35
+ try {
36
+ return utils.getAddress(address);
37
+ } catch (error) {
38
+ throw new Error('Invalid address: ' + address);
39
+ }
40
+ }
41
+
42
+ export function getDecimal(address: Address): number {
43
+ let addressLowercase = address.toLowerCase();
44
+ assert(
45
+ decimalRecords[addressLowercase] != undefined,
46
+ 'Decimal not found for ' + address
47
+ );
48
+ return decimalRecords[addressLowercase];
49
+ }
50
+
51
+ export function calcLMRewardApr(
52
+ rewardsValue: BigNumber,
53
+ totalStakeValue: BigNumber,
54
+ frequencyPerYear: number
55
+ ): BigNumber {
56
+ if (totalStakeValue.lte(0)) {
57
+ // avoid division by zero when there is no stake
58
+ return new BigNumber('999999999');
59
+ }
60
+ return rewardsValue.multipliedBy(frequencyPerYear).dividedBy(totalStakeValue);
61
+ }
62
+
63
+ export async function getBlockTimestamp(
64
+ provider: Provider,
65
+ blockNumber: number
66
+ ): Promise<number> {
67
+ const block = await provider.getBlock(blockNumber);
68
+ return block.timestamp;
69
+ }
70
+
71
+ /**
72
+ * Get the block number of the last block that has a timestamp before the given timestamp
73
+ * @param timestamp input timestamp
74
+ * @returns return the last block that its timestamp <= the give timestamp
75
+ * @note Check this API for more information: https://aurorascan.dev/apis#blocks
76
+ *
77
+ * This function is much faster than using binary search.
78
+ */
79
+ export async function getBlockBeforeTimestamp(
80
+ provider: Provider,
81
+ timestamp: number
82
+ ) {
83
+ let result = await getAuroraAPIQuery('block', 'getblocknobytime', {
84
+ timestamp: timestamp,
85
+ closest: 'before',
86
+ });
87
+
88
+ // In case the API return `Block timestamp too far in the future`
89
+ // use the last block number
90
+ return parseInt(result) || (await provider.getBlockNumber());
91
+ }
92
+
93
+ export function devLog(message?: any, ...optionalParams: any[]): void {
94
+ if ('production' !== process.env.NODE_ENV) {
95
+ console.log(message, ...optionalParams);
96
+ }
97
+ }
@@ -0,0 +1,4 @@
1
+ export * from './aurora-api-helpers';
2
+ export * from './helpers';
3
+ export * from './priceFetcher';
4
+ export * from './transfer-event-query';