Skip to main content

Usage

Configure and interact with Magi in 5 minutes or less.

Instantiation

Create an instance of Magi. Returns a Magi object.

import { Magi } from '@aioha/magi'

const magi = new Magi()

Enums

The Wallet enum exported are as follows:

export enum Wallet {
Hive = 'hive',
Ethereum = 'evm',
Bitcoin = 'btc',
ViewOnly = 'viewonly'
}

Register Wallets

Hive Wallet

Register a Hive wallet using an Aioha instance.

import { initAioha } from '@aioha/aioha'

const aioha = initAioha()
magi.setAioha(aioha)

Ethereum Wallet

Register an Ethereum wallet using a Viem wallet client.

import { createWalletClient, http } from 'viem'

const viemClient = createWalletClient({
account: '0xYourAddress',
transport: http('https://your-rpc-url')
})
magi.setViem(viemClient)

Bitcoin Wallet

Register a Bitcoin wallet by providing a BtcClient object. This is a minimal interface that any Bitcoin wallet can implement.

import { BtcClient } from '@aioha/magi'

The BtcClient interface:

interface BtcClient {
address: string
signMessage(message: string): Promise<string>
}
  • address — Bitcoin address (P2PKH 1..., P2SH-P2WPKH 3..., or P2WPKH bc1q...)
  • signMessage — Signs a message string and returns a base64-encoded signature (BIP-137 or BIP-322)
note

Taproot (bc1p...) addresses are not currently supported.

magi.setBitcoin({
address: 'bc1qYourAddress',
signMessage: (msg) => myBtcWallet.signMessage(msg)
})
Example: Reown AppKit

If you use Reown AppKit with the Bitcoin adapter, you can create a BtcClient from the AppKit modal:

import { createAppKit } from '@reown/appkit'
import { BitcoinAdapter } from '@reown/appkit-adapter-bitcoin'

const bitcoinAdapter = new BitcoinAdapter({ projectId })
const modal = createAppKit({
adapters: [bitcoinAdapter],
// ...
})

// After wallet connection:
const provider = modal.getProvider('bip122')
magi.setBitcoin({
address: modal.getAddress(),
signMessage: (msg) => provider.signMessage({
message: msg,
address: modal.getAddress(),
protocol: 'ECDSA'
})
})
Example: UniSat
const unisat = window.unisat
const accounts = await unisat.requestAccounts()

magi.setBitcoin({
address: accounts[0],
signMessage: (msg) => unisat.signMessage(msg)
})

View-only Wallet

Register a view-only wallet by passing a prefixed DID. This lets you display an account's state without ever holding a signer — useful for dashboards, block explorers, or preview UIs.

// Hive account
magi.setViewOnly('hive:alice')

// Ethereum account
magi.setViewOnly('did:pkh:eip155:1:0xYourAddress')

// Bitcoin account
magi.setViewOnly('did:pkh:bip122:000000000019d6689c085ae165831e93:bc1qYourAddress')

The prefix determines the chain:

PrefixChain
hive:Hive
did:pkh:eip155:1:Ethereum
did:pkh:bip122:000000000019d6689c085ae165831e93:Bitcoin

Any other input throws an Error.

note

All signing and broadcast operations on a view-only wallet return an OperationError with code 4200 and the message Cannot sign or transact in view only mode. getUser(), isConnected(), and getWallet() work as usual.

Set Active Wallet

Set the wallet type to use for transactions. This must be called before performing any operations.

import { Wallet } from '@aioha/magi'

magi.setWallet(Wallet.Ethereum)
// or
magi.setWallet(Wallet.Hive)
// or
magi.setWallet(Wallet.Bitcoin)
// or
magi.setWallet(Wallet.ViewOnly)

Setters

Set Magi API

Set the Magi GraphQL API URL. An optional array of fallback API URLs may be provided.

magi.setApi('https://vsc.techcoderx.com/api/v1/graphql', [
'https://api.vsc.eco/api/v1/graphql',
'https://vsc.atexoras.com:2087/api/v1/graphql'
])

The URL must start with http:// or https://. The default API is https://vsc.techcoderx.com/api/v1/graphql with built-in fallback nodes.

Set Network ID

Set the Magi network ID. Defaults to vsc-mainnet.

magi.setNetId('vsc-mainnet')

// For testnet
magi.setNetId('vsc-testnet')

Getters

Get API

Returns an array of API endpoints, where the first item is the main endpoint and the remaining are fallbacks.

magi.getApi() // ['https://vsc.techcoderx.com/api/v1/graphql', ...]

Get Network ID

Returns the current Magi network ID.

magi.getNetId() // 'vsc-mainnet'

Get Connected User

Returns the connected user address, or undefined if not connected.

// Without prefix
magi.getUser() // 'alice', '0xYourAddress', or 'bc1q...'

// With prefix
magi.getUser(true)
// 'hive:alice'
// 'did:pkh:eip155:1:0xYourAddress'
// 'did:pkh:bip122:000000000019d6689c085ae165831e93:bc1q...'

Get Active Wallet

Returns the Wallet enum of the wallet type currently in use, or undefined if not set.

