· 4 years ago · Apr 05, 2021, 08:30 AM
1/* UTXO STATE WITH CARDANO-RAY LIBRARY ============
2 * ================================================
3 */
4
5import CardanoRay from 'cardano-ray'
6
7const mnemonic = CardanoRay.generateMnemonic() // generate mnemonic
8const prvkey = CardanoRay.getPrivateKey(mnemonic) // get privatekey
9
10// init library
11const cardano = CardanoRay.init({
12 network: 'mainnet',
13 graphql: 'https://graphql.rraayy.com',
14 key: prvkey,
15})
16
17 // check 80 first internal/external addresses for balances
18const addressesWithBalances = cardano.getAddressesWithBalances()
19
20
21
22
23
24
25
26
27
28
29
30
31
32/* WITHOUT LIBRARY ================================
33 * ================================================
34 */
35
36import axios from 'axios
37import { generateMnemonic, validateMnemonic, mnemonicToEntropy } from 'bip39-light'
38
39const apiClient = axios.create({
40 baseURL: CARDANO_NETWORK === 'https://graphql.rraayy.com'
41})
42
43export async function GetAdressesUTXO(addresses) {
44 return apiClient
45 .post('/', {
46 query: `
47 query utxoSetForAddress($addresses: [String]) {
48 utxos(order_by: { value: desc }, where: { address: { _in: $addresses } }) {
49 address
50 value
51 tokens {
52 assetId
53 assetName
54 policyId
55 quantity
56 }
57 }
58 }
59 `,
60 variables: {
61 addresses,
62 },
63 })
64 .then((response) => {
65 if (response) {
66 return response.data
67 }
68 return false
69 })
70 .catch((err) => console.log(err))
71}
72
73class CardanoWasmModule {
74 async load() {
75 this.wasm = await import('@emurgo/cardano-serialization-lib-browser/cardano_serialization_lib')
76 }
77
78 get API() {
79 return this.wasm
80 }
81}
82
83
84/**
85 * Mnemonic generation
86 * @return {string}
87 */
88
89export const CardanoGenerateMnemonic = (length = 24) => {
90 return generateMnemonic((32 * length) / 3)
91}
92
93/**
94 * Get private key, public key, reward address
95 * @return {object}
96 */
97
98export const CardanoGetAccountInfo = async (network, mnemonic) => {
99 await CardanoWasm.load()
100
101 const harden = (num) => {
102 return 0x80000000 + num
103 }
104
105 const entropy = mnemonicToEntropy(mnemonic)
106 const rootKey = CardanoWasm.API.Bip32PrivateKey.from_bip39_entropy(
107 Buffer.from(entropy, 'hex'),
108 Buffer.from(''),
109 )
110
111 const privateKey = rootKey.derive(harden(1852)).derive(harden(1815)).derive(harden(0))
112
113 const stakeKey = privateKey.derive(2).derive(0).to_public()
114
115 const currentNetwork = network === 'testnet'
116 ? CardanoWasm.API.NetworkInfo.testnet().network_id()
117 : CardanoWasm.API.NetworkInfo.mainnet().network_id()
118
119 const rewardAddress = CardanoWasm.API.RewardAddress.new(
120 currentNetwork,
121 CardanoWasm.API.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
122 )
123 const rewardAddressBech32 = rewardAddress.to_address().to_bech32()
124 const privateKeyBech32 = privateKey.to_bech32()
125 const publicKeyBech32 = privateKey.to_public().to_bech32()
126
127 return { rewardAddressBech32, privateKeyBech32, publicKeyBech32 }
128}
129
130/**
131 * Generate address pack related to Private Key
132 * @param {string} publicKeyBech32 private key
133 * @param {string} type external internal / all derives
134 * @param {number} shift shifting addresses by page size
135 * @param {number} page page size
136 * @return {array} adresses array
137 */
138
139export const CardanoGetAccountAdresses = async (
140 network,
141 publicKeyBech32,
142 type = 'external',
143 shift = 0,
144 page = 20,
145) => {
146 await CardanoWasm.load()
147
148 const publicKey = CardanoWasm.API.Bip32PublicKey.from_bech32(publicKeyBech32)
149 const accountAdresses = []
150
151 const currentNetwork = network === 'testnet'
152 ? CardanoWasm.API.NetworkInfo.testnet().network_id()
153 : CardanoWasm.API.NetworkInfo.mainnet().network_id()
154
155 const generateAddresses = (addressType) => {
156 const tmpAddresses = []
157 for (let i = 0 + page * shift; i < page + page * shift; i += 1) {
158 const utxoPubKey = publicKey
159 .derive(addressType) // 0 external / 1 internal
160 .derive(i)
161 const stakeKey = publicKey
162 .derive(2) // chimeric
163 .derive(0)
164 const baseAddr = CardanoWasm.API.BaseAddress.new(
165 currentNetwork,
166 CardanoWasm.API.StakeCredential.from_keyhash(utxoPubKey.to_raw_key().hash()),
167 CardanoWasm.API.StakeCredential.from_keyhash(stakeKey.to_raw_key().hash()),
168 )
169 const baseAddrBech32 = baseAddr.to_address().to_bech32()
170 tmpAddresses.push(baseAddrBech32)
171 }
172 return tmpAddresses
173 }
174
175 switch (type) {
176 case 'external':
177 accountAdresses.push(...generateAddresses(0))
178 break
179 case 'internal':
180 accountAdresses.push(...generateAddresses(1))
181 break
182 case 'all':
183 accountAdresses.push(...generateAddresses(0))
184 accountAdresses.push(...generateAddresses(1))
185 break
186 default:
187 break
188 }
189
190 return accountAdresses
191}
192
193function* checkAddresses(type, shift, pageSize) {
194 const tmpAddresses = yield call(
195 Cardano.CardanoGetAccountAdresses,
196 CARDANO_NETWORK,
197 publicKey,
198 type,
199 shift,
200 pageSize,
201 )
202 const tmpAddresssesUTXO = yield call(Explorer.GetAdressesUTXO, tmpAddresses)
203 return [tmpAddresssesUTXO, tmpAddresses]
204}
205
206const UTXOArray = []
207const adressesArray = []
208const pageSize = 20
209const type = 'all'
210const maxShiftIndex = 10
211let shiftIndex = 0
212function* getAddressesWithShift(shift) {
213 const [adresssesWithUTXOs, checkedAdresses] = yield call(checkAddresses, type, shift, pageSize)
214 adressesArray.push(...checkedAdresses)
215 if (adresssesWithUTXOs.data && shiftIndex < maxShiftIndex) {
216 if (adresssesWithUTXOs.data.utxos.length) {
217 shiftIndex += 1
218 UTXOArray.push(...adresssesWithUTXOs.data.utxos)
219 yield call(getAddressesWithShift, shiftIndex)
220 }
221 }
222}
223yield call(getAddressesWithShift, shiftIndex)