Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onboarding rando #368

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d1859b7
Add more logs, cleanup unused funcs.
matthewcarlreetz Dec 21, 2023
dec4fae
Verify config message before sending.
matthewcarlreetz Dec 30, 2023
ab49dfc
Throw an error when firmware lookup fails to respond.
matthewcarlreetz Jan 4, 2024
100762b
Cleanup incorrect error logging when onboarding
matthewcarlreetz Jan 5, 2024
d83b479
Cleanup logs.
matthewcarlreetz Jan 5, 2024
1c5901e
Add cbrs suppot to mobile onboarding client.
matthewcarlreetz Jan 11, 2024
72a9d9a
Use config api dev url when onboarding to devnet.
matthewcarlreetz Jan 17, 2024
bbe0b11
Add hotspot to onboarding server after retrieving add_gateway_txn
matthewcarlreetz Feb 29, 2024
73b7543
Update assert fee calc to handle big numbers.
matthewcarlreetz Mar 12, 2024
880f9e5
v4.11.1-alpha.0
matthewcarlreetz Mar 12, 2024
83e638e
Retry hotspot create if it fails to land.
matthewcarlreetz Apr 10, 2024
c18b41a
Prefer hnt naming convention over bones.
matthewcarlreetz Apr 10, 2024
656240b
Limit amount of hotspot create retries.
matthewcarlreetz Apr 11, 2024
237aa88
Update to helium version 4.12.0
matthewcarlreetz Apr 11, 2024
07cb929
v4.12.1-alpha.0
matthewcarlreetz Apr 11, 2024
0c8bfa4
Fix incorrect fee for assertion.
matthewcarlreetz Apr 25, 2024
30a5d64
v4.12.1-alpha.1
matthewcarlreetz Apr 25, 2024
9c50238
Support azimuth and elevation when onboarding and asserting.
matthewcarlreetz May 14, 2024
1e4c52d
v4.12.1-alpha.2
matthewcarlreetz May 14, 2024
8e9f148
Remove gain from wifi onboarding as it is not used.
matthewcarlreetz May 15, 2024
a582780
v4.12.1-alpha.3
matthewcarlreetz May 15, 2024
eba119b
Add vendor_slug when sending hmh configuration message
matthewcarlreetz Jun 5, 2024
004d252
v4.12.1-alpha.4
matthewcarlreetz Jun 5, 2024
fe5d023
Reduce txn verification length to 3 minutes.
matthewcarlreetz Jun 5, 2024
88e591d
v4.12.1-alpha.5
matthewcarlreetz Jun 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"integration_tests",
"packages/*"
],
"version": "4.12.0",
"version": "4.12.1-alpha.0",
"npmClient": "yarn"
}
2 changes: 1 addition & 1 deletion packages/address/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@helium/address",
"version": "4.12.0",
"version": "4.12.1-alpha.0",
"description": "Helium public key utilities",
"keywords": [
"helium",
Expand Down
4 changes: 2 additions & 2 deletions packages/crypto-react-native/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions packages/crypto/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/currency/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
6 changes: 3 additions & 3 deletions packages/http/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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",
Expand Down
7 changes: 4 additions & 3 deletions packages/onboarding/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -41,13 +41,14 @@
},
"dependencies": {
"@coral-xyz/anchor": "^0.28.1-beta.2",
"@helium/address": "^4.12.0",
"@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",
Expand Down
18 changes: 16 additions & 2 deletions packages/onboarding/src/ConfigurationClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -24,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, {
Expand Down Expand Up @@ -74,9 +78,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') }
Expand Down
132 changes: 30 additions & 102 deletions packages/onboarding/src/HotspotOnboardingUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } from '@solana/web3.js'
import {
AccountLayout,
createAssociatedTokenAccountIdempotentInstruction,
getAccount,
getMinimumBalanceForRentExemptAccount,
Expand All @@ -24,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,
Expand All @@ -33,12 +31,14 @@ import {
TXN_FEE_IN_LAMPORTS,
} from './types'

type Account = AccountInfo<string[]>

const lowerFirst = (str: string) => str.charAt(0).toLowerCase() + str.slice(1)

export const deviceTypeToNetworkType = (deviceType: DeviceType): NetworkType => {
if (deviceType === null) return 'IOT'
const deviceTypeToNetworkType = (deviceType: DeviceType): NetworkType => {
// 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'
}
Expand Down Expand Up @@ -92,6 +92,7 @@ export const getHotspotNetworkDetails = async ({
if (!networkType && types.deviceType !== undefined) {
networkType = deviceTypeToNetworkType(types.deviceType)
}

if (!networkType) {
throw new Error('Could not determine network type')
}
Expand Down Expand Up @@ -149,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) => {
Expand All @@ -168,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 hnt = await getBalance(wallet, connection, HNT_MINT)
const dc = await getBalance(wallet, connection, DC_MINT)

return { hnt, dc, sol: new BN(sol) }
return { hnt, dc, lamports: new BN(lamports) }
}

const burnHNTForDataCredits = async ({
Expand Down Expand Up @@ -214,10 +218,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 {
Expand All @@ -229,84 +230,6 @@ export const getAtaAccountCreationFee = async (
}
}

export const fetchSimulatedTxn = async ({
apiUrl,
txnBuff,
accountAddresses,
}: {
apiUrl: string
txnBuff: Buffer
accountAddresses: string[]
}): Promise<Array<Account>> => {
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,
Expand Down Expand Up @@ -345,7 +268,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,
Expand All @@ -356,6 +283,7 @@ export const getAssertData = async ({
})

const errFound = !solResponse.success ? solResponse : undefined

if (errFound) {
throw errFound.errorMessage
}
Expand All @@ -369,6 +297,7 @@ export const getAssertData = async ({
address: gateway,
hemProgram,
})

const requiredDc = networkDetails?.locationStakingFee || new BN(0)

let makerDc = new BN(0)
Expand All @@ -381,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

Expand All @@ -390,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)
}

Expand All @@ -400,9 +328,9 @@ 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.div(oraclePrice)
const dcInCents = dcNeeded.div(new BN(100000)).mul(new BN(100))
const oraclePriceInCents = await getOraclePriceInCentsFromSolana({ connection, cluster })
const hntNeeded = dcInCents.mul(HNT_AS_BONES).divRound(oraclePriceInCents)
hasSufficientHnt = balances.hnt.gte(hntNeeded)

if (hasSufficientHnt) {
Expand All @@ -415,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)
}
}
}
Expand Down
Loading