You must send NEAR tokens to activate the wallet. Without NEAR tokens in the wallet, you will receive an error stating that the account does not exist when broadcasting a transaction.
This tutorial walks you through creating a developer-controlled wallet to sign transactions on NEAR.
Before you begin:
When
creating a developer-controlled wallet,
pass NEAR-TESTNET
or NEAR
in the blockchains
field. This wallet can be
used to sign transactions on NEAR.
The following example code shows how to create a wallet using the Circle Developer SDK.
const response = await circleDeveloperSdk.createWallets({
accountType: 'EOA',
blockchains: ['NEAR-TESTNET'],
count: 2,
walletSetId: '<wallet-set-id>',
})
You must send NEAR tokens to activate the wallet. Without NEAR tokens in the wallet, you will receive an error stating that the account does not exist when broadcasting a transaction.
Use count
to specify the number of wallets to create, up to a maximum of 200
per API request.
To build a raw transaction for signing in JavaScript:
The following example code shows how to build a raw transaction for signing.
import { initiateDeveloperControlledWalletsClient } from '@circle-fin/developer-controlled-wallets'
import { connect, utils } from 'near-api-js'
import { baseDecode, baseEncode } from '@near-js/utils'
import { PublicKey } from '@near-js/crypto'
import {
createTransaction,
actionCreators,
encodeTransaction,
} from '@near-js/transactions'
import axios from 'axios'
import fs from 'fs'
const NEAR_CONFIG = {
networkId: 'testnet',
nodeUrl: 'https://rpc.testnet.near.org',
}
// fill in these variables
const CIRCLE_API_KEY = ''
const CIRCLE_ENTITY_SECRET = ''
const CIRCLE_WALLET_PUBLIC_KEY = '' // with `ed25519:` scheme
const CIRCLE_WALLET_ID = ''
const CIRCLE_TX_MEMO = ''
const MASTER_ACCOUNT = ''
const RECEIVER = ''
const AMOUNT = '0.001'
async function main() {
const client = initiateDeveloperControlledWalletsClient({
apiKey: CIRCLE_API_KEY,
entitySecret: CIRCLE_ENTITY_SECRET,
})
try {
// setup client and account
const near = await connect({ ...NEAR_CONFIG })
const sender = await near.account(MASTER_ACCOUNT)
// get latest finalized block
const block = await near.connection.provider.block({ finality: 'final' })
const blockHash = block.header.hash
// get sender nonce
const senderAccessKey = await sender.getAccessKeys()
let nonce = BigInt(0)
for (let i = 0; i < senderAccessKey.length; i++) {
if (senderAccessKey[i].public_key === CIRCLE_WALLET_PUBLIC_KEY) {
nonce = senderAccessKey[i].access_key.nonce + BigInt(1)
}
}
if (nonce === BigInt(0)) {
console.error(
`couldn't find corresponding access key: ${CIRCLE_WALLET_PUBLIC_KEY}`,
)
return
}
// build raw transaction
const actions = [
actionCreators.transfer(
BigInt(utils.format.parseNearAmount(AMOUNT) || 0),
),
]
const signerPublicKey = PublicKey.fromString(CIRCLE_WALLET_PUBLIC_KEY)
const transaction = createTransaction(
MASTER_ACCOUNT,
signerPublicKey,
RECEIVER,
nonce,
actions,
baseDecode(blockHash),
)
// serialize borsh
const message = encodeTransaction(transaction)
// base64 encode
const base64EncodedTx = Buffer.from(message).toString('base64')
// call Circle's API to sign tx
const signedTx = await client.signTransaction({
walletId: CIRCLE_WALLET_ID,
rawTransaction: base64EncodedTx,
memo: CIRCLE_TX_MEMO,
})
} catch (err) {
if (axios.isAxiosError(err)) {
console.error(`status: ${err.response?.status}`)
console.error(`data: `, err.response?.data)
} else {
console.error(`unknown err: `, err)
}
}
}
;(async () => {
await main()
})()