-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDeFiChain.gs
318 lines (273 loc) · 9.55 KB
/
DeFiChain.gs
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
/**
* Get data from the DeFiChain Blockchain
*
* @author Michael Fuchs - derfuchs <[email protected]>
*/
/**
* Some config values for convenient access.
*/
const config = {
"apiUrls": {
//"general": "https://api.defichain.io/v1/",
"general": "https://dexprice.defichain-masternode-monitor.com/v1/",
"mainnet": "http://mainnet-api.defichain.io/api/DFI/mainnet/",
},
"fractions": 100000000, // parts in which 1 DFI can be split up, similar to BTC <-> Satoshis
"cachingTime": 10 // in Minutes
};
// -----------------------------------------------------------
/**
* Calculate whole DFI from fractional number
* ... which is a fancy term for dividing it by 100 mio.
*
* @param {number} amount The Amount of DFI fractions to be converted to whole DFI
*/
function fractionsToDfi(amount)
{
return parseFloat(amount) / config.fractions
}
// -----------------------------------------------------------
/**
* Send a request to one of the DeFiChain APIs and store the result in the cache.
*
* @param {"/resource/path"} resource Something like "address/8RUNjYgCHkT56t4C38YaaDvUQcY4HozdcD/balance"
* @param {"general | mainnet"} apiType There are multiple DeFiChain-APIs for different purpose. Have a look at https://defichain-wiki.com/wiki/API.
* @return Parsed JSON data as an object
*/
function callDefiChainApi(resource, apiType = "mainnet")
{
url = config.apiUrls[apiType] + resource
// fetch data
try {
// initialize some stuff
var data = {};
const CACHE_KEY = "DEFICHAIN__" + MD5(url)
var cache = CacheService.getUserCache()
// first check if there's a cached version available
var cached = cache.get(CACHE_KEY);
if (cached && cached != null && cached.length > 1) {
data = JSON.parse(cached)
}
// else, fetch it from API and cache it
else {
// send request
var response = UrlFetchApp.fetch(url, {muteHttpExceptions: true, validateHttpsCertificates: true})
data = JSON.parse(response.getContentText())
// if request response is valid, store it in the cache
if (response && response.getResponseCode() == 200 && data.length > 1 && data.length < 99900) {
cache.put(CACHE_KEY, response.getContentText(), config.cachingTime)
}
}
// return the data
return data
}
catch (e) {
throw new Error(e.message)
}
}
// -----------------------------------------------------------
/**
* Returns the current balance of a DeFiChain address in DFI
*
* @param {"DFI_ADDRESS"} address Something like "8RUNjYgCHkT56t4C38YaaDvUQcY4HozdcD"
* @param {"Empty cell reference"} refresh_cell ONLY on 2nd argument. Reference an empty cell and change its content to force refresh the rates.
* @return The current balance of this particular address. Will return 0 even if address does not exist.
* @customfunction
*/
function DEFICHAIN_ADDRESS_BALANCE(address, refresh_cell)
{
// sanitize input
address = (address + "") || "";
try {
data = callDefiChainApi("/address/" + address + "/balance")
return fractionsToDfi(data["balance"])
}
catch (e) {
throw new Error(e.message)
}
}
// -----------------------------------------------------------
/**
* Returns the current balance of a DeFiChain address in DFI
*
* @param {"block_height | difficulty | median_time | max_supply | current_total_supply | current_circulating_supply | current_foundation_supply | current_community_supply"} name
* @param {"Empty cell reference"} refresh_cell ONLY on 2nd argument. Reference an empty cell and change its content to force refresh the rates.
* @return the requested data key from DeFiChain's info endpoint from it's general API
* @customfunction
*/
function DEFICHAIN_INFO(name, refresh_cell)
{
// sanitize input
name = (name + "") || "";
try {
// some stuff
const data = callDefiChainApi("stats", "general")
var result = null
switch (name) {
case "block_height":
result = data.blockHeight
break;
case "difficulty":
result = data.difficulty
break;
case "median_time":
result = data.medianTime
break;
case "max_supply":
result = data.tokens.max
break;
case "current_total_supply":
result = data.supply.total
break;
case "current_circulating_supply":
result = data.supply.circilation
break;
case "current_foundation_supply":
result = data.supply.foundation
break;
case "current_community_supply":
result = data.supply.community
break;
}
return result;
}
catch (e) {
throw new Error(e.message)
}
}
// -----------------------------------------------------------
/**
* Returns the current price for one DFI in that particular coin
*
* @param {"USDT | BTC | ETH | BCH | LTC | DOGE"} coin Symbol of a supported coin
* @param {"Empty cell reference"} refresh_cell ONLY on 2nd argument. Reference an empty cell and change its content to force refresh the rates.
* @return The current price for one DFI in that particular coin
* @customfunction
*/
function DEFICHAIN_PRICE(coinSymbol, refresh_cell)
{
// sanitize input
coinSymbol = (coinSymbol + "") || "";
try {
const data = callDefiChainApi("listswaps", "general")
const pair = coinSymbol.toUpperCase() + "_DFI"
if (!(pair in data)) {
throw new Error("Unknown coin '" + coinSymbol + "'")
}
return Number.parseFloat(data[pair].last_price).toFixed(8)
}
catch (e) {
throw new Error(e.message)
}
}
// -----------------------------------------------------------
/**
* Returns the current count of minted blocks by this collateral address
*
* @param {"DFI_STAKING_COLLATERAL_ADDRESS"} address Something like "8RUNjYgCHkT56t4C38YaaDvUQcY4HozdcD"
* @param {"Empty cell reference"} refresh_cell ONLY on 2nd argument. Reference an empty cell and change its content to force refresh the rates.
* @return The current count of minted blocks by this collateral address.
* @customfunction
*/
function DEFICHAIN_MINTED_BLOCKS(address, refresh_cell)
{
// sanitize input
address = (address + "") || "";
try {
const data = callDefiChainApi("/address/" + address + "/txs")
let counter = 0
data.forEach(function(tx) {
if (tx.coinbase) {
counter++
}
})
return counter
}
catch (e) {
throw new Error(e.message)
}
}
// -----------------------------------------------------------
/**
* https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d
*
* ------------------------------------------
* MD5 function for GAS(GoogleAppsScript)
*
* You can get a MD5 hash value and even a 4digit short Hash value of a string.
* ------------------------------------------
* Usage1:
* `=MD5("YourStringToHash")`
* or
* `=MD5( A1 )` with the same string at A1 cell
* result:
* `FCE7453B7462D9DE0C56AFCCFB756193`.
* For your sure-ness you can verify it in your terminal as below.
* `$ md5 -s "YourStringToHash"`
* Usage2:
* `=MD5("YourStringToHash", true)` for short Hash
* result:
* `6MQH`
* Note that it has more conflict probability.
*
* How to install:
* Copy the scipt, pase it at [Tools]-[Script Editor]-[<YourProject>]
* or go https://script.google.com and paste it.
* For more details go:
* https://developers.google.com/apps-script/articles/
* Latest version:
* https://gist.github.com/dotysan/36b99217fdc958465b62f84f66903f07
* Author/Collaborator/Contributor:
* KEINOS @ https://github.com/keinos
* Alex Ivanov @ https://github.com/contributorpw
+ Curtis Doty @ https://github.com/dotysan
* Reference and thanks to:
* https://stackoverflow.com/questions/7994410/hash-of-a-cell-text-in-google-spreadsheet
* https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d#gistcomment-3129967
* https://gist.github.com/dotysan/36b99217fdc958465b62f84f66903f07
* https://developers.google.com/apps-script/reference/utilities/utilities#computedigestalgorithm-value
* https://cloud.google.com/dataprep/docs/html/Logical-Operators_57344671
* ------------------------------------------
*
* @param {(string|Bytes[])} input The value to hash.
* @param {boolean} isShortMode Set true for 4 digit shortend hash, else returns usual MD5 hash.
* @return {string} The hashed input
* @customfunction
*
*/
function MD5( input, isShortMode )
{
var isShortMode = !!isShortMode; // Be sure to be bool
var txtHash = '';
var rawHash = Utilities.computeDigest(
Utilities.DigestAlgorithm.MD5,
input );
if ( ! isShortMode ) {
for ( i = 0; i < rawHash.length; i++ ) {
var hashVal = rawHash[i];
if ( hashVal < 0 ) {
hashVal += 256;
};
if ( hashVal.toString( 16 ).length == 1 ) {
txtHash += '0';
};
txtHash += hashVal.toString( 16 );
};
} else {
for ( j = 0; j < 16; j += 8 ) {
hashVal = ( rawHash[j] + rawHash[j+1] + rawHash[j+2] + rawHash[j+3] )
^ ( rawHash[j+4] + rawHash[j+5] + rawHash[j+6] + rawHash[j+7] );
if ( hashVal < 0 ) {
hashVal += 1024;
};
if ( hashVal.toString( 36 ).length == 1 ) {
txtHash += "0";
};
txtHash += hashVal.toString( 36 );
};
};
// change below to "txtHash.toUpperCase()" if needed
return txtHash;
}
// -----------------------------------------------------------
// -----------------------------------------------------------