Enclave
  • Introducing Enclave Money
    • Enclave Smart Accounts
      • Security & Recovery
      • MEV Protection
    • Enclave Money Protocol
      • Asset Support
      • Network Support
      • Wallet Support
    • Embedded Swaps
  • Integrate with Enclave Money
    • SDK
      • Integrate with Privy
      • Integrate with Turnkey
    • API Reference
      • Health
      • User
      • Smart Balance
      • Smart Account
      • Passkey Account
      • Delegated Action
  • Applications
  • Business Model
  • Audits
  • Disclaimer
  • Risk Disclosure
Powered by GitBook
On this page
  • Demo Repository
  • Step 1: Install Enclave Money
  • Step 2: Initialize Enclave Client
  • Step 3: Create Account with Turnkey as Signing Key
  • Step 3: Build User Operation
  • Step 4: Sign User Operation
  • Step 5: Submit User Operation
  • Conclusion
  1. Integrate with Enclave Money
  2. SDK

Integrate with Turnkey

The steps given below contain instructions on how to integrate Enclave's SDK with an application that uses Turnkey's React SDK

PreviousIntegrate with PrivyNextAPI Reference

Last updated 2 months ago

Demo Repository

Step 1: Install Enclave Money

npm install enclavemoney

Step 2: Initialize Enclave Client

import { Enclave, SignMode } from 'enclavemoney';
const API_KEY = 'your-api-key-here';
const enclave = new Enclave(API_KEY);

Step 3: Create Account with Turnkey as Signing Key

In the snippet given below we:

  • Import 3rd party dependencies

  • Retrieve the active Turnkey signing key address

  • Create an Enclave account on all supported networks using the Turnkey signing key

import { useState, useEffect } from "react";
import { useTurnkey } from "@turnkey/sdk-react";
import { formatUnits, parseUnits, isAddress, ethers, getBytes } from 'ethers';

....

const { turnkey, getActiveClient } = useTurnkey();

const client = await getActiveClient();

// The user's sub-organization id
const organizationId = user?.organization.organizationId;

// Get the user's wallets
const wallets = await client?.getWallets({
  organizationId,
});

// Get the first wallet of the user
const walletId = wallets?.wallets[0].walletId ?? "";

// Use the `walletId` to get the accounts associated with the wallet
const accounts = await client?.getWalletAccounts({
  organizationId,
  walletId,
});

const signingKey = accounts?.accounts[0].address;

const account = await enclave.createSmartAccount(signingKey);
console.log('Smart Account created:', account.wallet.scw_address);

The user can transfer USDC to the account address returned from the createSmartAccount response and start transacting on any supported chain with their USDC deposits.

Step 3: Build User Operation

In the example below we build a user operation to transfer USDC. This requires the user to have an account (created in Step 2) and the user must transfer USDC to their account. The user can deposit USDC on any supported chain and spend their funds on any chain.

// Define the transaction details
// Define the USDC contract address on Optimism
const usdcContractAddress = '<Insert USDC Contract Address for Chain ID>'; 

// Define the recipient address and amount to transfer
const recipientAddress = '0x...'; // Replace with the recipient's address
const amount = ethers.parseUnits('1', 6); // Amount of USDC to transfer (1 USDC)

// Create the call data for the ERC20 transfer
const erc20Interface = new ethers.Interface([
    'function transfer(address to, uint256 amount)'
]);
const encodedData = erc20Interface.encodeFunctionData('transfer', [recipientAddress, amount]);

const transactionDetails = [{
    encodedData, 
    targetContractAddress: usdcContractAddress,
    value: 0 // Assuming no ETH is being transferred, only USDC
}];

// Define the order data - Describes how much the user wants to spend from their chain-abstracted balances
// Understanding order type
// AMOUNT_OUT: User needs 100 USDC on the target network. The user will be charged 100 + fees.
// AMOUNT_IN : User is charged 100 USDC and receives (100 - fees) on target network 
const orderData = {
    amount: amount.toString(), // Amount of USDC required for the transfer 
    type: 'AMOUNT_OUT'
};

// Build the transaction
const builtTxn = await enclave.buildTransaction(
    transactionDetails,
    chainId, // chainId of the network you want to execute the transaction on
    account.wallet.scw_address, // User's smart account address
    orderData,
    undefined, // Pass custom ERC4337 paymaster signature if required
    SignMode.ECDSA // ECDSA Signature Mode (for secp256k1)
);

Step 4: Sign User Operation

In the snippet below we create a Turnkey ethers signer and sign the user operation hash (buildTxn.messageToSign) retriveed in Step 3.

const turnkeySigner = new TurnkeySigner({
    client: client,
    organizationId: user.organization.organizationId,
    signWith: accounts.accounts[0].address,
}) 
console.log("UserOpHash To Sign: ", builtTxn.messageToSign);

const msgBytes = getBytes(builtTxn.messageToSign);
const signature = await turnkeySigner.signMessage(msgBytes);

Step 5: Submit User Operation

In the code snippet given below we use the enclave SDK to submit the signed user operation using builtTxn from Step 3 and the signature from Step 4

const txnResult = await enclave.submitTransaction(
  signature,
  builtTxn.userOp,
  chainId, // chainId of the network you want to execute the transaction on
  enclaveAddress,
  SignMode.ECDSA
);

Conclusion

Congratulations! You have now added chain abstraction capabilities to your application using Turnkey as the signing key. This effectively allows your users to spend their unified USDC balance across chains for executing any on-chain action using their preferred authentication, authorization and signing methods provided by Turnkey (ex. Email, Google, Passkey, etc).

GitHub - Enclave-Money/enclave-turnkey-demo: This is a demo built on next js using Turnkey and Enclave Money SDKs to implement a basic chain abstracted payments applicationGitHub
Logo