From d1859b712fa03e90fd0e49ffafa903dae47abe97 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 21 Dec 2023 09:44:04 -0600 Subject: [PATCH 01/25] Add more logs, cleanup unused funcs. --- .../onboarding/src/HotspotOnboardingUtil.ts | 100 ++---------------- .../onboarding/src/MobileWifiOnboarding.ts | 2 + 2 files changed, 13 insertions(+), 89 deletions(-) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index f0491bdc..2d5d16b5 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -8,10 +8,8 @@ import { heliumAddressToSolPublicKey, } from '@helium/spl-utils' import { subDaoKey } from '@helium/helium-sub-daos-sdk' -import { Connection, PublicKey, AccountInfo, Cluster, LAMPORTS_PER_SOL } from '@solana/web3.js' -import axios from 'axios' +import { Connection, PublicKey, Cluster, LAMPORTS_PER_SOL } from '@solana/web3.js' import { - AccountLayout, createAssociatedTokenAccountIdempotentInstruction, getAccount, getMinimumBalanceForRentExemptAccount, @@ -33,11 +31,9 @@ import { TXN_FEE_IN_LAMPORTS, } from './types' -type Account = AccountInfo - const lowerFirst = (str: string) => str.charAt(0).toLowerCase() + str.slice(1) -export const deviceTypeToNetworkType = (deviceType: DeviceType): NetworkType => { +const deviceTypeToNetworkType = (deviceType: DeviceType): NetworkType => { if (deviceType === null) return 'IOT' return 'MOBILE' @@ -92,6 +88,7 @@ export const getHotspotNetworkDetails = async ({ if (!networkType && types.deviceType !== undefined) { networkType = deviceTypeToNetworkType(types.deviceType) } + if (!networkType) { throw new Error('Could not determine network type') } @@ -214,10 +211,7 @@ const burnHNTForDataCredits = async ({ return txn } -export const getAtaAccountCreationFee = async ( - solanaAddress: PublicKey, - connection: Connection, -) => { +const getAtaAccountCreationFee = async (solanaAddress: PublicKey, connection: Connection) => { const ataAddress = getAssociatedTokenAddressSync(DC_MINT, solanaAddress, true) try { @@ -229,84 +223,6 @@ export const getAtaAccountCreationFee = async ( } } -export const fetchSimulatedTxn = async ({ - apiUrl, - txnBuff, - accountAddresses, -}: { - apiUrl: string - txnBuff: Buffer - accountAddresses: string[] -}): Promise> => { - const body = { - jsonrpc: '2.0', - id: 1, - method: 'simulateTransaction', - params: [ - txnBuff.toString('base64'), - { - encoding: 'base64', - commitment: 'recent', - sigVerify: false, - accounts: { - encoding: 'jsonParsed', - addresses: accountAddresses, - }, - }, - ], - } - const response = await axios.post<{ - result: { value: { accounts: Account[]; logs: string[]; err?: any } } - }>(apiUrl, body) - - if (response.data.result.value.err) { - console.error(response.data.result.value.logs.join('\n') + 'Transaction would fail') - throw new Error('Transaction would fail') - } - return response.data.result.value.accounts -} - -export const getAccountFees = async ({ - dcAccount, - account, - connection, - key, - dcMint, -}: { - key: PublicKey - dcAccount?: Account - account?: Account - connection: Connection - dcMint: PublicKey -}) => { - const lamportsBefore = new BN(await connection.getBalance(key)) - const dcBefore = await getBalance(key, connection, dcMint) - - let lamportsAfter = new BN(0) - let dcAfter = new BN(0) - - if (account) { - lamportsAfter = new BN(account.lamports.toString()) - } else { - lamportsAfter = lamportsBefore - } - - const lamportFee = lamportsBefore.sub(lamportsAfter) - let dcFee = new BN(0) - - if (dcAccount && dcAccount.lamports > 0) { - const tokenAccount = AccountLayout.decode( - Buffer.from(dcAccount.data[0], dcAccount.data[1] as BufferEncoding), - ) - - const dcBalance = new BN(tokenAccount.amount.toString()) - dcAfter = dcBalance - dcFee = dcBefore.sub(dcAfter) - } - - return { lamports: lamportFee, dc: dcFee } -} - export const getAssertData = async ({ deviceType, gateway, @@ -345,7 +261,11 @@ export const getAssertData = async ({ const networkType = deviceTypeToNetworkType(deviceType) const solanaAddress = owner.toBase58() - const gain = Math.round((decimalGain || 0) * 10.0) + let gain: number | undefined = undefined + if (decimalGain) { + gain = Math.round((decimalGain || 0) * 10.0) + } + const solResponse = await onboardingClient.updateMetadata({ type: networkType, solanaAddress, @@ -356,6 +276,7 @@ export const getAssertData = async ({ }) const errFound = !solResponse.success ? solResponse : undefined + if (errFound) { throw errFound.errorMessage } @@ -369,6 +290,7 @@ export const getAssertData = async ({ address: gateway, hemProgram, }) + const requiredDc = networkDetails?.locationStakingFee || new BN(0) let makerDc = new BN(0) diff --git a/packages/onboarding/src/MobileWifiOnboarding.ts b/packages/onboarding/src/MobileWifiOnboarding.ts index c7302d75..daebb60a 100644 --- a/packages/onboarding/src/MobileWifiOnboarding.ts +++ b/packages/onboarding/src/MobileWifiOnboarding.ts @@ -136,10 +136,12 @@ export default class MobileWifiOnboarding { signGatewayAddTransaction = async (deviceType: ManufacturedDeviceType) => { this.setProgressToStep('get_add_gateway') + this.writeLog('Getting add gateway txn', { deviceType, cluster: this._cluster }) const { txn: txnStr, apiVersion } = await this._wifiClient.signGatewayAddTransaction( this._cluster, deviceType, ) + this.writeLog('Got add gateway str', { txnStr }) const txn = AddGatewayV1.fromString(txnStr) this.setProgressToStep('got_add_gateway') return { txn, apiVersion } From dec4faecee4d0bf80c2e1e11c110ab716999649d Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Fri, 29 Dec 2023 22:20:34 -0600 Subject: [PATCH 02/25] Verify config message before sending. --- packages/onboarding/package.json | 1 + .../onboarding/src/ConfigurationClient.ts | 13 +- packages/onboarding/src/WifiHttpClient.ts | 11 +- .../__tests__/MobileWifiOnboarding.spec.ts | 10 +- packages/onboarding/yarn.lock | 121 +++++++++++++++++- 5 files changed, 138 insertions(+), 18 deletions(-) diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 008b3a07..3c7cc2d3 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -42,6 +42,7 @@ "dependencies": { "@coral-xyz/anchor": "^0.28.1-beta.2", "@helium/address": "^4.12.0", + "@helium/crypto": "^4.10.2", "@helium/currency-utils": "^0.6.6", "@helium/data-credits-sdk": "^0.6.6", "@helium/helium-entity-manager-sdk": "^0.6.6", diff --git a/packages/onboarding/src/ConfigurationClient.ts b/packages/onboarding/src/ConfigurationClient.ts index 244e78d5..313be051 100644 --- a/packages/onboarding/src/ConfigurationClient.ts +++ b/packages/onboarding/src/ConfigurationClient.ts @@ -5,6 +5,7 @@ import { Cluster, PublicKey } from '@solana/web3.js' import { Message, heightTypeFromJSON } from './OutdoorConfig' import { HeightType } from './types' import bs58 from 'bs58' +import { utils } from '@helium/crypto' export default class ConfigurationClient { private axios!: AxiosInstance @@ -74,9 +75,19 @@ export default class ConfigurationClient { signedMessage: Uint8Array token: string }) { + const message = Message.decode(originalMessage) + + let verified = false + try { + verified = await utils.verify(signedMessage, originalMessage, message.walletPubKey) + } catch {} + + if (!verified) { + throw new Error('Config Message verification failed') + } + const url = `/api/v1/hmhpubkey/${hotspotAddress}/submitCoverageConfigurationMessage` - const message = Message.decode(originalMessage) message.signature = signedMessage const encodedMessage = Message.encode(message).finish() const body = { payloadB64: Buffer.from(encodedMessage).toString('base64') } diff --git a/packages/onboarding/src/WifiHttpClient.ts b/packages/onboarding/src/WifiHttpClient.ts index 3dd02d78..4b969f0e 100644 --- a/packages/onboarding/src/WifiHttpClient.ts +++ b/packages/onboarding/src/WifiHttpClient.ts @@ -11,8 +11,9 @@ import { OutdoorManufacturedDeviceType, OutdoorManufacturedDeviceTypes, } from './types' - -const MOCK_GATEWAY = Address.fromB58('13yTQcEaPEVuYeWRMz9F6XjAMgMJjDuCgueukjaiJzmdvCHncMz') +import { MAINNET } from '@helium/address/build/NetTypes' +import { ED25519_KEY_TYPE } from '@helium/address/build/KeyTypes' +import { Keypair } from '@helium/crypto' type GPSLocation = { latitude: number @@ -125,13 +126,15 @@ export default class HmhHttpClient { this.logCallback?.('signGatewayAddTransaction', { body, url }) if (this.mockAdapter) { + const keypair = await Keypair.makeRandom() + const gateway = new Address(0, MAINNET, ED25519_KEY_TYPE, keypair.publicKey) const addGateway = new AddGatewayV1({ owner: Address.fromB58(ownerHeliumAddress), - gateway: MOCK_GATEWAY, + gateway, }) this.mockAdapter.onPost(url).reply(200, { - gatewayAddress: MOCK_GATEWAY.b58, + gatewayAddress: gateway.b58, signedAddGwTx: addGateway.toString(), }) } diff --git a/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts b/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts index f8981969..3a920dd2 100644 --- a/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts +++ b/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts @@ -1,11 +1,10 @@ import MobileWifiOnboarding from '../MobileWifiOnboarding' -import Address from '@helium/address' import { heliumAddressToSolPublicKey } from '@helium/spl-utils' import { Transaction } from '@solana/web3.js' import h3 from 'h3-js' -import { Message } from '../OutdoorConfig' import { usersFixture } from '../../../../integration_tests/fixtures/users' import { v4 as uuidv4 } from 'uuid' +import Address from '@helium/address' const ALICE = Address.fromB58('148d8KTRcKA5JKPekBcKFd4KfvprvFRpjGtivhtmRmnZ8MFYnP3') const ALICE_PUBKEY = heliumAddressToSolPublicKey(ALICE.b58) @@ -17,7 +16,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { wifiApiVersion: 'v2', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', - wallet: ALICE_PUBKEY, + wallet: heliumAddressToSolPublicKey(alice.address.b58), onboardingClientUrl: 'https://onboarding.web.test-helium.com/api/v3', cluster: 'devnet', rpcEndpoint: 'https://api.devnet.solana.com', @@ -49,15 +48,12 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { hotspotAddress: txn.gateway.b58, }) - const message = Message.decode(originalMessage) const signature = await alice.sign(originalMessage) - message.signature = signature - const encodedMessage = Message.encode(message).finish() const response = await client.sendConfigurationMessage({ hotspotAddress: txn.gateway.b58, originalMessage, - signedMessage: encodedMessage, + signedMessage: signature, token: 'asdf', }) expect(response.status).toBe(204) diff --git a/packages/onboarding/yarn.lock b/packages/onboarding/yarn.lock index b984a796..d89631df 100644 --- a/packages/onboarding/yarn.lock +++ b/packages/onboarding/yarn.lock @@ -75,6 +75,15 @@ js-sha256 "^0.9.0" multiformats "^9.6.4" +"@helium/address@^4.11.0", "@helium/address@^4.11.1": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@helium/address/-/address-4.11.1.tgz#e6c6debaee2f50ed16383d5660ba81d29e604948" + integrity sha512-QMrdBx5l5XIy0K9fL3R64Whuk556BLz/pa6yhOQtog1hb3C904m1ykAU8eg2hgiA265Yp98XZkIK3GKTHbH+0A== + dependencies: + bs58 "^5.0.0" + js-sha256 "^0.9.0" + multiformats "^9.6.4" + "@helium/anchor-resolvers@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@helium/anchor-resolvers/-/anchor-resolvers-0.5.0.tgz#499fbcd82411d07b148d7015a1e6432020a3f82d" @@ -102,6 +111,15 @@ bn.js "^5.2.0" bs58 "^4.0.1" +"@helium/crypto@^4.10.2": + version "4.10.2" + resolved "https://registry.yarnpkg.com/@helium/crypto/-/crypto-4.10.2.tgz#4707756a4623035e5a6f30b6e4ae51158f1e269a" + integrity sha512-ltDWuQwEMNNvIq82QhqF1EPsHm1LrOceiGZgPvi0c9FPp5B6ft2TPjpDueGM27uKy0XbcHAjvBM7HhSCRhs+iQ== + dependencies: + "@helium/address" "^4.10.2" + create-hash "^1.2.0" + libsodium-wrappers "^0.7.6" + "@helium/currency-utils@^0.6.6": version "0.6.6" resolved "https://registry.yarnpkg.com/@helium/currency-utils/-/currency-utils-0.6.6.tgz#d5114efa0828f420c9f7e1eba405a952bec96f9a" @@ -226,12 +244,12 @@ borsh "^0.7.0" bs58 "^4.0.1" -"@helium/transactions@^4.10.2": - version "4.10.2" - resolved "https://registry.yarnpkg.com/@helium/transactions/-/transactions-4.10.2.tgz#7b5bdd0fa1c37db3c273522b266b8e5f16ad79ed" - integrity sha512-WVbkJDIdcQQ81Dta9K9IH2qXQTJ/pMUpdmivs9W+DDSudFX2yLB35bCzqcFfa8RYGld52EhmTWXyuq0HSDaoQw== +"@helium/transactions@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@helium/transactions/-/transactions-4.11.1.tgz#38c48d0c2c395ce1e0a78fd57510c09d958c24e8" + integrity sha512-uL6OKo5o8AKn7oOuuW6/T7MSwPikbYU2HsSDu2O7ZhnGiyzKcKXQMkIHSBuFKz9KT+DKVpVSwjeLXr4a6/D/eQ== dependencies: - "@helium/address" "^4.10.2" + "@helium/address" "^4.11.1" "@helium/proto" "^1.6.0" "@types/libsodium-wrappers" "^0.7.8" long "^4.0.0" @@ -669,6 +687,14 @@ case-anything@^2.1.13: resolved "https://registry.yarnpkg.com/case-anything/-/case-anything-2.1.13.tgz#0cdc16278cb29a7fcdeb072400da3f342ba329e9" integrity sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng== +cipher-base@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -686,6 +712,17 @@ compare-versions@^6.1.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== +create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + cross-fetch@^3.1.5: version "3.1.8" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" @@ -854,6 +891,15 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -878,6 +924,11 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + is-buffer@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" @@ -931,6 +982,18 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +libsodium-wrappers@^0.7.6: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz#83299e06ee1466057ba0e64e532777d2929b90d3" + integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== + dependencies: + libsodium "^0.7.13" + +libsodium@^0.7.13: + version "0.7.13" + resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.13.tgz#230712ec0b7447c57b39489c48a4af01985fb393" + integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== + long@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" @@ -948,6 +1011,15 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -1067,11 +1139,28 @@ qs@^6.10.3: dependencies: side-channel "^1.0.4" +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== +ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + rpc-websockets@^7.5.1: version "7.9.0" resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.9.0.tgz#a3938e16d6f134a3999fdfac422a503731bf8973" @@ -1085,7 +1174,7 @@ rpc-websockets@^7.5.1: bufferutil "^4.0.1" utf-8-validate "^5.0.2" -safe-buffer@^5.0.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -1100,6 +1189,14 @@ set-function-length@^1.1.1: gopd "^1.0.1" has-property-descriptors "^1.0.0" +sha.js@^2.4.0: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -1117,6 +1214,13 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + superstruct@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" @@ -1201,6 +1305,11 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + util@^0.10.3: version "0.10.4" resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901" From ab49dfcb8e12dfa79f94efca619ad7e4a9c8313e Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 4 Jan 2024 16:01:11 -0600 Subject: [PATCH 03/25] Throw an error when firmware lookup fails to respond. --- packages/onboarding/src/MobileWifiOnboarding.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/MobileWifiOnboarding.ts b/packages/onboarding/src/MobileWifiOnboarding.ts index daebb60a..f4786c57 100644 --- a/packages/onboarding/src/MobileWifiOnboarding.ts +++ b/packages/onboarding/src/MobileWifiOnboarding.ts @@ -161,7 +161,9 @@ export default class MobileWifiOnboarding { const isSuccessful = status >= 200 && status < 300 - if (!isSuccessful || !firmwareVersion) return false + if (!isSuccessful || !firmwareVersion) { + throw new Error('Could not determine firmware version.') + } if (firmwareVersion.startsWith('dev')) return true From 100762b668d30d3f2e1e133282ca42df78cafd29 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Fri, 5 Jan 2024 09:33:12 -0600 Subject: [PATCH 04/25] Cleanup incorrect error logging when onboarding --- .../onboarding/src/MobileWifiOnboarding.ts | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/packages/onboarding/src/MobileWifiOnboarding.ts b/packages/onboarding/src/MobileWifiOnboarding.ts index f4786c57..0e71cb56 100644 --- a/packages/onboarding/src/MobileWifiOnboarding.ts +++ b/packages/onboarding/src/MobileWifiOnboarding.ts @@ -302,10 +302,17 @@ export default class MobileWifiOnboarding { try { const hotspotPubKey = await this._solanaOnboarding.hotspotToAssetKey(hotspotAddress) - this.writeLog(`Hotspot asset found?: ${hotspotPubKey?.toBase58()} ${hotspotAddress}`) - if (hotspotPubKey) return hotspotPubKey + if (hotspotPubKey) { + this.writeLog(`Hotspot has been found: ${hotspotPubKey?.toBase58()} ${hotspotAddress}`) + return hotspotPubKey + } else { + this.writeLog(`Hotspot not yet found ${hotspotAddress}`) + } } catch (e) { - this.writeError(e) + if (i === 199) { + // if we've reached the end of the loop, write the error + this.writeError(e) + } } } return undefined @@ -333,12 +340,22 @@ export default class MobileWifiOnboarding { address: hotspotAddress, }) - this.writeLog(`Hotspot ${!!hotspotInfo ? 'has' : 'has not'} been onboarded to MOBILE`) + if (hotspotInfo) { + this.writeLog('Hotspot has been onboarded to MOBILE') + } else { + this.writeLog('Hotspot MOBILE details not yet found.') + } + if (hotspotInfo) return hotspotInfo } catch (e) { - this.writeError(e) + this.writeLog('Hotspot MOBILE details not yet found.') + if (i === 199) { + // if we've reached the end of the loop, write the error + this.writeError(e) + } } } + return undefined } @@ -414,10 +431,12 @@ export default class MobileWifiOnboarding { }) if (hotspotInfo) { needsOnboarding = false + this.writeLog('Hotspot has been onboarded to MOBILE') + } else { + this.writeLog('Hotspot MOBILE details not found.') } - this.writeLog(`Hotspot ${!!hotspotInfo ? 'has' : 'has not'} been onboarded to MOBILE`) - } catch (e) { - this.writeError(e) + } catch { + this.writeLog('Hotspot MOBILE details not found.') } if (!this._shouldMock && !needsOnboarding) { From d83b4795b5a032642260aa729a1d3b1118e9149e Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Fri, 5 Jan 2024 14:00:24 -0600 Subject: [PATCH 05/25] Cleanup logs. --- packages/onboarding/src/MobileWifiOnboarding.ts | 7 +++++-- packages/onboarding/src/OnboardingClient.ts | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/onboarding/src/MobileWifiOnboarding.ts b/packages/onboarding/src/MobileWifiOnboarding.ts index 0e71cb56..3ccf1f94 100644 --- a/packages/onboarding/src/MobileWifiOnboarding.ts +++ b/packages/onboarding/src/MobileWifiOnboarding.ts @@ -251,23 +251,26 @@ export default class MobileWifiOnboarding { let solanaTransactions: number[][] | undefined = undefined + let err: unknown = undefined try { const createTxns = await this._onboardingClient.createHotspot({ transaction, }) - solanaTransactions = createTxns.data?.solanaTransactions + solanaTransactions = createTxns?.data?.solanaTransactions + err = createTxns if (solanaTransactions?.length) { this.writeLog('Created hotspot onboard txns') } else { this.writeLog('Could not create hotspot onboard txns', createTxns) } } catch (e) { + err = e this.writeError(e) } try { if (!solanaTransactions?.length) { - throw new Error('No solana transactions returned from create hotspot') + throw new Error(`No solana transactions returned from create hotspot\n\n${err}`) } this.writeLog('Submitting hotspot to solana') diff --git a/packages/onboarding/src/OnboardingClient.ts b/packages/onboarding/src/OnboardingClient.ts index 9912926f..d50248d1 100644 --- a/packages/onboarding/src/OnboardingClient.ts +++ b/packages/onboarding/src/OnboardingClient.ts @@ -82,10 +82,10 @@ export default class OnboardingClient { url: path, data: params, }) - if (response.data.errorMessage) { + if (response.data?.errorMessage) { throw new Error(response.data.errorMessage) } - if (response.data.success === false) { + if (response.data?.success === false) { throw new Error(`Failed with code ${response.data.code}}`) } return response.data From 1c5901e176bff5041110513153c75167c4e05bbf Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 11 Jan 2024 14:37:16 -0600 Subject: [PATCH 06/25] Add cbrs suppot to mobile onboarding client. --- .../onboarding/src/HotspotOnboardingUtil.ts | 10 +- ...boarding.ts => MobileHotspotOnboarding.ts} | 113 +++++++++++------- ...pec.ts => MobileHotspotOnboarding.spec.ts} | 30 ++--- packages/onboarding/src/index.ts | 2 +- 4 files changed, 92 insertions(+), 63 deletions(-) rename packages/onboarding/src/{MobileWifiOnboarding.ts => MobileHotspotOnboarding.ts} (87%) rename packages/onboarding/src/__tests__/{MobileWifiOnboarding.spec.ts => MobileHotspotOnboarding.spec.ts} (92%) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index 2d5d16b5..ed47f2cd 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -34,7 +34,11 @@ import { const lowerFirst = (str: string) => str.charAt(0).toLowerCase() + str.slice(1) const deviceTypeToNetworkType = (deviceType: DeviceType): NetworkType => { - if (deviceType === null) return 'IOT' + // deviceType is null for IOT hotspots + // cbrs devices are both IOT and MOBILE hotspots, but the location, gain, and elevation are all stored on the IOT side + if (deviceType === null || deviceType === 'Cbrs') { + return 'IOT' + } return 'MOBILE' } @@ -324,8 +328,8 @@ export const getAssertData = async ({ const dcInDollars = dcNeeded.div(new BN(100000)) const oraclePrice = await getOraclePriceFromSolana({ connection, cluster }) - const hntNeeded = dcInDollars.div(oraclePrice) - hasSufficientHnt = balances.hnt.gte(hntNeeded) + const hntNeeded = dcInDollars.toNumber() / oraclePrice.toNumber() + hasSufficientHnt = balances.hnt.toNumber() > hntNeeded if (hasSufficientHnt) { const txn = await burnHNTForDataCredits({ diff --git a/packages/onboarding/src/MobileWifiOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts similarity index 87% rename from packages/onboarding/src/MobileWifiOnboarding.ts rename to packages/onboarding/src/MobileHotspotOnboarding.ts index 3ccf1f94..8a537189 100644 --- a/packages/onboarding/src/MobileWifiOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -23,14 +23,13 @@ const ProgressKeys = [ 'got_mobile', 'submit_signed_messages', 'verify_mobile', - 'shutdown_wifi', 'complete', ] as const type ProgressStep = (typeof ProgressKeys)[number] -export default class MobileWifiOnboarding { +export default class MobileHotspotOnboarding { private _configurationClient!: ConfigurationClient - private _wifiClient!: WifiHttpClient + private _wifiClient?: WifiHttpClient private _onboardingClient!: OnboardingClient private _solanaOnboarding!: SolanaOnboarding private _progressCallback?: (progress: number, step?: ProgressStep) => void @@ -45,8 +44,8 @@ export default class MobileWifiOnboarding { return this._cluster } - private _wifiBaseUrl!: string - public get wifiBaseUrl(): string { + private _wifiBaseUrl?: string + public get wifiBaseUrl(): string | undefined { return this._wifiBaseUrl } @@ -66,7 +65,7 @@ export default class MobileWifiOnboarding { } constructor(opts: { - wifiBaseUrl: string + wifiBaseUrl?: string wifiApiVersion?: 'v2' | 'v1' onboardingClientUrl: string shouldMock?: boolean @@ -91,14 +90,17 @@ export default class MobileWifiOnboarding { wallet: opts.wallet, }) - this._wifiClient = new WifiHttpClient({ - owner: opts.wallet, - baseURL: opts.wifiBaseUrl, - apiVersion: opts.wifiApiVersion, - mockRequests: opts.shouldMock, - errorCallback: opts.errorCallback, - logCallback: opts.logCallback, - }) + if (opts.wifiBaseUrl) { + this._wifiClient = new WifiHttpClient({ + owner: opts.wallet, + baseURL: opts.wifiBaseUrl, + apiVersion: opts.wifiApiVersion, + mockRequests: opts.shouldMock, + errorCallback: opts.errorCallback, + logCallback: opts.logCallback, + }) + } + this._onboardingClient = new OnboardingClient(opts.onboardingClientUrl, { mockRequests: opts.shouldMock, }) @@ -114,7 +116,7 @@ export default class MobileWifiOnboarding { this._logCallback = opts.logCallback this._errorCallback = opts.errorCallback - this._logCallback?.('Initialized MobileWifiOnboarding', opts) + this._logCallback?.('Initialized MobileHotspotOnboarding', opts) } writeError = (error: unknown) => { @@ -134,10 +136,18 @@ export default class MobileWifiOnboarding { } } + private getWifiClient = () => { + if (!this._wifiClient) { + throw new Error('Wifi base url not set') + } + + return this._wifiClient + } + signGatewayAddTransaction = async (deviceType: ManufacturedDeviceType) => { this.setProgressToStep('get_add_gateway') this.writeLog('Getting add gateway txn', { deviceType, cluster: this._cluster }) - const { txn: txnStr, apiVersion } = await this._wifiClient.signGatewayAddTransaction( + const { txn: txnStr, apiVersion } = await this.getWifiClient().signGatewayAddTransaction( this._cluster, deviceType, ) @@ -149,7 +159,7 @@ export default class MobileWifiOnboarding { checkFwValid = async (minVersion?: string) => { this.writeLog('Checking firmware version') - const fwInfo = await this._wifiClient.getVersionDetails() + const fwInfo = await this.getWifiClient().getVersionDetails() const minFirmwareVersion = minVersion || 'v0.10.0' @@ -174,14 +184,14 @@ export default class MobileWifiOnboarding { } getGpsLocation = async (deviceType: OutdoorManufacturedDeviceType) => { - return this._wifiClient.getGpsLocation(deviceType) + return this.getWifiClient().getGpsLocation(deviceType) } getApiVersion = () => { - return this._wifiClient.getApiVersion() + return this.getWifiClient().getApiVersion() } - getMobileAssertData = async ({ + getWifiAssertData = async ({ gateway, decimalGain, elevation, @@ -192,7 +202,7 @@ export default class MobileWifiOnboarding { decimalGain?: number elevation?: number location: string - deviceType: DeviceType + deviceType: 'WifiIndoor' | 'WifiOutdoor' }) => { return this._solanaOnboarding.getAssertData({ gateway, @@ -203,6 +213,28 @@ export default class MobileWifiOnboarding { }) } + getCbrsAssertData = async ({ + gateway, + decimalGain, + elevation, + location, + }: { + gateway: string + decimalGain?: number + elevation?: number + location: string + }) => { + // We update assert data for the IOT network only + // For the MOBILE network we don't set location. They must update their radio location at https://hotspots.hellohelium.com + return this._solanaOnboarding.getAssertData({ + gateway, + decimalGain, + elevation, + location, + deviceType: 'Cbrs', + }) + } + getMobileOnboardTxns = async ({ hotspotAddress, location, @@ -460,8 +492,7 @@ export default class MobileWifiOnboarding { return this._solanaOnboarding.hotspotToAssetKey(hotspotAddress) } - onHotspotCreated = async (hotspotAddress: string) => { - this.setProgressToStep('shutdown_wifi') + onWifiHotspotCreated = async (hotspotAddress: string) => { const asset = await this._solanaOnboarding.hotspotToAssetKey(hotspotAddress) if (!asset) { this.writeLog('Hotspot asset not found') @@ -470,9 +501,8 @@ export default class MobileWifiOnboarding { this.writeLog('Calling onHotspotCreated', { data: { asset: asset.toBase58() } }) - let shutdownSuccess = false try { - shutdownSuccess = await this._wifiClient.onHotspotCreated({ + await this.getWifiClient().onHotspotCreated({ assetId: asset.toBase58(), cluster: this._cluster, }) @@ -481,23 +511,17 @@ export default class MobileWifiOnboarding { throw e } - if (!shutdownSuccess) { - throw new Error('Failed to shutdown wifi') - } - - this.writeLog(`Shutdown wifi success: ${shutdownSuccess}`) - this.setProgressToStep('complete') - - return shutdownSuccess } submitAndCompleteOnboarding = async ({ hotspotAddress, signedTxns, + deviceType, }: { hotspotAddress: string signedTxns: Buffer[] + deviceType: DeviceType }) => { this.writeLog('Submitting MOBILE onboard txns to solana') this.setProgressToStep('submit_signed_messages') @@ -533,21 +557,20 @@ export default class MobileWifiOnboarding { this.writeError(err) throw err } - this.setProgressToStep('shutdown_wifi') - this.writeLog('Calling onHotspotCreated', { data: { asset: asset.toBase58() } }) + if (deviceType === 'WifiIndoor' || deviceType === 'WifiOutdoor') { + this.writeLog('Calling onHotspotCreated', { data: { asset: asset.toBase58() } }) - let shutdownSuccess = false - try { - shutdownSuccess = await this._wifiClient.onHotspotCreated({ - assetId: asset.toBase58(), - cluster: this._cluster, - }) - } catch (e) { - this.writeError(e) - throw e + try { + await this.getWifiClient().onHotspotCreated({ + assetId: asset.toBase58(), + cluster: this._cluster, + }) + } catch (e) { + this.writeError(e) + throw e + } } - this.writeLog(`Shutdown wifi success: ${shutdownSuccess}`) this.setProgressToStep('complete') return { txnIds } diff --git a/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts b/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts similarity index 92% rename from packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts rename to packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts index 3a920dd2..1d917a46 100644 --- a/packages/onboarding/src/__tests__/MobileWifiOnboarding.spec.ts +++ b/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts @@ -1,4 +1,4 @@ -import MobileWifiOnboarding from '../MobileWifiOnboarding' +import MobileHotspotOnboarding from '../MobileHotspotOnboarding' import { heliumAddressToSolPublicKey } from '@helium/spl-utils' import { Transaction } from '@solana/web3.js' import h3 from 'h3-js' @@ -12,7 +12,7 @@ const ALICE_PUBKEY = heliumAddressToSolPublicKey(ALICE.b58) describe('Wifi Onboarding with wifi api version 2 (default)', () => { it('Creates, signs, and send config message', async () => { const { alice } = await usersFixture() - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v2', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -60,7 +60,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Gets the gps data from an outdoor hotspot', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v2', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -89,7 +89,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Checks for valid firmware', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', wallet: ALICE_PUBKEY, @@ -103,7 +103,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Checks for invalid firmware', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', wallet: ALICE_PUBKEY, @@ -117,7 +117,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Fetches the add gateway txn from the wifi access point', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', wallet: ALICE_PUBKEY, @@ -132,7 +132,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Fetches the gateway location information', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', wallet: ALICE_PUBKEY, @@ -141,7 +141,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { cluster: 'devnet', }) - const assertData = await client.getMobileAssertData({ + const assertData = await client.getWifiAssertData({ gateway: 'asdf', location: 'asdf123', deviceType: 'WifiIndoor', @@ -152,7 +152,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { }) it('Creates and onboards a mobile wifi access point', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', wallet: ALICE_PUBKEY, @@ -199,6 +199,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { const { txnIds } = await client.submitAndCompleteOnboarding({ hotspotAddress: txn.gateway?.b58!, signedTxns: signed, + deviceType: 'WifiIndoor', }) expect(txnIds).toBeDefined() @@ -207,7 +208,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { describe('Wifi Onboarding with wifi api version 1 (default)', () => { it('Checks for valid firmware', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v1', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -222,7 +223,7 @@ describe('Wifi Onboarding with wifi api version 1 (default)', () => { }) it('Fetches the add gateway txn from the wifi access point', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v1', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -238,7 +239,7 @@ describe('Wifi Onboarding with wifi api version 1 (default)', () => { }) it('Fetches the gateway location information', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v1', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -248,7 +249,7 @@ describe('Wifi Onboarding with wifi api version 1 (default)', () => { cluster: 'devnet', }) - const assertData = await client.getMobileAssertData({ + const assertData = await client.getWifiAssertData({ gateway: 'asdf', location: 'asdf123', deviceType: 'WifiOutdoor', @@ -259,7 +260,7 @@ describe('Wifi Onboarding with wifi api version 1 (default)', () => { }) it('Creates and onboards a mobile wifi access point', async () => { - const client = new MobileWifiOnboarding({ + const client = new MobileHotspotOnboarding({ wifiApiVersion: 'v1', shouldMock: true, wifiBaseUrl: 'http://192.168.68.1:3333', @@ -307,6 +308,7 @@ describe('Wifi Onboarding with wifi api version 1 (default)', () => { const { txnIds } = await client.submitAndCompleteOnboarding({ hotspotAddress: txn.gateway?.b58!, signedTxns: signed, + deviceType: 'WifiIndoor', }) expect(txnIds).toBeDefined() diff --git a/packages/onboarding/src/index.ts b/packages/onboarding/src/index.ts index 4dc07996..e559bc9d 100644 --- a/packages/onboarding/src/index.ts +++ b/packages/onboarding/src/index.ts @@ -6,7 +6,7 @@ import OnboardingClient from './OnboardingClient' -export { default as MobileWifiOnboarding } from './MobileWifiOnboarding' +export { default as MobileHotspotOnboarding } from './MobileHotspotOnboarding' export { default as SolanaOnboarding } from './SolanaOnboarding' export { default as degToCompass } from './degToCompass' From 72a9d9a3f32316bafac2d8d1402c31381fbdf42b Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 17 Jan 2024 08:45:21 -0600 Subject: [PATCH 07/25] Use config api dev url when onboarding to devnet. --- packages/onboarding/src/ConfigurationClient.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/ConfigurationClient.ts b/packages/onboarding/src/ConfigurationClient.ts index 313be051..307f0b0d 100644 --- a/packages/onboarding/src/ConfigurationClient.ts +++ b/packages/onboarding/src/ConfigurationClient.ts @@ -25,7 +25,10 @@ export default class ConfigurationClient { this.cluster = cluster this.wallet = wallet this.axios = axios.create({ - baseURL: 'https://hmh-configuration-api.wifi.freedomfi.com', + baseURL: + cluster === 'devnet' + ? 'https://hmh-configuration-api.dev.wifi.freedomfi.com' + : 'https://hmh-configuration-api.wifi.freedomfi.com', }) axiosRetry(this.axios, { From bbe0b116546dcd8b9a91b0b97e03aa0e71cac911 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 29 Feb 2024 15:02:27 -0600 Subject: [PATCH 08/25] Add hotspot to onboarding server after retrieving add_gateway_txn --- .../onboarding/src/MobileHotspotOnboarding.ts | 91 ++++++++++++++----- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index 8a537189..f38e380b 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -27,6 +27,16 @@ const ProgressKeys = [ ] as const type ProgressStep = (typeof ProgressKeys)[number] +type AddToOnboardingServerOpts = { + authToken?: string + batch?: string + deviceType?: DeviceType + heliumSerial?: string + macEth0?: string + macWlan0?: string + rpiSerial?: string +} + export default class MobileHotspotOnboarding { private _configurationClient!: ConfigurationClient private _wifiClient?: WifiHttpClient @@ -144,7 +154,10 @@ export default class MobileHotspotOnboarding { return this._wifiClient } - signGatewayAddTransaction = async (deviceType: ManufacturedDeviceType) => { + signGatewayAddTransaction = async ( + deviceType: ManufacturedDeviceType, + opts?: AddToOnboardingServerOpts, + ) => { this.setProgressToStep('get_add_gateway') this.writeLog('Getting add gateway txn', { deviceType, cluster: this._cluster }) const { txn: txnStr, apiVersion } = await this.getWifiClient().signGatewayAddTransaction( @@ -154,6 +167,12 @@ export default class MobileHotspotOnboarding { this.writeLog('Got add gateway str', { txnStr }) const txn = AddGatewayV1.fromString(txnStr) this.setProgressToStep('got_add_gateway') + + await this.addToOnboardingServer({ + ...opts, + hotspotAddress: txn.gateway?.b58 || '', + }) + return { txn, apiVersion } } @@ -394,6 +413,49 @@ export default class MobileHotspotOnboarding { return undefined } + addToOnboardingServer = async ({ + authToken, + hotspotAddress, + batch, + deviceType, + heliumSerial, + macEth0, + macWlan0, + rpiSerial, + }: AddToOnboardingServerOpts & { hotspotAddress: string }) => { + if ( + this._shouldMock || + this._cluster !== 'devnet' || + !authToken || + !batch || + !deviceType || + !heliumSerial || + !macEth0 || + !macWlan0 || + !rpiSerial + ) { + return + } + + // If onboarding to devnet, we create the hotspot on the onboarding server + try { + await this._onboardingClient.addToOnboardingServer({ + authToken, + onboardingKey: hotspotAddress, + batch, + deviceType, + heliumSerial, + macEth0, + macWlan0, + rpiSerial, + }) + await sleep(1000) + } catch (e) { + // if it's already been added, we don't need to do anything + this.writeError(e) + } + } + createHotspotGetOnboardTxns = async ({ addGatewayTxn, authToken, @@ -401,16 +463,9 @@ export default class MobileHotspotOnboarding { elevation, gain, ...opts - }: { + }: AddToOnboardingServerOpts & { addGatewayTxn: string - authToken?: string location?: string - deviceType: DeviceType - batch: string - heliumSerial: string - macEth0: string - macWlan0: string - rpiSerial: string elevation?: number | undefined gain?: number | undefined }) => { @@ -420,19 +475,11 @@ export default class MobileHotspotOnboarding { } const hotspotAddress = addGatewayV1.gateway.b58 - if (!this._shouldMock && authToken && this._cluster === 'devnet') { - // If onboarding to devnet, we create the hotspot on the onboarding server - try { - await this._onboardingClient.addToOnboardingServer({ - ...opts, - authToken, - onboardingKey: hotspotAddress, - }) - await sleep(1000) - } catch (e) { - this.writeError(e) - } - } + await this.addToOnboardingServer({ + ...opts, + authToken, + hotspotAddress, + }) let hotspotPubKey: PublicKey | undefined try { From 73b7543c809d1445d2579d661fda20f28cc3c882 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Tue, 12 Mar 2024 15:59:43 -0500 Subject: [PATCH 09/25] Update assert fee calc to handle big numbers. --- .../onboarding/src/HotspotOnboardingUtil.ts | 28 ++++++++++--------- .../onboarding/src/__mocks__/AssertMock.ts | 4 +-- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index ed47f2cd..c7084726 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -8,7 +8,7 @@ import { heliumAddressToSolPublicKey, } from '@helium/spl-utils' import { subDaoKey } from '@helium/helium-sub-daos-sdk' -import { Connection, PublicKey, Cluster, LAMPORTS_PER_SOL } from '@solana/web3.js' +import { Connection, PublicKey, Cluster } from '@solana/web3.js' import { createAssociatedTokenAccountIdempotentInstruction, getAccount, @@ -150,13 +150,16 @@ export const getHotspotNetworkDetails = async ({ } } -const getOraclePriceFromSolana = async (opts: { connection: Connection; cluster: Cluster }) => { +const getOraclePriceInCentsFromSolana = async (opts: { + connection: Connection + cluster: Cluster +}) => { const price = await Currency.getOraclePrice({ tokenType: 'HNT', ...opts }) if (!price?.aggregate.price) { throw new Error('Failed to fetch oracle price') } - return new BN(price.aggregate.price) + return new BN(price.aggregate.price * 100) } const getBalance = async (wallet: PublicKey, connection: Connection, mint: PublicKey) => { @@ -169,11 +172,11 @@ const getBalance = async (wallet: PublicKey, connection: Connection, mint: Publi } const getBalances = async (wallet: PublicKey, connection: Connection) => { - const sol = await connection.getBalance(wallet) - const hnt = (await getBalance(wallet, connection, HNT_MINT)).div(BONES_IN_HNT) + const lamports = await connection.getBalance(wallet) + const bones = await getBalance(wallet, connection, HNT_MINT) const dc = await getBalance(wallet, connection, DC_MINT) - return { hnt, dc, sol: new BN(sol) } + return { bones, dc, lamports: new BN(lamports) } } const burnHNTForDataCredits = async ({ @@ -307,7 +310,6 @@ export const getAssertData = async ({ const isPayer = insufficientMakerDcBal || !maker || numLocationChanges >= maker.locationNonceLimit const isFree = !isPayer - const lamportBalance = balances.sol.mul(new BN(LAMPORTS_PER_SOL)) const dcFee = networkDetails?.locationStakingFee || new BN(0) let lamportFee = TXN_FEE_IN_LAMPORTS @@ -316,7 +318,7 @@ export const getAssertData = async ({ if (!isFree) { const ataFee = await getAtaAccountCreationFee(owner, connection) lamportFee = lamportFee.add(ataFee) - hasSufficientSol = lamportBalance.gte(lamportFee) + hasSufficientSol = balances.lamports.gte(lamportFee) hasSufficientDc = balances.dc.gte(dcFee) } @@ -326,10 +328,10 @@ export const getAssertData = async ({ const dcBalance = balances.dc || new BN(0) dcNeeded = dcFee.sub(dcBalance) - const dcInDollars = dcNeeded.div(new BN(100000)) - const oraclePrice = await getOraclePriceFromSolana({ connection, cluster }) - const hntNeeded = dcInDollars.toNumber() / oraclePrice.toNumber() - hasSufficientHnt = balances.hnt.toNumber() > hntNeeded + const dcInCents = dcNeeded.div(new BN(100000)).mul(new BN(100)) + const oraclePriceInCents = await getOraclePriceInCentsFromSolana({ connection, cluster }) + const bonesNeeded = dcInCents.mul(BONES_IN_HNT).divRound(oraclePriceInCents) + hasSufficientHnt = balances.bones.gte(bonesNeeded) if (hasSufficientHnt) { const txn = await burnHNTForDataCredits({ @@ -341,7 +343,7 @@ export const getAssertData = async ({ if (txn) { solanaTransactions = [txn.serialize({ verifySignatures: false }), ...solanaTransactions] lamportFee = lamportFee.add(TXN_FEE_IN_LAMPORTS) - hasSufficientSol = lamportBalance.gte(lamportFee) + hasSufficientSol = balances.lamports.gte(lamportFee) } } } diff --git a/packages/onboarding/src/__mocks__/AssertMock.ts b/packages/onboarding/src/__mocks__/AssertMock.ts index a887d3ba..0262f42c 100644 --- a/packages/onboarding/src/__mocks__/AssertMock.ts +++ b/packages/onboarding/src/__mocks__/AssertMock.ts @@ -5,9 +5,9 @@ import { AssertData } from '../types' export const getAssertData = async (): Promise => { return { balances: { - hnt: new BN(100000000000), + bones: new BN(100000000000), dc: new BN(1000000000), - sol: new BN(1000000000000), + lamports: new BN(1000000000000), }, isFree: false, solanaTransactions: [], From 880f9e50fef56b3086b08e3399754c0086ae1a88 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Tue, 12 Mar 2024 17:47:53 -0500 Subject: [PATCH 10/25] v4.11.1-alpha.0 --- lerna.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lerna.json b/lerna.json index 95f5849f..bc8aac88 100644 --- a/lerna.json +++ b/lerna.json @@ -1,8 +1,5 @@ { - "packages": [ - "integration_tests", - "packages/*" - ], + "packages": ["integration_tests", "packages/*"], "version": "4.12.0", "npmClient": "yarn" } From 83e638ea2dfb20c6cbdb6b2fd7a3155a853b0428 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 10 Apr 2024 10:46:48 -0500 Subject: [PATCH 11/25] Retry hotspot create if it fails to land. --- .../onboarding/src/MobileHotspotOnboarding.ts | 84 +++++++------------ packages/onboarding/src/index.ts | 1 + packages/onboarding/src/types.ts | 14 ++++ 3 files changed, 47 insertions(+), 52 deletions(-) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index f38e380b..b702a30c 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -10,23 +10,11 @@ import { HeightType, ManufacturedDeviceType, OutdoorManufacturedDeviceType, + ProgressKeys, + ProgressStep, } from './types' import ConfigurationClient from './ConfigurationClient' -const ProgressKeys = [ - 'get_add_gateway', - 'got_add_gateway', - 'fetch_create', - 'submit_create', - 'verify_create', - 'fetch_mobile', - 'got_mobile', - 'submit_signed_messages', - 'verify_mobile', - 'complete', -] as const -type ProgressStep = (typeof ProgressKeys)[number] - type AddToOnboardingServerOpts = { authToken?: string batch?: string @@ -300,41 +288,36 @@ export default class MobileHotspotOnboarding { this._logCallback?.('Creating hotspot on Solana', { transaction }) this.setProgressToStep('fetch_create') - let solanaTransactions: number[][] | undefined = undefined + let txIds: string[] = [] - let err: unknown = undefined - try { - const createTxns = await this._onboardingClient.createHotspot({ - transaction, - }) - solanaTransactions = createTxns?.data?.solanaTransactions - err = createTxns - if (solanaTransactions?.length) { - this.writeLog('Created hotspot onboard txns') - } else { - this.writeLog('Could not create hotspot onboard txns', createTxns) - } - } catch (e) { - err = e - this.writeError(e) - } + while (!txIds.length) { + try { + const createTxns = await this._onboardingClient.createHotspot({ + transaction, + }) + const solanaTransactions = createTxns?.data?.solanaTransactions - try { - if (!solanaTransactions?.length) { - throw new Error(`No solana transactions returned from create hotspot\n\n${err}`) - } + if (solanaTransactions?.length) { + this.writeLog('Created hotspot onboard txns') + } else { + this.writeLog('Could not create hotspot onboard txns', createTxns) + throw new Error( + `No solana transactions returned from create hotspot\n\n${JSON.stringify(createTxns)}`, + ) + } - this.writeLog('Submitting hotspot to solana') - this.setProgressToStep('submit_create') - const txnids = await this._solanaOnboarding.submitAll({ - txns: solanaTransactions.map((t) => Buffer.from(t)), - }) - this.writeLog('Hotspot has successfully been submitted to solana', { data: txnids }) - return txnids - } catch (e) { - this.writeError(e) - throw e + this.writeLog('Submitting hotspot to solana') + this.setProgressToStep('submit_create') + txIds = await this._solanaOnboarding.submitAll({ + txns: solanaTransactions.map((t) => Buffer.from(t)), + }) + this.writeLog('Hotspot has successfully been submitted to solana', { data: txIds }) + } catch (e) { + this.writeError(e) + } } + + return txIds } verifyHotspotCreated = async (hotspotAddress: string) => { @@ -505,15 +488,16 @@ export default class MobileHotspotOnboarding { } // Check if this hotspot has already been onboarded to MOBILE - let needsOnboarding = true try { const hotspotInfo = await this._solanaOnboarding.getHotspotDetails({ networkType: 'MOBILE', address: hotspotAddress, }) if (hotspotInfo) { - needsOnboarding = false - this.writeLog('Hotspot has been onboarded to MOBILE') + this.writeLog('Hotspot has already been onboarded') + if (!this._shouldMock) { + throw new Error('Hotspot has already been onboarded') + } } else { this.writeLog('Hotspot MOBILE details not found.') } @@ -521,10 +505,6 @@ export default class MobileHotspotOnboarding { this.writeLog('Hotspot MOBILE details not found.') } - if (!this._shouldMock && !needsOnboarding) { - return [] - } - const txns = await this.getMobileOnboardTxns({ location, hotspotAddress, diff --git a/packages/onboarding/src/index.ts b/packages/onboarding/src/index.ts index e559bc9d..2fe758e6 100644 --- a/packages/onboarding/src/index.ts +++ b/packages/onboarding/src/index.ts @@ -19,6 +19,7 @@ export { DeviceType, ManufacturedDeviceType, HeightType, + ProgressStep, } from './types' export { Message } from './OutdoorConfig' diff --git a/packages/onboarding/src/types.ts b/packages/onboarding/src/types.ts index 53f732a4..2e95fe3f 100644 --- a/packages/onboarding/src/types.ts +++ b/packages/onboarding/src/types.ts @@ -68,3 +68,17 @@ export type SubmitStatus = { currentBatchProgress: number currentBatchSize: number } + +export const ProgressKeys = [ + 'get_add_gateway', + 'got_add_gateway', + 'fetch_create', + 'submit_create', + 'verify_create', + 'fetch_mobile', + 'got_mobile', + 'submit_signed_messages', + 'verify_mobile', + 'complete', +] as const +export type ProgressStep = (typeof ProgressKeys)[number] From c18b41af4d46fec9629c8a24b1fde8605596f8d7 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 10 Apr 2024 11:13:06 -0500 Subject: [PATCH 12/25] Prefer hnt naming convention over bones. --- packages/onboarding/src/HotspotOnboardingUtil.ts | 10 +++++----- packages/onboarding/src/__mocks__/AssertMock.ts | 2 +- packages/onboarding/src/types.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index c7084726..84fcd634 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -22,7 +22,7 @@ import { } from '@helium/helium-entity-manager-sdk' import * as Currency from '@helium/currency-utils' import { - BONES_IN_HNT, + HNT_AS_BONES, DcProgram, DeviceType, HemProgram, @@ -173,10 +173,10 @@ const getBalance = async (wallet: PublicKey, connection: Connection, mint: Publi const getBalances = async (wallet: PublicKey, connection: Connection) => { const lamports = await connection.getBalance(wallet) - const bones = await getBalance(wallet, connection, HNT_MINT) + const hnt = await getBalance(wallet, connection, HNT_MINT) const dc = await getBalance(wallet, connection, DC_MINT) - return { bones, dc, lamports: new BN(lamports) } + return { hnt, dc, lamports: new BN(lamports) } } const burnHNTForDataCredits = async ({ @@ -330,8 +330,8 @@ export const getAssertData = async ({ const dcInCents = dcNeeded.div(new BN(100000)).mul(new BN(100)) const oraclePriceInCents = await getOraclePriceInCentsFromSolana({ connection, cluster }) - const bonesNeeded = dcInCents.mul(BONES_IN_HNT).divRound(oraclePriceInCents) - hasSufficientHnt = balances.bones.gte(bonesNeeded) + const hntNeeded = dcInCents.mul(HNT_AS_BONES).divRound(oraclePriceInCents) + hasSufficientHnt = balances.hnt.gte(hntNeeded) if (hasSufficientHnt) { const txn = await burnHNTForDataCredits({ diff --git a/packages/onboarding/src/__mocks__/AssertMock.ts b/packages/onboarding/src/__mocks__/AssertMock.ts index 0262f42c..2c134635 100644 --- a/packages/onboarding/src/__mocks__/AssertMock.ts +++ b/packages/onboarding/src/__mocks__/AssertMock.ts @@ -5,7 +5,7 @@ import { AssertData } from '../types' export const getAssertData = async (): Promise => { return { balances: { - bones: new BN(100000000000), + hnt: new BN(100000000000), dc: new BN(1000000000), lamports: new BN(1000000000000), }, diff --git a/packages/onboarding/src/types.ts b/packages/onboarding/src/types.ts index 2e95fe3f..8ae1daf2 100644 --- a/packages/onboarding/src/types.ts +++ b/packages/onboarding/src/types.ts @@ -56,7 +56,7 @@ export type HeightType = 'MSL' | 'AGL' | 'NONE' | 'UNRECOGNIZED' export type NetworkType = 'IOT' | 'MOBILE' export type DeviceType = 'Cbrs' | 'WifiIndoor' | 'WifiOutdoor' | null // null is for IOT devices -export const BONES_IN_HNT = new BN(100000000) +export const HNT_AS_BONES = new BN(100000000) export const TXN_FEE_IN_LAMPORTS = new BN(5000) export type HemProgram = Awaited> From 656240b7d5589218b5bc172078097e6a80e09d90 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 11 Apr 2024 12:58:45 -0500 Subject: [PATCH 13/25] Limit amount of hotspot create retries. --- packages/onboarding/src/MobileHotspotOnboarding.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index b702a30c..4a91c3b0 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -289,8 +289,10 @@ export default class MobileHotspotOnboarding { this.setProgressToStep('fetch_create') let txIds: string[] = [] + let tries = 0 - while (!txIds.length) { + while (!txIds.length && tries < 12) { + tries++ try { const createTxns = await this._onboardingClient.createHotspot({ transaction, @@ -315,6 +317,14 @@ export default class MobileHotspotOnboarding { } catch (e) { this.writeError(e) } + + if (!txIds.length) { + await sleep(5000) // wait 5 seconds before trying again + } + } + + if (!txIds.length) { + throw new Error('Failed to create hotspot') } return txIds From 237aa888ff47073004d462dca666e47a2e6fd49e Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 11 Apr 2024 14:26:16 -0500 Subject: [PATCH 14/25] Update to helium version 4.12.0 --- packages/onboarding/yarn.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/onboarding/yarn.lock b/packages/onboarding/yarn.lock index d89631df..530f9d91 100644 --- a/packages/onboarding/yarn.lock +++ b/packages/onboarding/yarn.lock @@ -75,10 +75,10 @@ js-sha256 "^0.9.0" multiformats "^9.6.4" -"@helium/address@^4.11.0", "@helium/address@^4.11.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@helium/address/-/address-4.11.1.tgz#e6c6debaee2f50ed16383d5660ba81d29e604948" - integrity sha512-QMrdBx5l5XIy0K9fL3R64Whuk556BLz/pa6yhOQtog1hb3C904m1ykAU8eg2hgiA265Yp98XZkIK3GKTHbH+0A== +"@helium/address@^4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@helium/address/-/address-4.12.0.tgz#14738298794fb26089dd60fafaec99fdff27efa9" + integrity sha512-gTgPHEn19vBzVwYYl6nVDjuWG9dXpgnXdEdWI65vcpseXIg1+E3iVn43FC3TK1wXzIUQkXz6RzRKASc/w85rWA== dependencies: bs58 "^5.0.0" js-sha256 "^0.9.0" @@ -244,12 +244,12 @@ borsh "^0.7.0" bs58 "^4.0.1" -"@helium/transactions@^4.11.0": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@helium/transactions/-/transactions-4.11.1.tgz#38c48d0c2c395ce1e0a78fd57510c09d958c24e8" - integrity sha512-uL6OKo5o8AKn7oOuuW6/T7MSwPikbYU2HsSDu2O7ZhnGiyzKcKXQMkIHSBuFKz9KT+DKVpVSwjeLXr4a6/D/eQ== +"@helium/transactions@^4.12.0": + version "4.12.0" + resolved "https://registry.yarnpkg.com/@helium/transactions/-/transactions-4.12.0.tgz#391d9cdbadaa4cb7716685e6a44199b300d6f7b3" + integrity sha512-LFassrm0FzcEX8uCqoPvRbXrONTmp2UuZP6Hc+CSCIGfHnXESf1Zpac9kZLBsaLm2vLj7d62FUtNwa4J3edILg== dependencies: - "@helium/address" "^4.11.1" + "@helium/address" "^4.12.0" "@helium/proto" "^1.6.0" "@types/libsodium-wrappers" "^0.7.8" long "^4.0.0" From 07cb9296684f4ce20031019db476d35ae82df271 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 11 Apr 2024 14:27:43 -0500 Subject: [PATCH 15/25] v4.12.1-alpha.0 --- lerna.json | 7 +++++-- packages/address/package.json | 2 +- packages/crypto-react-native/package.json | 4 ++-- packages/crypto/package.json | 4 ++-- packages/currency/package.json | 2 +- packages/http/package.json | 6 +++--- packages/onboarding/package.json | 8 ++++---- packages/transactions/package.json | 6 +++--- packages/wallet-link/package.json | 8 ++++---- 9 files changed, 25 insertions(+), 22 deletions(-) diff --git a/lerna.json b/lerna.json index bc8aac88..eeb3faff 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,8 @@ { - "packages": ["integration_tests", "packages/*"], - "version": "4.12.0", + "packages": [ + "integration_tests", + "packages/*" + ], + "version": "4.12.1-alpha.0", "npmClient": "yarn" } diff --git a/packages/address/package.json b/packages/address/package.json index fbf3b731..e20a832e 100644 --- a/packages/address/package.json +++ b/packages/address/package.json @@ -1,6 +1,6 @@ { "name": "@helium/address", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Helium public key utilities", "keywords": [ "helium", diff --git a/packages/crypto-react-native/package.json b/packages/crypto-react-native/package.json index f6af42b9..f38a36f2 100644 --- a/packages/crypto-react-native/package.json +++ b/packages/crypto-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@helium/crypto-react-native", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Cryptography utilities including mnemonics, keypairs and base58-check encoding for React Native", "keywords": [ "helium", @@ -27,7 +27,7 @@ "build": "yarn run clean && tsc" }, "dependencies": { - "@helium/address": "^4.12.0", + "@helium/address": "^4.12.1-alpha.0", "js-sha256": "^0.9.0", "react-native-sodium": "^0.4.0", "safe-buffer": "^5.2.1" diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 381ffefd..b61eb7c9 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -1,6 +1,6 @@ { "name": "@helium/crypto", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Cryptography utilities including mnemonics, keypairs and base58-check encoding", "keywords": [ "helium", @@ -26,7 +26,7 @@ "build": "yarn run clean && tsc" }, "dependencies": { - "@helium/address": "^4.12.0", + "@helium/address": "^4.12.1-alpha.0", "create-hash": "^1.2.0", "libsodium-wrappers": "^0.7.6" }, diff --git a/packages/currency/package.json b/packages/currency/package.json index 3f327900..0e00ed55 100644 --- a/packages/currency/package.json +++ b/packages/currency/package.json @@ -1,6 +1,6 @@ { "name": "@helium/currency", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Utilities for handling different currency types on the Helium blockchain", "keywords": [ "helium", diff --git a/packages/http/package.json b/packages/http/package.json index d4daa01d..1383e86a 100644 --- a/packages/http/package.json +++ b/packages/http/package.json @@ -1,6 +1,6 @@ { "name": "@helium/http", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "HTTP library for interacting with the Helium blockchain API", "keywords": [ "helium", @@ -26,8 +26,8 @@ "build": "yarn run clean && tsc" }, "dependencies": { - "@helium/address": "^4.12.0", - "@helium/currency": "^4.12.0", + "@helium/address": "^4.12.1-alpha.0", + "@helium/currency": "^4.12.1-alpha.0", "axios": "^0.21.1", "camelcase-keys": "^6.2.2", "qs": "^6.9.3", diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 3c7cc2d3..bd1816c1 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium", @@ -41,14 +41,14 @@ }, "dependencies": { "@coral-xyz/anchor": "^0.28.1-beta.2", - "@helium/address": "^4.12.0", - "@helium/crypto": "^4.10.2", + "@helium/address": "^4.12.1-alpha.0", + "@helium/crypto": "^4.12.1-alpha.0", "@helium/currency-utils": "^0.6.6", "@helium/data-credits-sdk": "^0.6.6", "@helium/helium-entity-manager-sdk": "^0.6.6", "@helium/hotspot-utils": "^0.6.6", "@helium/spl-utils": "^0.6.6", - "@helium/transactions": "^4.12.0", + "@helium/transactions": "^4.12.1-alpha.0", "@metaplex-foundation/mpl-bubblegum": "^0.7.0", "@solana/web3.js": "^1.78.4", "axios": "^1.5.0", diff --git a/packages/transactions/package.json b/packages/transactions/package.json index c536d081..95d931f1 100644 --- a/packages/transactions/package.json +++ b/packages/transactions/package.json @@ -1,6 +1,6 @@ { "name": "@helium/transactions", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Construct and serialize Helium blockchain transaction primatives", "keywords": [ "helium", @@ -27,14 +27,14 @@ "build": "yarn run clean && tsc" }, "dependencies": { - "@helium/address": "^4.12.0", + "@helium/address": "^4.12.1-alpha.0", "@helium/proto": "^1.6.0", "@types/libsodium-wrappers": "^0.7.8", "long": "^4.0.0", "path": "^0.12.7" }, "devDependencies": { - "@helium/crypto": "^4.12.0", + "@helium/crypto": "^4.12.1-alpha.0", "@types/node": "^20.5.9" }, "gitHead": "07d361645c7851908721d7fbd70c6f9a39c3b210" diff --git a/packages/wallet-link/package.json b/packages/wallet-link/package.json index 5f0a51e0..3707be26 100644 --- a/packages/wallet-link/package.json +++ b/packages/wallet-link/package.json @@ -1,6 +1,6 @@ { "name": "@helium/wallet-link", - "version": "4.12.0", + "version": "4.12.1-alpha.0", "description": "Utilities for linking a 3rd party app to the helium wallet.", "keywords": [ "helium", @@ -26,8 +26,8 @@ "build": "yarn run clean && tsc" }, "dependencies": { - "@helium/address": "^4.12.0", - "@helium/transactions": "^4.12.0", + "@helium/address": "^4.12.1-alpha.0", + "@helium/transactions": "^4.12.1-alpha.0", "date-fns": "^2.28.0", "query-string": "^7.1.1" }, @@ -35,7 +35,7 @@ "@helium/crypto": "^4.3.1" }, "devDependencies": { - "@helium/crypto": "^4.12.0", + "@helium/crypto": "^4.12.1-alpha.0", "@types/node": "^20.5.9" }, "gitHead": "07d361645c7851908721d7fbd70c6f9a39c3b210" From 0c8bfa4cee9b19786f55208ebef0f572572c1c24 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 25 Apr 2024 09:58:15 -0500 Subject: [PATCH 16/25] Fix incorrect fee for assertion. --- .../onboarding/src/HotspotOnboardingUtil.ts | 60 +++++++------------ .../onboarding/src/__mocks__/AssertMock.ts | 2 + 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index 84fcd634..2eabe3c9 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -8,11 +8,9 @@ import { heliumAddressToSolPublicKey, } from '@helium/spl-utils' import { subDaoKey } from '@helium/helium-sub-daos-sdk' -import { Connection, PublicKey, Cluster } from '@solana/web3.js' +import { Connection, PublicKey, Cluster, Transaction } from '@solana/web3.js' import { createAssociatedTokenAccountIdempotentInstruction, - getAccount, - getMinimumBalanceForRentExemptAccount, getAssociatedTokenAddressSync, } from '@solana/spl-token' import { @@ -21,15 +19,7 @@ import { rewardableEntityConfigKey, } from '@helium/helium-entity-manager-sdk' import * as Currency from '@helium/currency-utils' -import { - HNT_AS_BONES, - DcProgram, - DeviceType, - HemProgram, - Maker, - NetworkType, - TXN_FEE_IN_LAMPORTS, -} from './types' +import { HNT_AS_BONES, DcProgram, DeviceType, HemProgram, Maker, NetworkType } from './types' const lowerFirst = (str: string) => str.charAt(0).toLowerCase() + str.slice(1) @@ -218,18 +208,6 @@ const burnHNTForDataCredits = async ({ return txn } -const getAtaAccountCreationFee = async (solanaAddress: PublicKey, connection: Connection) => { - const ataAddress = getAssociatedTokenAddressSync(DC_MINT, solanaAddress, true) - - try { - await getAccount(connection, ataAddress) - return new BN(0) - } catch { - const minRent = await getMinimumBalanceForRentExemptAccount(connection) - return new BN(minRent) - } -} - export const getAssertData = async ({ deviceType, gateway, @@ -298,27 +276,21 @@ export const getAssertData = async ({ hemProgram, }) - const requiredDc = networkDetails?.locationStakingFee || new BN(0) - let makerDc = new BN(0) if (makerKey) { makerDc = await getBalance(makerKey, connection, DC_MINT) } - const insufficientMakerDcBal = makerDc.lt(requiredDc) + const dcFee = networkDetails?.locationStakingFee || new BN(0) + const insufficientMakerDcBal = makerDc.lt(dcFee) const numLocationChanges = networkDetails?.numLocationAsserts || 0 const isPayer = insufficientMakerDcBal || !maker || numLocationChanges >= maker.locationNonceLimit const isFree = !isPayer - - const dcFee = networkDetails?.locationStakingFee || new BN(0) - let lamportFee = TXN_FEE_IN_LAMPORTS - - let hasSufficientSol = true let hasSufficientDc = true + let hasSufficientSol = true + let lamportFee = new BN(0) + if (!isFree) { - const ataFee = await getAtaAccountCreationFee(owner, connection) - lamportFee = lamportFee.add(ataFee) - hasSufficientSol = balances.lamports.gte(lamportFee) hasSufficientDc = balances.dc.gte(dcFee) } @@ -342,11 +314,23 @@ export const getAssertData = async ({ }) if (txn) { solanaTransactions = [txn.serialize({ verifySignatures: false }), ...solanaTransactions] - lamportFee = lamportFee.add(TXN_FEE_IN_LAMPORTS) - hasSufficientSol = balances.lamports.gte(lamportFee) } } } + + const estimatedFees = await Promise.all( + solanaTransactions.map(async (buff) => { + const tx = Transaction.from(buff) + const estimatedFee = await connection.getFeeForMessage(tx.compileMessage(), 'confirmed') + return estimatedFee.value + }), + ) + lamportFee = estimatedFees.reduce((acc, fee) => acc.add(new BN(fee || 0)), new BN(0)) + + if (!isFree) { + hasSufficientSol = balances.lamports.gte(lamportFee) + } + const hasSufficientBalance = (hasSufficientDc || hasSufficientHnt) && hasSufficientSol return { @@ -355,8 +339,10 @@ export const getAssertData = async ({ hasSufficientSol, hasSufficientDc, hasSufficientHnt, + dcFee, dcNeeded, isFree, + lamportFee, solanaTransactions: solanaTransactions.map((tx) => tx.toString('base64')), } } diff --git a/packages/onboarding/src/__mocks__/AssertMock.ts b/packages/onboarding/src/__mocks__/AssertMock.ts index 2c134635..78499454 100644 --- a/packages/onboarding/src/__mocks__/AssertMock.ts +++ b/packages/onboarding/src/__mocks__/AssertMock.ts @@ -15,7 +15,9 @@ export const getAssertData = async (): Promise => { hasSufficientDc: true, hasSufficientHnt: true, hasSufficientSol: true, + dcFee: new BN(0), dcNeeded: new BN(0), + lamportFee: new BN(0), } } From 30a5d6478af3193e62a2062308625cc17f2ab78f Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Thu, 25 Apr 2024 10:14:07 -0500 Subject: [PATCH 17/25] v4.12.1-alpha.1 --- lerna.json | 2 +- packages/onboarding/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index eeb3faff..84347b17 100644 --- a/lerna.json +++ b/lerna.json @@ -3,6 +3,6 @@ "integration_tests", "packages/*" ], - "version": "4.12.1-alpha.0", + "version": "4.12.1-alpha.1", "npmClient": "yarn" } diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index bd1816c1..2a97643c 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.1-alpha.0", + "version": "4.12.1-alpha.1", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium", From 9c5023866f5c20011f908577097b61d654d25364 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Tue, 14 May 2024 15:10:27 -0500 Subject: [PATCH 18/25] Support azimuth and elevation when onboarding and asserting. --- packages/onboarding/src/HotspotOnboardingUtil.ts | 3 +++ packages/onboarding/src/MobileHotspotOnboarding.ts | 9 +++++++++ packages/onboarding/src/OnboardingClient.ts | 4 +++- packages/onboarding/src/SolanaOnboarding.ts | 3 +++ packages/onboarding/src/types.ts | 1 + 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/HotspotOnboardingUtil.ts b/packages/onboarding/src/HotspotOnboardingUtil.ts index 2eabe3c9..db3ccb16 100644 --- a/packages/onboarding/src/HotspotOnboardingUtil.ts +++ b/packages/onboarding/src/HotspotOnboardingUtil.ts @@ -211,6 +211,7 @@ const burnHNTForDataCredits = async ({ export const getAssertData = async ({ deviceType, gateway, + azimuth, hemProgram, onboardingClient, owner, @@ -227,6 +228,7 @@ export const getAssertData = async ({ owner: PublicKey decimalGain?: number elevation?: number + azimuth?: number nextLocation: string deviceType: DeviceType onboardingClient: OnboardingClient @@ -258,6 +260,7 @@ export const getAssertData = async ({ location: nextLocation, elevation, gain, + azimuth, }) const errFound = !solResponse.success ? solResponse : undefined diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index 4a91c3b0..cc2592d7 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -204,7 +204,9 @@ export default class MobileHotspotOnboarding { elevation, location, deviceType, + azimuth, }: { + azimuth?: number gateway: string decimalGain?: number elevation?: number @@ -212,6 +214,7 @@ export default class MobileHotspotOnboarding { deviceType: 'WifiIndoor' | 'WifiOutdoor' }) => { return this._solanaOnboarding.getAssertData({ + azimuth, gateway, decimalGain, elevation, @@ -244,6 +247,7 @@ export default class MobileHotspotOnboarding { getMobileOnboardTxns = async ({ hotspotAddress, + azimuth, location, elevation, gain, @@ -252,6 +256,7 @@ export default class MobileHotspotOnboarding { location?: string elevation?: number gain?: number + azimuth?: number }) => { this.writeLog('Getting MOBILE onboard txns') this.setProgressToStep('fetch_mobile') @@ -261,6 +266,7 @@ export default class MobileHotspotOnboarding { location, type: 'MOBILE', elevation, + azimuth, gain, }) @@ -452,6 +458,7 @@ export default class MobileHotspotOnboarding { createHotspotGetOnboardTxns = async ({ addGatewayTxn, authToken, + azimuth, location, elevation, gain, @@ -459,6 +466,7 @@ export default class MobileHotspotOnboarding { }: AddToOnboardingServerOpts & { addGatewayTxn: string location?: string + azimuth?: number | undefined elevation?: number | undefined gain?: number | undefined }) => { @@ -518,6 +526,7 @@ export default class MobileHotspotOnboarding { const txns = await this.getMobileOnboardTxns({ location, hotspotAddress, + azimuth, elevation, gain, }) diff --git a/packages/onboarding/src/OnboardingClient.ts b/packages/onboarding/src/OnboardingClient.ts index d50248d1..59a27c95 100644 --- a/packages/onboarding/src/OnboardingClient.ts +++ b/packages/onboarding/src/OnboardingClient.ts @@ -154,6 +154,7 @@ export default class OnboardingClient { elevation: opts.elevation, gain: opts.gain, payer: opts.payer, + azimuth: opts.azimuth, }, ) } @@ -174,7 +175,7 @@ export default class OnboardingClient { payer?: string }, ) { - const { solanaAddress, elevation, gain, hotspotAddress, type, payer } = opts + const { solanaAddress, elevation, gain, hotspotAddress, type, payer, azimuth } = opts let location: string | undefined = undefined if (opts.location) { @@ -182,6 +183,7 @@ export default class OnboardingClient { } const body = { + azimuth, entityKey: hotspotAddress, location, elevation, diff --git a/packages/onboarding/src/SolanaOnboarding.ts b/packages/onboarding/src/SolanaOnboarding.ts index 097433c7..35855e36 100644 --- a/packages/onboarding/src/SolanaOnboarding.ts +++ b/packages/onboarding/src/SolanaOnboarding.ts @@ -81,11 +81,13 @@ export default class SolanaOnboarding { getAssertData = async ({ gateway, decimalGain, + azimuth, elevation, location, deviceType, }: { gateway: string + azimuth?: number decimalGain?: number elevation?: number location: string @@ -106,6 +108,7 @@ export default class SolanaOnboarding { hemProgram, decimalGain, gateway, + azimuth, elevation, nextLocation: location, deviceType, diff --git a/packages/onboarding/src/types.ts b/packages/onboarding/src/types.ts index 8ae1daf2..e255bf78 100644 --- a/packages/onboarding/src/types.ts +++ b/packages/onboarding/src/types.ts @@ -38,6 +38,7 @@ export type Metadata = { location: string elevation: number gain: number + azimuth: number } export const IndoorManufacturedDeviceTypes = ['HeliumMobileIndoor'] as const From 1e4c52d28f7eaef13186b28e93068743f6747677 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Tue, 14 May 2024 15:12:22 -0500 Subject: [PATCH 19/25] v4.12.1-alpha.2 --- lerna.json | 2 +- packages/onboarding/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 84347b17..6ef95139 100644 --- a/lerna.json +++ b/lerna.json @@ -3,6 +3,6 @@ "integration_tests", "packages/*" ], - "version": "4.12.1-alpha.1", + "version": "4.12.1-alpha.2", "npmClient": "yarn" } diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 2a97643c..3d2a75b2 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.1-alpha.1", + "version": "4.12.1-alpha.2", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium", From 8e9f1482365a264e704ee09e8f76273e8a6c4c06 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 15 May 2024 08:07:42 -0500 Subject: [PATCH 20/25] Remove gain from wifi onboarding as it is not used. --- packages/onboarding/src/MobileHotspotOnboarding.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index cc2592d7..c1f72632 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -200,7 +200,6 @@ export default class MobileHotspotOnboarding { getWifiAssertData = async ({ gateway, - decimalGain, elevation, location, deviceType, @@ -208,7 +207,6 @@ export default class MobileHotspotOnboarding { }: { azimuth?: number gateway: string - decimalGain?: number elevation?: number location: string deviceType: 'WifiIndoor' | 'WifiOutdoor' @@ -216,7 +214,6 @@ export default class MobileHotspotOnboarding { return this._solanaOnboarding.getAssertData({ azimuth, gateway, - decimalGain, elevation, location, deviceType, @@ -250,12 +247,10 @@ export default class MobileHotspotOnboarding { azimuth, location, elevation, - gain, }: { hotspotAddress: string location?: string elevation?: number - gain?: number azimuth?: number }) => { this.writeLog('Getting MOBILE onboard txns') @@ -267,7 +262,6 @@ export default class MobileHotspotOnboarding { type: 'MOBILE', elevation, azimuth, - gain, }) if (!onboardTxns.data?.solanaTransactions?.length) { @@ -461,14 +455,12 @@ export default class MobileHotspotOnboarding { azimuth, location, elevation, - gain, ...opts }: AddToOnboardingServerOpts & { addGatewayTxn: string location?: string azimuth?: number | undefined elevation?: number | undefined - gain?: number | undefined }) => { const addGatewayV1 = AddGatewayV1.fromString(addGatewayTxn) if (!addGatewayV1.gateway) { @@ -528,7 +520,6 @@ export default class MobileHotspotOnboarding { hotspotAddress, azimuth, elevation, - gain, }) return txns @@ -655,6 +646,7 @@ export default class MobileHotspotOnboarding { azimuth: number heightType: HeightType hotspotAddress: string + antenna?: number }) { return this._configurationClient.createConfigurationMessage(opts) } From a5827803b8061df5f6559f836da552c31eb142b0 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 15 May 2024 08:08:53 -0500 Subject: [PATCH 21/25] v4.12.1-alpha.3 --- lerna.json | 2 +- packages/onboarding/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 6ef95139..0d676f46 100644 --- a/lerna.json +++ b/lerna.json @@ -3,6 +3,6 @@ "integration_tests", "packages/*" ], - "version": "4.12.1-alpha.2", + "version": "4.12.1-alpha.3", "npmClient": "yarn" } diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 3d2a75b2..6ce969b2 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.1-alpha.2", + "version": "4.12.1-alpha.3", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium", From eba119b5bc00d31422f802369f89ae8142e2698f Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 5 Jun 2024 16:08:52 -0500 Subject: [PATCH 22/25] Add vendor_slug when sending hmh configuration message --- packages/onboarding/src/ConfigurationClient.ts | 7 ++++++- packages/onboarding/src/MobileHotspotOnboarding.ts | 1 + .../src/__tests__/MobileHotspotOnboarding.spec.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/ConfigurationClient.ts b/packages/onboarding/src/ConfigurationClient.ts index 307f0b0d..211cbc48 100644 --- a/packages/onboarding/src/ConfigurationClient.ts +++ b/packages/onboarding/src/ConfigurationClient.ts @@ -72,11 +72,13 @@ export default class ConfigurationClient { signedMessage, hotspotAddress, token, + vendorSlug, }: { hotspotAddress: string originalMessage: Uint8Array signedMessage: Uint8Array token: string + vendorSlug?: string // default is 'helium mobile' - current options are 'rakwireless' and 'helium mobile' }) { const message = Message.decode(originalMessage) @@ -93,7 +95,10 @@ export default class ConfigurationClient { message.signature = signedMessage const encodedMessage = Message.encode(message).finish() - const body = { payloadB64: Buffer.from(encodedMessage).toString('base64') } + const body = { + payloadB64: Buffer.from(encodedMessage).toString('base64'), + vendor_slug: vendorSlug, + } if (this.mockAdapter) { this.mockAdapter.onPost(url).reply(204, { success: true }) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index c1f72632..1087d572 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -656,6 +656,7 @@ export default class MobileHotspotOnboarding { originalMessage: Uint8Array signedMessage: Uint8Array token: string + vendorSlug?: string }) { this._logCallback?.('Sending configuration message') const response = await this._configurationClient.sendConfigurationMessage(opts) diff --git a/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts b/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts index 1d917a46..77fa5159 100644 --- a/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts +++ b/packages/onboarding/src/__tests__/MobileHotspotOnboarding.spec.ts @@ -55,6 +55,7 @@ describe('Wifi Onboarding with wifi api version 2 (default)', () => { originalMessage, signedMessage: signature, token: 'asdf', + vendorSlug: 'rakwireless', }) expect(response.status).toBe(204) }) From 004d252238789f5a541af6f8aa424042df893fb1 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 5 Jun 2024 16:09:26 -0500 Subject: [PATCH 23/25] v4.12.1-alpha.4 --- lerna.json | 2 +- packages/onboarding/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 0d676f46..68bd8808 100644 --- a/lerna.json +++ b/lerna.json @@ -3,6 +3,6 @@ "integration_tests", "packages/*" ], - "version": "4.12.1-alpha.3", + "version": "4.12.1-alpha.4", "npmClient": "yarn" } diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 6ce969b2..2148e016 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.1-alpha.3", + "version": "4.12.1-alpha.4", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium", From fe5d02346779803175aeac4ff96b05172e3f3865 Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 5 Jun 2024 17:03:51 -0500 Subject: [PATCH 24/25] Reduce txn verification length to 3 minutes. --- .../onboarding/src/MobileHotspotOnboarding.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/onboarding/src/MobileHotspotOnboarding.ts b/packages/onboarding/src/MobileHotspotOnboarding.ts index 1087d572..8e7316fa 100644 --- a/packages/onboarding/src/MobileHotspotOnboarding.ts +++ b/packages/onboarding/src/MobileHotspotOnboarding.ts @@ -341,9 +341,9 @@ export default class MobileHotspotOnboarding { // confirm that it was successfully created. This is a hacky way // to verify the asset was created. Every 3 seconds, we check to see // if the asset exists. If it does, we stop checking. - // We check if the asset exists up to 200 times - // This equates to 600 seconds or 10 minutes - for (let i = 0; i < 200; i++) { + // We check if the asset exists up to 60 times + // This equates to 180 seconds or 3 minutes + for (let i = 0; i < 60; i++) { // waiting for the asset to be created on solana await sleep(3000) @@ -356,7 +356,7 @@ export default class MobileHotspotOnboarding { this.writeLog(`Hotspot not yet found ${hotspotAddress}`) } } catch (e) { - if (i === 199) { + if (i === 59) { // if we've reached the end of the loop, write the error this.writeError(e) } @@ -375,9 +375,9 @@ export default class MobileHotspotOnboarding { }) } - // We check if the mobile info exists up to 200 times - // This equates to 600 seconds or 10 minutes - for (let i = 0; i < 200; i++) { + // We check if the mobile info exists up to 60 times + // This equates to 180 seconds or 3 minutes + for (let i = 0; i < 60; i++) { // waiting for the asset to be created on solana await sleep(3000) @@ -396,7 +396,7 @@ export default class MobileHotspotOnboarding { if (hotspotInfo) return hotspotInfo } catch (e) { this.writeLog('Hotspot MOBILE details not yet found.') - if (i === 199) { + if (i === 59) { // if we've reached the end of the loop, write the error this.writeError(e) } From 88e591d5afadf797957842283210f666384d957b Mon Sep 17 00:00:00 2001 From: Matt Reetz Date: Wed, 5 Jun 2024 17:04:16 -0500 Subject: [PATCH 25/25] v4.12.1-alpha.5 --- lerna.json | 2 +- packages/onboarding/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 68bd8808..aa270ffd 100644 --- a/lerna.json +++ b/lerna.json @@ -3,6 +3,6 @@ "integration_tests", "packages/*" ], - "version": "4.12.1-alpha.4", + "version": "4.12.1-alpha.5", "npmClient": "yarn" } diff --git a/packages/onboarding/package.json b/packages/onboarding/package.json index 2148e016..de99394c 100644 --- a/packages/onboarding/package.json +++ b/packages/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@helium/onboarding", - "version": "4.12.1-alpha.4", + "version": "4.12.1-alpha.5", "description": "HTTP library for interacting with an onboarding server", "keywords": [ "helium",