Getting Started With Browser Passkeys

Halliday's SDK provides functionality for integrating the browser's native passkeys system for authenticating users to your application. With our SDK, users will have unique non-custodial smart accounts based on the passkey they use (i.e fingerprint, touch id, device passcode, etc.).

πŸ“˜

What are Passkeys?

A new standard advocated by Google and Apple, passkeys is the next-generation user authentication technology designed to replace traditional passwords. When a user registers or logs in, their device creates a unique private-public key pair that associates the user to that specific site or service, which is known a passkey. The passkey's private key, stored securely on the user's device, is used for authentication and is never shared.

In Web3, the passkey can be used to manage wallets and accounts on the blockchain, including Halliday Smart Accounts.

πŸ“˜

To learn more about Passkeys, please refer to the Passkeys section of Architecture + Concepts, or these helpful sources below:

Google's Passkeys Documentation: https://www.google.com/account/about/passkeys/

Apple's Passkeys Documentation: https://support.apple.com/guide/iphone/use-passkeys-to-sign-in-to-apps-and-websites-iphf538ea8d0/ios

WebAuthn Passkeys Standards: https://fidoalliance.org/passkeys/


Initialize the Halliday SDK via Browser Passkeys

To get started with our SDK using our browser passkey log-in flow, first install halliday-sdk:

npm install halliday-sdk

or

yarn add halliday-sdk

The following example shows how to leverage browser passkeys with our SDK to access your Halliday Smart Account:

import {HallidayViaPasskey, BlockchainType} from "halliday-sdk";

// Initialize the Halliday client.
const hallidayClient = new HallidayViaPasskey({
  hallidayPublicApiKey: "API_KEY",          // Provided to you by the Halliday team
  gameName: "Demo Game Name",               // Your application's name, mainly for display purposes when passkey prompt comes to user
  domain: "localhost",                      // Your domain, to register the passkey with (localhost for local testing)
  blockchainType: BlockchainType.MUMBAI,    // Optional argument - defaults to Mumbai
  sandbox: true                             // Optional argument - defaults to false. If true, the SDK will interact with our test environment.
});

In your registration flow, prompt a new user for a passkey and use the passkey to connect your user to Halliday. The passkeyName (along with gameName in the constructor) is for display purposes when prompting the user for a passkey. The passkeyName can be the user's username or any identifier for display purposes.

const passkeyName = "Demo Username";

async function onClickRegisterButton(passkeyName) {
  await hallidayClient.registerUser(passkeyName);
}

In your login flow, prompt a returning user to choose a previously stored passkey to connect your user to Halliday. Passkeys will be labeled based on the gameName entered in the constructor and the passkeyName entered with the registerUser() function.

async function onClickLoginButton() {
  await hallidayClient.login();
}

Once the user has registered or logged in with browser passkeys, they can access their Halliday Smart Account as demonstrated below:

// To get or create the Halliday Smart Account, call getOrCreateHallidayAAWallet. 
// This will get the user's smart account for the blockchain you specified in the constructor.
const userInGameId = "user_in_game_id";           // The user's id in your application. Must be unique for each user.
const hallidayAccount = await hallidayClient.getOrCreateHallidayAAWallet(
  userInGameId,					
  "[email protected]"
);
const hallidayAccountAddress = hallidayAccount.account_address;

View Assets in the Smart Account

You can view assets and balances in the smart account as demonstrated below:

// Get NFTs in the Halliday Smart Account.
const assets = await hallidayClient.getAssets(userInGameId);

// Get ERC20 balances in the Halliday Smart Account.
const balances = await hallidayClient.getBalances(userInGameId);

Create a transferAsset Transaction

To transfer an ERC721 token from one account to another, you can construct and send the transaction as demonstrated below:

// Transfer an NFT to a different user, with gas sponsored by the paymaster.
const transferAssetTxInfo = await hallidayClient.transferAsset({
  from_in_game_player_id: userInGameId,                                 // Your user's id in your application
  to_in_game_player_id: "other_player_id",                              // Other user's id in your application
  collection_address: "0xeeaf9e39057002eae4bea8bb4e65b01a9cfd59be",     // ERC721 token contract address
  token_id: "3988",																											// Token id to transfer
  sponsor_gas: true,																										// Send with gas sponsorship
});
console.log(transferAssetTxInfo.status, transferAssetTxInfo.on_chain_id);

Create a transferBalance Transaction

To transfer an ERC20 token or native token from one account to another, you can construct and send the transaction as demonstrated below:

// Transfer an ERC20 to a different user, with gas sponsored by the paymaster.
const balanceTransferTxInfo = await hallidayClient.transferBalance({
  from_in_game_player_id: userInGameId,                         // Your user's id in your application
  to_in_game_player_id: "other_player_id",                      // Other user's id in your application
  token_address: "0x0799ea468f812e40dbabe77b381cac105da500cd",  // ERC20 token contract address
  value: "100000000000000000",                                  // Amount of token to transfer, in the lowest decimal demonition of the token
  sponsor_gas: true,                                            // Send with gas sponsorship
});
console.log(balanceTransferTxInfo.status, balanceTransferTxInfo.on_chain_id);

Create a Transaction to Call Any Smart Contract Function

To call any on-chain smart contract function, you can construct and send the transaction as demonstrated below:

// Call an arbitrary contract.
const contractAddress = '0x1f6557356bfb310a556300a36fb18f54fb4791b1';
// The contract's ABI
const contractAbi = [...];                           // Replace with your contract's ABI
// Create an instance of the contract
const contract = new ethers.Contract(contractAddress, contractAbi, signer);
// Get the calldata for a contract call
const calldata = contract.interface.encodeFunctionData('someFunction', ['arg1', 'arg2']);

// Call the contract, with gas sponsored by the paymaster.
const contractCallTxInfo = await hallidayClient.callContract({
  from_in_game_player_id: userInGameId,               // Your user's id in your application
  target_address: contractAddress,
  value: "0",
  calldata,
  sponsor_gas: true,
});
console.log(contractCallTxInfo.status, contractCallTxInfo.on_chain_id);