magi.getWallet() // Wallet.Hive, Wallet.Ethereum, Wallet.Bitcoin, or Wallet.ViewOnly

Is Connected

Returns a boolean of whether a wallet is connected.

magi.isConnected() // true or false

Sign and Broadcast Transaction

Sign and broadcast a Magi transaction consisting of one or more operations.

const result = await magi.signAndBroadcastTx([
{
type: 'call',
payload: {
contract_id: 'vsc1BX9RbKJYAqSSZZzrGeBWyBZkG3ojTVPRoo',
action: 'dumpEnv',
payload: '',
rc_limit: 300,
intents: []
}
}
], KeyTypes.Active)
  • tx: Array of MagiOperation objects
  • keyType (optional): KeyTypes.Active or KeyTypes.Posting — only applicable for Hive wallets, defaults to KeyTypes.Active

Operations

The return value for these method calls will be equivalent to sign and broadcast transaction result above.

Call Contract

Call a Magi smart contract.

// Call testLog at contract vsc1Bp8y... with 100 RC limit, no intents
const result = await magi.call('vsc1Bp8ykBKDT74vYrZShhfEhp8Mn8bG2ChiAf', 'testLog', { foo: 'bar' }, 100, [])

// With posting key (Hive wallets only)
const result = await magi.call('vsc1Bp8ykBKDT74vYrZShhfEhp8Mn8bG2ChiAf', 'testLog', { foo: 'bar' }, 100, [], KeyTypes.Posting)
  • contractId: The contract ID
  • action: The contract action/method to call
  • payload: The payload to pass to the contract action
  • rc_limit: The maximum RC (resource credits) to spend on this call
  • intents: Array of transaction intents
  • keyType (optional): Key type for Hive wallets

Transfer

Transfer tokens to another Magi account.

// Transfer 1 HIVE to a Hive account
const xfer = await magi.transfer('hive:bob', 1, Asset.hive)

// Transfer 1 HBD to an Ethereum address with memo
const xferWithMemo = await magi.transfer('did:pkh:eip155:1:0xRecipient', 1, Asset.hbd, 'Optional memo')
  • to: Recipient address (prefixed with hive:, did:pkh:eip155:1:, or did:pkh:bip122:...:)
  • amount: Amount to transfer (must be greater than 0)
  • currency: Asset.hive or Asset.hbd
  • memo (optional): Transfer memo

Unmap

Unmap tokens from Magi.

// Unmap 1 HIVE
const wd = await magi.unmap('hive:charlie', 1, Asset.hive)

// Unmap 50 HBD with memo
const wdWithMemo = await magi.unmap('hive:charlie', 50, Asset.hbd, 'Optional memo')
  • to: Destination address on L1 (prefixed with hive:, did:pkh:eip155:1:, or did:pkh:bip122:...:)
  • amount: Amount to withdraw (must be greater than 0)
  • currency: Asset.hive or Asset.hbd
  • memo (optional): Withdrawal memo

Stake

Stake tokens on Magi.

import { VscStakeType } from '@aioha/aioha'

// Stake 2,000 HIVE for consensus (to self)
const consensusStake = await magi.stake(VscStakeType.Consensus, 2000)

// Stake 2,000 HIVE for consensus to another account
const consensusStakeOther = await magi.stake(VscStakeType.Consensus, 2000, 'hive:anotheraccount')

// Stake 100 HBD
const hbdStake = await magi.stake(VscStakeType.HBD, 100)
  • stakeType: VscStakeType.Consensus for HIVE consensus staking, VscStakeType.HBD for HBD staking
  • amount: Amount to stake (must be greater than 0)
  • to (optional): Recipient address — defaults to the connected account
  • memo (optional): Stake memo

Unstake

Unstake tokens on Magi.

import { VscStakeType } from '@aioha/aioha'

// Unstake 2,000 HIVE from consensus
const consensusUnstake = await magi.unstake(VscStakeType.Consensus, 2000)

// Unstake 100 HBD
const hbdUnstake = await magi.unstake(VscStakeType.HBD, 100)
  • stakeType: VscStakeType.Consensus for HIVE consensus unstaking, VscStakeType.HBD for HBD unstaking
  • amount: Amount to unstake (must be greater than 0)
  • to (optional): Recipient address — defaults to the connected account
  • memo (optional): Unstake memo

Events

Subscribe to Magi events using the on, once, and off methods.

Subscribe

magi.on('wallet_changed', () => {
console.log('Wallet type changed to:', magi.getWallet())
})

magi.on('sign_tx_request', () => {
console.log('Transaction signature requested')
})

Subscribe Once

The listener will be called only on the next emission of the event.

magi.once('sign_tx_request', () => {
console.log('This fires only once')
})

Unsubscribe

const handler = () => console.log('wallet changed')
magi.on('wallet_changed', handler)

// Unsubscribe specific listener
magi.off('wallet_changed', handler)

// Unsubscribe all listeners for the event
magi.off('wallet_changed')

Event Reference

EventDescription
wallet_changedEmitted when the active wallet type is changed via setWallet(), or when setViewOnly() updates the DID while Wallet.ViewOnly is the active wallet
sign_tx_requestEmitted when a transaction signature is requested from the wallet