@learncard/ethereum-plugin 1.1.24 → 1.1.26
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.
- package/README.md +12 -7
- package/dist/ethereum-plugin.cjs.development.cjs +7032 -7035
- package/dist/ethereum-plugin.cjs.development.cjs.map +4 -4
- package/dist/ethereum-plugin.cjs.production.min.cjs +3 -3
- package/dist/ethereum-plugin.cjs.production.min.cjs.map +4 -4
- package/dist/ethereum-plugin.esm.js +7027 -7030
- package/dist/ethereum-plugin.esm.js.map +3 -3
- package/dist/index.d.ts.map +1 -1
- package/package.json +58 -56
- package/src/erc20.abi.json +222 -0
- package/src/hardcodedTokens.ts +26 -0
- package/src/helpers.ts +63 -0
- package/src/index.ts +188 -0
- package/src/types.ts +41 -0
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAa,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,cAAc,EAAa,MAAM,SAAS,CAAC;AAWpE,cAAc,SAAS,CAAC;AAMxB;;GAEG;AACH,eAAO,MAAM,iBAAiB,kBACX,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,UAC3B,cAAc,KACvB,cA+JF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,57 +1,59 @@
|
|
|
1
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
|
-
}
|
|
2
|
+
"name": "@learncard/ethereum-plugin",
|
|
3
|
+
"version": "1.1.26",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/ethereum-plugin.esm.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"development": "./src/index.ts",
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/ethereum-plugin.esm.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node ./scripts/build.mjs && shx cp ./scripts/mixedEntypoint.js ./dist/index.cjs && tsc --p tsconfig.json && shx cp ./dist/index.d.ts ./dist/index.d.cts",
|
|
27
|
+
"test": "jest --passWithNoTests",
|
|
28
|
+
"test:watch": "jest --watch",
|
|
29
|
+
"test:coverage": "jest --silent --ci --coverage --coverageReporters=\"text\" --coverageReporters=\"text-summary\""
|
|
30
|
+
},
|
|
31
|
+
"author": "Learning Economy Foundation (www.learningeconomy.io)",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"homepage": "https://github.com/learningeconomy/LearnCard/tree/main/packages/plugins/ethereum/README.md",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/learningeconomy/LearnCard"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/learningeconomy/LearnCard/issues"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/jest": "^29.2.2",
|
|
43
|
+
"@types/node": "^17.0.31",
|
|
44
|
+
"aqu": "0.4.3",
|
|
45
|
+
"esbuild": "^0.27.1",
|
|
46
|
+
"esbuild-jest": "^0.5.0",
|
|
47
|
+
"esbuild-plugin-copy": "^1.3.0",
|
|
48
|
+
"jest": "^29.3.0",
|
|
49
|
+
"shx": "^0.3.4",
|
|
50
|
+
"ts-jest": "^29.0.3"
|
|
51
|
+
},
|
|
52
|
+
"types": "./dist/index.d.ts",
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@learncard/core": "workspace:*",
|
|
55
|
+
"@uniswap/default-token-list": "^4.1.0",
|
|
56
|
+
"ethers": "^5.6.9"
|
|
57
|
+
},
|
|
58
|
+
"sideEffects": false
|
|
59
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"constant": true,
|
|
4
|
+
"inputs": [],
|
|
5
|
+
"name": "name",
|
|
6
|
+
"outputs": [
|
|
7
|
+
{
|
|
8
|
+
"name": "",
|
|
9
|
+
"type": "string"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"payable": false,
|
|
13
|
+
"stateMutability": "view",
|
|
14
|
+
"type": "function"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"constant": false,
|
|
18
|
+
"inputs": [
|
|
19
|
+
{
|
|
20
|
+
"name": "_spender",
|
|
21
|
+
"type": "address"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "_value",
|
|
25
|
+
"type": "uint256"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"name": "approve",
|
|
29
|
+
"outputs": [
|
|
30
|
+
{
|
|
31
|
+
"name": "",
|
|
32
|
+
"type": "bool"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"payable": false,
|
|
36
|
+
"stateMutability": "nonpayable",
|
|
37
|
+
"type": "function"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"constant": true,
|
|
41
|
+
"inputs": [],
|
|
42
|
+
"name": "totalSupply",
|
|
43
|
+
"outputs": [
|
|
44
|
+
{
|
|
45
|
+
"name": "",
|
|
46
|
+
"type": "uint256"
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"payable": false,
|
|
50
|
+
"stateMutability": "view",
|
|
51
|
+
"type": "function"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"constant": false,
|
|
55
|
+
"inputs": [
|
|
56
|
+
{
|
|
57
|
+
"name": "_from",
|
|
58
|
+
"type": "address"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "_to",
|
|
62
|
+
"type": "address"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"name": "_value",
|
|
66
|
+
"type": "uint256"
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
"name": "transferFrom",
|
|
70
|
+
"outputs": [
|
|
71
|
+
{
|
|
72
|
+
"name": "",
|
|
73
|
+
"type": "bool"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"payable": false,
|
|
77
|
+
"stateMutability": "nonpayable",
|
|
78
|
+
"type": "function"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"constant": true,
|
|
82
|
+
"inputs": [],
|
|
83
|
+
"name": "decimals",
|
|
84
|
+
"outputs": [
|
|
85
|
+
{
|
|
86
|
+
"name": "",
|
|
87
|
+
"type": "uint8"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"payable": false,
|
|
91
|
+
"stateMutability": "view",
|
|
92
|
+
"type": "function"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"constant": true,
|
|
96
|
+
"inputs": [
|
|
97
|
+
{
|
|
98
|
+
"name": "_owner",
|
|
99
|
+
"type": "address"
|
|
100
|
+
}
|
|
101
|
+
],
|
|
102
|
+
"name": "balanceOf",
|
|
103
|
+
"outputs": [
|
|
104
|
+
{
|
|
105
|
+
"name": "balance",
|
|
106
|
+
"type": "uint256"
|
|
107
|
+
}
|
|
108
|
+
],
|
|
109
|
+
"payable": false,
|
|
110
|
+
"stateMutability": "view",
|
|
111
|
+
"type": "function"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"constant": true,
|
|
115
|
+
"inputs": [],
|
|
116
|
+
"name": "symbol",
|
|
117
|
+
"outputs": [
|
|
118
|
+
{
|
|
119
|
+
"name": "",
|
|
120
|
+
"type": "string"
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"payable": false,
|
|
124
|
+
"stateMutability": "view",
|
|
125
|
+
"type": "function"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"constant": false,
|
|
129
|
+
"inputs": [
|
|
130
|
+
{
|
|
131
|
+
"name": "_to",
|
|
132
|
+
"type": "address"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"name": "_value",
|
|
136
|
+
"type": "uint256"
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"name": "transfer",
|
|
140
|
+
"outputs": [
|
|
141
|
+
{
|
|
142
|
+
"name": "",
|
|
143
|
+
"type": "bool"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
146
|
+
"payable": false,
|
|
147
|
+
"stateMutability": "nonpayable",
|
|
148
|
+
"type": "function"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"constant": true,
|
|
152
|
+
"inputs": [
|
|
153
|
+
{
|
|
154
|
+
"name": "_owner",
|
|
155
|
+
"type": "address"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"name": "_spender",
|
|
159
|
+
"type": "address"
|
|
160
|
+
}
|
|
161
|
+
],
|
|
162
|
+
"name": "allowance",
|
|
163
|
+
"outputs": [
|
|
164
|
+
{
|
|
165
|
+
"name": "",
|
|
166
|
+
"type": "uint256"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
"payable": false,
|
|
170
|
+
"stateMutability": "view",
|
|
171
|
+
"type": "function"
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"payable": true,
|
|
175
|
+
"stateMutability": "payable",
|
|
176
|
+
"type": "fallback"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"anonymous": false,
|
|
180
|
+
"inputs": [
|
|
181
|
+
{
|
|
182
|
+
"indexed": true,
|
|
183
|
+
"name": "owner",
|
|
184
|
+
"type": "address"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
"indexed": true,
|
|
188
|
+
"name": "spender",
|
|
189
|
+
"type": "address"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"indexed": false,
|
|
193
|
+
"name": "value",
|
|
194
|
+
"type": "uint256"
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
"name": "Approval",
|
|
198
|
+
"type": "event"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"anonymous": false,
|
|
202
|
+
"inputs": [
|
|
203
|
+
{
|
|
204
|
+
"indexed": true,
|
|
205
|
+
"name": "from",
|
|
206
|
+
"type": "address"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"indexed": true,
|
|
210
|
+
"name": "to",
|
|
211
|
+
"type": "address"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"indexed": false,
|
|
215
|
+
"name": "value",
|
|
216
|
+
"type": "uint256"
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
"name": "Transfer",
|
|
220
|
+
"type": "event"
|
|
221
|
+
}
|
|
222
|
+
]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const hardcodedTokens = [
|
|
2
|
+
{
|
|
3
|
+
name: 'USDCoin',
|
|
4
|
+
address: '0x07865c6e87b9f70255377e024ace6630c1eaa37f',
|
|
5
|
+
symbol: 'USDC',
|
|
6
|
+
decimals: 6,
|
|
7
|
+
chainId: 5,
|
|
8
|
+
logoURI:
|
|
9
|
+
'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png',
|
|
10
|
+
extensions: {
|
|
11
|
+
bridgeInfo: {
|
|
12
|
+
'10': {
|
|
13
|
+
tokenAddress: '0x7F5c764cBc14f9669B88837ca1490cCa17c31607',
|
|
14
|
+
},
|
|
15
|
+
'137': {
|
|
16
|
+
tokenAddress: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174',
|
|
17
|
+
},
|
|
18
|
+
'42161': {
|
|
19
|
+
tokenAddress: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export default hardcodedTokens;
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
import { Token, TokenList } from './types';
|
|
4
|
+
|
|
5
|
+
export const isAddress = (maybeAddress: string) => {
|
|
6
|
+
return maybeAddress.startsWith('0x') && maybeAddress.length === 42;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/* From Ethereum-compatible numbers to human-readable numbers */
|
|
10
|
+
export const formatUnits = async (
|
|
11
|
+
units: ethers.BigNumberish,
|
|
12
|
+
symbolOrAddress: string,
|
|
13
|
+
tokenList: TokenList,
|
|
14
|
+
chainId: number
|
|
15
|
+
) => {
|
|
16
|
+
const token = await getTokenFromSymbolOrAddress(symbolOrAddress, tokenList, chainId);
|
|
17
|
+
|
|
18
|
+
return ethers.utils.formatUnits(units, token?.decimals);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/* From human-readable numbers to Ethereum-compatible numbers */
|
|
22
|
+
export const parseUnits = async (
|
|
23
|
+
units: string,
|
|
24
|
+
symbolOrAddress: string,
|
|
25
|
+
tokenList: TokenList,
|
|
26
|
+
chainId: number
|
|
27
|
+
) => {
|
|
28
|
+
const token = await getTokenFromSymbolOrAddress(symbolOrAddress, tokenList, chainId);
|
|
29
|
+
|
|
30
|
+
return ethers.utils.parseUnits(units, token?.decimals);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const getTokenFromSymbolOrAddress = async (
|
|
34
|
+
symbolOrAddress: string,
|
|
35
|
+
tokenList: TokenList,
|
|
36
|
+
chainId: number
|
|
37
|
+
): Promise<Token | undefined> => {
|
|
38
|
+
let token;
|
|
39
|
+
if (isAddress(symbolOrAddress)) {
|
|
40
|
+
token = await getTokenFromAddress(symbolOrAddress, tokenList, chainId);
|
|
41
|
+
} else {
|
|
42
|
+
token = await getTokenFromSymbol(symbolOrAddress, tokenList, chainId);
|
|
43
|
+
}
|
|
44
|
+
return token;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const getTokenFromAddress = async (address: string, tokenList: TokenList, chainId: number) => {
|
|
48
|
+
const token = tokenList.find(token => token.chainId === chainId && token.address === address);
|
|
49
|
+
|
|
50
|
+
return token;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const getTokenFromSymbol = async (symbol: string, tokenList: TokenList, chainId: number) => {
|
|
54
|
+
const token = tokenList.find(
|
|
55
|
+
token => token.chainId === chainId && token.symbol.toUpperCase() === symbol.toUpperCase()
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
return token;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const getChainIdFromProvider = async (provider: ethers.providers.Provider) => {
|
|
62
|
+
return (await provider.getNetwork()).chainId;
|
|
63
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
|
|
3
|
+
import { LearnCard } from '@learncard/core';
|
|
4
|
+
import { ethers } from 'ethers';
|
|
5
|
+
|
|
6
|
+
import { EthereumConfig, EthereumPlugin, TokenList } from './types';
|
|
7
|
+
import {
|
|
8
|
+
formatUnits,
|
|
9
|
+
parseUnits,
|
|
10
|
+
getTokenFromSymbolOrAddress,
|
|
11
|
+
getChainIdFromProvider,
|
|
12
|
+
} from './helpers';
|
|
13
|
+
import ERC20ABI from './erc20.abi.json';
|
|
14
|
+
import uniswapDefaultTokenList from '@uniswap/default-token-list/build/uniswap-default.tokenlist.json';
|
|
15
|
+
import hardcodedTokens from './hardcodedTokens';
|
|
16
|
+
|
|
17
|
+
export * from './types';
|
|
18
|
+
|
|
19
|
+
const defaultTokenList = (uniswapDefaultTokenList as { tokens: TokenList }).tokens.concat(
|
|
20
|
+
hardcodedTokens
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @group Plugins
|
|
25
|
+
*/
|
|
26
|
+
export const getEthereumPlugin = (
|
|
27
|
+
initLearnCard: LearnCard<any, 'id'>,
|
|
28
|
+
config: EthereumConfig
|
|
29
|
+
): EthereumPlugin => {
|
|
30
|
+
let { infuraProjectId, network = 'mainnet' } = config;
|
|
31
|
+
|
|
32
|
+
// Ethers wallet
|
|
33
|
+
const secpKeypair = initLearnCard.id.keypair('secp256k1');
|
|
34
|
+
|
|
35
|
+
if (!secpKeypair) {
|
|
36
|
+
throw new Error('LearnCard must support secp256k1 JWK in order to add Ethereum Plugin');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const privateKey = Buffer.from(secpKeypair.d, 'base64').toString('hex');
|
|
40
|
+
let ethersWallet = new ethers.Wallet(privateKey);
|
|
41
|
+
const publicKey: string = ethersWallet.address;
|
|
42
|
+
|
|
43
|
+
// Provider
|
|
44
|
+
const getProvider = () => {
|
|
45
|
+
let provider: ethers.providers.Provider;
|
|
46
|
+
if (infuraProjectId) {
|
|
47
|
+
provider = new ethers.providers.InfuraProvider(network, infuraProjectId);
|
|
48
|
+
} else {
|
|
49
|
+
provider = ethers.getDefaultProvider(network);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
ethersWallet = ethersWallet.connect(provider);
|
|
53
|
+
return provider;
|
|
54
|
+
};
|
|
55
|
+
let provider: ethers.providers.Provider;
|
|
56
|
+
|
|
57
|
+
const defaultTokenListForNetwork = defaultTokenList;
|
|
58
|
+
|
|
59
|
+
const getTokenAddress = async (tokenSymbolOrAddress: string) => {
|
|
60
|
+
if (!provider) provider = getProvider();
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
await getTokenFromSymbolOrAddress(
|
|
64
|
+
tokenSymbolOrAddress,
|
|
65
|
+
defaultTokenListForNetwork,
|
|
66
|
+
await getChainIdFromProvider(provider)
|
|
67
|
+
)
|
|
68
|
+
)?.address;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const getErc20TokenBalance = async (
|
|
72
|
+
tokenContractAddress: string,
|
|
73
|
+
walletPublicAddress = publicKey
|
|
74
|
+
) => {
|
|
75
|
+
if (!provider) provider = getProvider();
|
|
76
|
+
|
|
77
|
+
const contract = new ethers.Contract(tokenContractAddress, ERC20ABI, provider);
|
|
78
|
+
|
|
79
|
+
const balance = await contract.balanceOf(walletPublicAddress);
|
|
80
|
+
const formattedBalance = formatUnits(
|
|
81
|
+
balance,
|
|
82
|
+
tokenContractAddress,
|
|
83
|
+
defaultTokenList,
|
|
84
|
+
await getChainIdFromProvider(provider)
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return formattedBalance;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Core Methods
|
|
91
|
+
const getBalance = async (walletAddress = publicKey, tokenSymbolOrAddress = 'ETH') => {
|
|
92
|
+
if (!provider) provider = getProvider();
|
|
93
|
+
|
|
94
|
+
if (!tokenSymbolOrAddress || tokenSymbolOrAddress === 'ETH') {
|
|
95
|
+
// check ETH by default
|
|
96
|
+
const balance = await provider.getBalance(walletAddress);
|
|
97
|
+
const formattedBalance = ethers.utils.formatEther(balance);
|
|
98
|
+
|
|
99
|
+
return formattedBalance;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const tokenAddress = await getTokenAddress(tokenSymbolOrAddress);
|
|
103
|
+
|
|
104
|
+
if (!tokenAddress) {
|
|
105
|
+
throw new Error(`Unable to determine token address for \"${tokenSymbolOrAddress}\"`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const balance = await getErc20TokenBalance(tokenAddress, walletAddress);
|
|
109
|
+
|
|
110
|
+
return balance;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
name: 'Ethereum',
|
|
115
|
+
displayName: 'Ethereum',
|
|
116
|
+
description: 'Provides access to currency',
|
|
117
|
+
methods: {
|
|
118
|
+
getEthereumAddress: () => publicKey,
|
|
119
|
+
|
|
120
|
+
getBalance: async (_learnCard, symbolOrAddress = 'ETH') =>
|
|
121
|
+
getBalance(publicKey, symbolOrAddress),
|
|
122
|
+
getBalanceForAddress: async (_learnCard, walletAddress, symbolOrAddress) =>
|
|
123
|
+
getBalance(walletAddress, symbolOrAddress),
|
|
124
|
+
|
|
125
|
+
transferTokens: async (_learnCard, tokenSymbolOrAddress, amount, toAddress) => {
|
|
126
|
+
if (!provider) provider = getProvider();
|
|
127
|
+
|
|
128
|
+
if (tokenSymbolOrAddress === 'ETH') {
|
|
129
|
+
const transaction = {
|
|
130
|
+
to: toAddress,
|
|
131
|
+
|
|
132
|
+
// Convert ETH to wei
|
|
133
|
+
value: ethers.utils.parseEther(amount.toString()),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
return (await ethersWallet.sendTransaction(transaction)).hash;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const tokenAddress = await getTokenAddress(tokenSymbolOrAddress);
|
|
140
|
+
if (!tokenAddress) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Unable to determine token address for \"${tokenSymbolOrAddress}\"`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const tokenContract = new ethers.Contract(tokenAddress, ERC20ABI, ethersWallet);
|
|
147
|
+
|
|
148
|
+
return (
|
|
149
|
+
await tokenContract.transfer(
|
|
150
|
+
toAddress,
|
|
151
|
+
await parseUnits(
|
|
152
|
+
amount.toString(),
|
|
153
|
+
tokenContract.address,
|
|
154
|
+
defaultTokenList,
|
|
155
|
+
await getChainIdFromProvider(provider)
|
|
156
|
+
)
|
|
157
|
+
)
|
|
158
|
+
).hash;
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
getGasPrice: async () => {
|
|
162
|
+
if (!provider) provider = getProvider();
|
|
163
|
+
|
|
164
|
+
return ethers.utils.formatUnits(await provider.getGasPrice());
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
/* Configuration-type methods */
|
|
168
|
+
getCurrentNetwork: () => {
|
|
169
|
+
return network;
|
|
170
|
+
},
|
|
171
|
+
changeNetwork: (_learnCard, _network: ethers.providers.Networkish) => {
|
|
172
|
+
const oldNetwork = network;
|
|
173
|
+
try {
|
|
174
|
+
network = _network;
|
|
175
|
+
provider = getProvider();
|
|
176
|
+
} catch (e) {
|
|
177
|
+
network = oldNetwork;
|
|
178
|
+
provider = getProvider();
|
|
179
|
+
throw e;
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
addInfuraProjectId: (_learnCard, infuraProjectIdToAdd) => {
|
|
183
|
+
infuraProjectId = infuraProjectIdToAdd;
|
|
184
|
+
provider = getProvider();
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { providers } from 'ethers';
|
|
2
|
+
import { Plugin } from '@learncard/core';
|
|
3
|
+
|
|
4
|
+
/** @group Ethereum Plugin */
|
|
5
|
+
export type EthereumPluginMethods = {
|
|
6
|
+
getEthereumAddress: () => string; // TODO is there a way for this to just be a property?
|
|
7
|
+
getBalance: (symbolOrAddress?: string) => Promise<string>;
|
|
8
|
+
getBalanceForAddress: (walletAddress: string, symbolOrAddress?: string) => Promise<string>;
|
|
9
|
+
transferTokens: (
|
|
10
|
+
tokenSymbolOrAddress: string,
|
|
11
|
+
amount: number,
|
|
12
|
+
toAddress: string
|
|
13
|
+
) => Promise<string>;
|
|
14
|
+
getGasPrice: () => Promise<string>;
|
|
15
|
+
getCurrentNetwork: () => providers.Networkish;
|
|
16
|
+
changeNetwork: (network: providers.Networkish) => void;
|
|
17
|
+
addInfuraProjectId: (infuraProjectIdToAdd: string) => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** @group Ethereum Plugin */
|
|
21
|
+
export type EthereumConfig = {
|
|
22
|
+
infuraProjectId?: string;
|
|
23
|
+
network?: providers.Networkish;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/** @group Ethereum Plugin */
|
|
27
|
+
export type Token = {
|
|
28
|
+
chainId: number;
|
|
29
|
+
address: string;
|
|
30
|
+
name: string;
|
|
31
|
+
symbol: string;
|
|
32
|
+
decimals: number;
|
|
33
|
+
logoURI: string;
|
|
34
|
+
extensions: any;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** @group Ethereum Plugin */
|
|
38
|
+
export type TokenList = Token[];
|
|
39
|
+
|
|
40
|
+
/** @group Ethereum Plugin */
|
|
41
|
+
export type EthereumPlugin = Plugin<'Ethereum', any, EthereumPluginMethods, 'id'>;
|