> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shinami.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Invisible Wallets: backend-only

> How to integrate Shinami Invisible Wallets

## Overview

In this tutorial, we show you how to use the [Shinami Invisible Wallet API](/api-docs/aptos/wallet-services/invisible-wallet-api). Shinami’s Invisible Wallets are app-controlled, backend wallets under the shared custody of your app and Shinami. Both parties must cooperate in order to obtain a valid signature.

The examples also show how to leverage [Shinami's Gas Station](/product-overviews/aptos/gas-station) to seamlessly sign, sponsor, and execute a transaction in one request. When you create an Invisible Wallet for a user it won't have any APT in it. With Gas Station you can sponsor your user's transaction fees so they don't have to download a wallet app and complete KYC to buy APT. Removing this friction - along with the burden of remembering recovery phrases and reading signing pop-ups - is a great way to smoothly onboard Web2-native users.

### Understanding errors

Check the error code and message of any errors you get. We outline common errors in our Error Reference - make sure to check out the [section specific to Aptos Invisible Wallet API](/developer-guides/core-integration-topics/error-reference#aptos-invisible-wallet-api) as well as the "General Error Codes" section at the top that apply to all Shinami services.

### Usage and Billing FAQ

Make sure to check out the Aptos Wallet Services [product usage FAQ](/help-center/aptos/wallet-services-faq) and [billing FAQ](/help-center/billing/aptos-faq#wallet-services) in our Help Center for answers to common questions.

## Tutorial

<Info>
  **Notes:**

  * This tutorial requires a Shinami account. If you do not have one, you can sign up [here](https://app.shinami.com/signup).
  * We take you through the process step-by-step below, but if you get stuck you can [reach out to us](/help-center/overview#contacting-support).
</Info>

### 1. Create a Shinami Gas Station fund on Testnet

You'll need a Testnet Gas Station fund with APT in it in order to sponsor transactions. We have guidance on creating one in the [Aptos Gas Station page of our Help Center](/help-center/aptos/gas-station-faq). When you make a Testnet fund we deposit some APT in it so you can start testing immediately.

### 2. Clone the github repo

Clone the [shinami-examples github repo](https://github.com/shinamicorp/shinami-examples/tree/main), cd into the `shinami-examples/aptos/typescript/backend_examples` directory, and run `npm install`to install the dependencies for running the code. Run `tsc` in your terminal, and if the command isn't found run `npm install typescript --save-dev` (see other options [here](https://www.typescriptlang.org/download/) ) . If you need to install npm and Node.js, [see here](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). Below, we'll be using the `invisible_wallet.ts` file in the `shinami-examples/aptos/typescript/backend_examples/src` directory.

### 3. Create an API access key with Wallet Services and Testnet Gas Station rights

You use API access keys to interact with Shinami's services. For this tutorial, we'll create one access key with both `Wallet Services` rights and with Testnet `Gas Station` rights (Wallet Service rights work for all networks).

See [in our Authentication and API Keys guide](/developer-guides/core-integration-topics/authentication-and-api-keys#create-an-access-key) for info on how to set up a key with rights to all services.

Once you've created the key, enter it as the value for `ALL_SERVICES_TESTNET_ACCESS_KEY`.

Replace all instances of `{{name}}` with the actual value for that name.

<CodeGroup>
  ```bash TypeScript theme={null}
  // 2. Copy your access key value. Must have rights to Wallet Services and Testnet Gas Station.
  const ALL_SERVICES_TESTNET_ACCESS_KEY = "{{allServicesTestnetAccessKey}}";
  ```
</CodeGroup>

It will be used in the creation of all the Shinami clients you'll need for these examples (setup shown in the next code block below).

### 4. Create an Invisible Wallet

For each Invisible Wallet you create, you need to create and store two new pieces of information: a unique `walletId` and its associated, ideally unique `secret`. This 1-to-1 pairing can be thought of as a username/password equivalent you use with Shinami's API for each wallet. A `walletId` only works with the `secret` used when the wallet was created, so your application MUST remember each (`walletId`, `secret`) pair. If you forget or change either value, the wallet's private key will be unrecoverable. For more information and images, see [WalletId and Secret Pairing](/api-docs/aptos/wallet-services/invisible-wallet-api#walletid-and-secret-pairing).

You'll need to define a (`walletId`, `secret`) pair first. Choose and enter them into the file as the values for `WALLET_ONE_ID` and `WALLET_ONE_SECRET` in Step 3 below.

In steps 4-6 below, we first set up our Shinami clients. We then create a `ShinamiWalletSigner` instance to make our operations easier as it simplifies things by abstracting away session token management. Finally, we create the wallet and initialize it on Testnet (since that's where the Gas Station rights of our access key are tied to).

Replace all instances of `{{name}}` with the actual value for that name.

<CodeGroup>
  ```bash Shinami TypeScript SDK expandable theme={null}
  // 3. Set up a walletId and its associated secret. Just for the tutorial. Your
  //    app should figure out the best way to manage its wallet IDs and secrets.
  const WALLET_ID = "{{walletID}}";
  const WALLET_SECRET = "{{walletSecret}}";

  // 4. Instantiate your Shinami and Aptos clients
  const keyClient = new KeyClient(ALL_SERVICES_TESTNET_ACCESS_KEY);
  const walletClient = new WalletClient(ALL_SERVICES_TESTNET_ACCESS_KEY);
  // Only required for `signSponsorAndSubmitTransactionInTwoSteps` example:
  const gasClient = new GasStationClient(ALL_SERVICES_TESTNET_ACCESS_KEY);

  // Create an Aptos client for building, submitting, and fetching transactions
  const aptosClient = new Aptos(new AptosConfig({ network: Network.TESTNET }));

  // 5. Create a ShinamiWalletSinger to more easily manage the Invisible Wallet
  const signer = new ShinamiWalletSigner(
    WALLET_ID,
    walletClient,
    WALLET_SECRET,
    keyClient
  );

  // 6. Create an Invisible Wallet. The call to `executeGaslessTransaction` below will
  //    inititalize the wallet on-chain, so we do not need to initialize it on-chain 
  //    at creation time.
  const CREATE_WALLET_IF_NOT_FOUND = true;
  const INITIALIZE_ON_CHAIN = false;
  const walletAddress = await signer.getAddress(CREATE_WALLET_IF_NOT_FOUND, INITIALIZE_ON_CHAIN);
  console.log("Invisible wallet address: ", walletAddress.toString());
  ```
</CodeGroup>

<Info>
  **A note on wallet initialization**

  When you create a wallet, you have the choice of whether or not to initialize it on Testnet or Mainnet at the moment of creation. Initialization costs a very small amount of APT (your Gas Station fund sponsors a simple transaction which initializes the wallet). When you execute a transaction on behalf of an un-initialized wallet, wallet initialization happens as a part of that transaction. So, if the first action of a new user's wallet will always be to execute a transaction, when a user creates an account on your app you may wish to create an un-initialized wallet. If they engage with your app enough to reach their first transaction, the `executeGaslessTransaction` call will initialize their wallet (for a small APT fee).

  In the code above, we explicitly initialize the wallet for safety in case you only run the function that signs a transaction (since only initialized wallets can sign).
</Info>

### 5: Generate a feePayer Transaction

Next, we build a SimpleTransaction with a feePayer where the Invisible Wallet is the sender.

<CodeGroup>
  ```bash Shinami TypeScript SDK theme={null}
  // 7. Generate a feePayer transaction where an Invisible Wallet is the sender
  const simpleTx = await simpleMoveCallTransaction(walletAddress);
  ```
</CodeGroup>

The below `simpleMoveCallTransaction` function creates a transaction that calls a function on a Move module we've [deployed to Testnet](https://explorer.aptoslabs.com/account/0xc13c3641ba3fc36e6a62f56e5a4b8a1f651dc5d9dc280bd349d5e4d0266d0817/modules/code/message?network=testnet) (it's from an [Aptos tutorial](https://aptos.dev/tutorials/first-move-module/)). The `set_message` function allows the caller to store a message at their address inside a `MessageHolder`. If there was already a value the user was storing, the function emits an event that says what the messaged changed from and to, and who made the change.

The transaction's expiration timestamp must be set to a time within the next hour (as is required by our Gas Station). When you control the generation of the sender's signature, as with an Invisible Wallet you control for the user, you can likely use the SDK default, which is 20 seconds from now. This is what we do below by not setting a timestamp.

<CodeGroup>
  ```bash TypeScript theme={null}
  async function simpleMoveCallTransaction(sender: AccountAddress, withFeePayer = true): Promise<SimpleTransaction> {
      return await aptosClient.transaction.build.simple({
          sender: sender,
          withFeePayer: withFeePayer,
          data: {
            function: "0xc13c3641ba3fc36e6a62f56e5a4b8a1f651dc5d9dc280bd349d5e4d0266d0817::message::set_message",
            functionArguments: ["hello"]
          }
      });
  }
  ```
</CodeGroup>

### 6: Review and run the code to sign, sponsor, and execute a transaction

The `executeGaslessTransaction` method uses Wallet Service to sign the sponsored transaction as the sender and then Gas Station to sponsor the transaction and produce the sponsor's signature, before submitting the transaction to the Aptos blockchain.

**Explore the code**

<CodeGroup>
  ```bash Shinami TypeScript SDK theme={null}
  // 8. Sign, sponsor, and submit the transaction
  const pendingTx = await signer.executeGaslessTransaction(simpleTx);
                    // await signSponsorAndSubmitTransactionInTwoSteps(signer, simpleTx)

  // 9. Wait for the transaction to execute and print its status
  const executedTransaction = await aptosClient.waitForTransaction({
      transactionHash: pendingTx.hash
  });
  console.log("\nTransaction hash:", executedTransaction.hash);
  console.log("Transaction status:", executedTransaction.vm_status);
  ```
</CodeGroup>

**Run the code**

Make sure you've saved the changes to the file made above: adding your API access key and a wallet ID and secret. In the `shinami-examples/aptos/typescript/backend_examples` directory, run `tsc` to compile the file. Then, run `node build/invisible_wallet.ts` to run the code. You'll see the transaction digest printed to the console. You can look it up in an explorer like [Aptos Scan](https://aptoscan.com/?network=testnet) (make sure you've selected Testnet). To run an example where you break up transaction signing, sponsorship, and submission into multiple steps, [see the example in the Appendix](/developer-guides/aptos/tutorials/invisible-wallets#sign-sponsor-and-submit-a-transaction-in-multiple-steps).

By default, the code also runs the a function that signs a transaction and then verifies the signature, as [explained in the Appendix](/developer-guides/aptos/tutorials/invisible-wallets#sign-a-transaction-and-verify-the-signature).

## Appendix

### Sign, sponsor, and submit a transaction in multiple steps

In most cases where you are sponsoring transactions for Invisible Wallets, you will use the `executeGaslessTransaction` method to sign, sponsor, and execute transaction in one request. However, there may be cases where you want to break this into 2-3 steps. The below function gives an example.

**Explore the code**

The `signSponsorAndSubmitTransactionInTwoSteps` does the following:

1. Generates the sender's signature for the Invisible Wallet
2. Asks Shinami's Gas Station to sponsor and submit the signed transaction. As the comment explains, you could break this step in two by asking for just a sponsorship and then submitting the transaction along with the sender and feePayer signatures.

<CodeGroup>
  ```bash TypeScript theme={null}
  async function signSponsorAndSubmitTransactionInTwoSteps(onChainWalletSigner: ShinamiWalletSigner,
      transaction: SimpleTransaction): Promise<PendingTransactionResponse> {

      // 1. Generate the sender signature (from an Invisible Wallet that's been initialized on chain)
      const senderSignature = await onChainWalletSigner.signTransaction(transaction);

      // 2. Ask Shinami to sponsor and submit the transaction.
      //     You could also break this into two steps with a call to
      //     `gasClient.sponsorTransaction()` and then `aptosClient.transaction.submit.simple()`
      return await gasClient.sponsorAndSubmitSignedTransaction(transaction, senderSignature);
  }
  ```
</CodeGroup>

**Run the code**

Make sure the function call in Step 8 is only one uncommented, so it looks like this:

<CodeGroup>
  ```bash TypeScript theme={null}
  // 8. Sign, sponsor, and submit the transaction
  const pendingTx = // await signer.executeGaslessTransaction(simpleTx);
                    await signSponsorAndSubmitTransactionInTwoSteps(signer, simpleTx)
  ```
</CodeGroup>

Make sure you've saved your changes. Then, in the `shinami-examples/aptos/typescript/backend_examples` directory, run `tsc` to compile the file. Finally, run `node build/invisible_wallet.ts` to run the code. You'll see the transaction digest printed to the console. You can look it up in an explorer like [Aptos Scan](https://aptoscan.com/?network=testnet) (make sure you've selected Testnet).

### Sign a transaction and verify the signature

The below example shows how to sign a transaction and verify the signature.

**Explore the code**

The `signAndVerifyTransaction` does the following:

1. Creates a feePayer SimpleTransaction, where the Invisible Wallet is the sender
2. Generates the Invisible Wallet's signature on the Transaction.
3. Verifies that the signature was valid.

<CodeGroup>
  ```bash TypeScript theme={null}
  async function signAndVerifyTransaction(onChainWalletSigner: ShinamiWalletSigner,
                                                transaction: SimpleTransaction): Promise<void> {

    // 1. Generate the sender signature (from an Invisible Wallet that's been initialized on chain)
    const accountAuthenticator = await onChainWalletSigner.signTransaction(transaction);

    // 2. Verify the signature.
    const signingMessage = aptosClient.getSigningMessage({ transaction });
    const accountAuthenticatorEd25519 = accountAuthenticator as AccountAuthenticatorEd25519;
    const verifyResult = accountAuthenticatorEd25519.public_key.verifySignature(
      {
        message: signingMessage,
        signature: accountAuthenticatorEd25519.signature,
      },
    );
    console.log("\nInvisible Wallet signature was valid:", verifyResult);
  }
  ```
</CodeGroup>

**Run the code**

Make sure the function call in Step 10 is uncommented, so it looks like this:

<CodeGroup>
  ```bash TypeScript theme={null}
  // 10. (optional) Uncomment the next line to sign a transaction and verify the signature:
  await signAndVerifyTransaction(signer, simpleTx);
  ```
</CodeGroup>

Make sure you've saved any changes. Then, in the `shinami-examples/aptos/typescript/backend_examples` directory, run `tsc` to compile the file. Finally, run `node build/invisible_wallet.ts` to run the code.
