Overview
In this tutorial, we show you how to use the Shinami 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 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 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 and billing FAQ in our Help Center for answers to common questions.Tutorial
Notes:
- This tutorial requires a Shinami account. If you do not have one, you can sign up here.
- We take you through the process step-by-step below, but if you get stuck you can reach out to us.
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. 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, cd into theshinami-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 ) . If you need to install npm and Node.js, see here. 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 Testnet rights to all Shinami services
You use API access keys to interact with Shinami’s services. For this tutorial, we’ll create one access key with rights for all Testnet services -Wallet Services
, Node Service
, and Gas Station
- because some of the calls require rights to all services.
Create your key in our US East - us1
region as this code code uses the US East - us1
service URLs since all services used in this tutorial are deployed there (unlike Tokyo - apac1
). See our in our Authentication and API Keys guide for info on how to set up a key with rights to all services.
Once you’ve created the key, enter is as the value for ALL_SERVICES_TESTNET_ACCESS_KEY
.
Replace all instances of{{name}}
with the actual value for that name
4. Create an Invisible Wallet
For each Invisible Wallet you create, you need to create and store two new pieces of information: a uniquewalletId
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.
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 and Node Service rights of our access key are tied to).
Replace all instances of{{name}}
with the actual value for that name
A note on wallet initializationWhen 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 initializing 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).5: Generate a feePayer Transaction
Next, we build a SimpleTransaction with a feePayer where the Invisible Wallet is the sender.simpleMoveCallTransaction
function creates a transaction that calls a function on a Move module we’ve deployed to Testnet (it’s from an Aptos tutorial). 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.
6: Review and run the code to sign, sponsor, and execute a transaction
TheexecuteGaslessTransaction
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
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 (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.
By default, the code also runs the a function that signs a transaction and then verifies the signature, as explained in the Appendix.
Appendix
Sign, sponsor, and submit a transaction in multiple steps
In most cases where you are sponsoring transactions for Invisible Wallets, you will use theexecuteGaslessTransaction
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:
- Generates the sender’s signature for the Invisible Wallet
- 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.
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 (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 ThesignAndVerifyTransaction
does the following:
- Creates a feePayer SimpleTransaction, where the Invisible Wallet is the sender
- Generates the Invisible Wallet’s signature on the Transaction.
- Verifies that the signature was valid.
shinami-examples/aptos/typescript/backend_examples
directory, run tsc
to compile the file. Finally, run node build/invisible_wallet.ts
to run the code.