# Aptos

To use SafePal Wallet with your dApp, your users must first install the SafePal Wallet Chrome extension in their browser. SafePal Wallet injects an safePal object into the window (opens new window) of any web app the user visits.

# npm package

# Installed or not

To check if the user has installed SafePal Wallet, perform the below check:

const isSafePalInstalled = window.safePal;
1

# Detecting the Aptos provider

If SafePal Wallet is not installed, you can prompt the user to first install SafePal Wallet and provide the below installation instructions. For example, see below:

function getAptosWallet() {
  const provider = window.safePal;
  if (!provider) {
    return window.open('https://www.safepal.com/download?product=2');
    throw  `Please guide users to download from our official website`
  }
  return provider;
}
1
2
3
4
5
6
7
8

# Connecting to SafePal Wallet

After confirming that the web app has the safePal object, we can connect to SafePal Wallet by calling wallet.connect().

When you call wallet.connect(), it prompts the user to allow your web app to make additional calls to SafePal Wallet, and obtains from the user basic information such as the address and public key.

Note:

After the user has approved the connnection for the first time, the web app's domain will be remembered for the future sessions.

See the example code below:

const wallet = getAptosWallet();
try {
  const response = await wallet.connect();
  console.log(response); // { address: string, address: string }
  const account = await wallet.account();
  console.log(account); // { address: string, address: string }
} catch (error) {
  // { code: 4001, message: "User rejected the request."}
}
1
2
3
4
5
6
7
8
9
10

# Sending a Transaction

After your web app is connected to SafePal Wallet, the web app can prompt the user to sign and send transactions to the Aptos blockchain.

SafePal Wallet API handles the transactions in two ways:

  1. Sign a transaction and submit it to the Aptos blockchain. Return a pending transaction to the web app.
  2. Sign a transaction but do not submit the transaction to the Aptos blockchain. Return the signed transaction to the web app for the web app to submit the transaction.

See the below examples for both the options.

Note:

For more on Aptos transactions, see the Aptos SDKs (opens new window).

# Sign and submit

The below code example shows how to use the signAndSubmitTransaction() API to sign the transaction and send it to the Aptos blockchain.

const wallet = getAptosWallet(); // see "Connecting"
// Example Transaction, following an [EntryFunctionPayload](https://github.com/aptos-labs/aptos-core/blob/main/ecosystem/typescript/sdk/src/generated/models/EntryFunctionPayload.ts#L8-L21)
const transaction = {
    arguments: [address, '717'],
    function: '0x1::coin::transfer',
    type: 'entry_function_payload',
    type_arguments: ['0x1::aptos_coin::TestCoin'],
};
/**
 *  Custom gas fee
 *  default {
        "gas_unit_price":"100",
        "max_gas_amount":"10000"
    }
 */
const options = {
    gas_unit_price:100,
    max_gas_amount:10000
} 
try {
    const pendingTransaction = await window.safePal.signAndSubmitTransaction(transaction);
    // const pendingTransaction = await window.safePal.signAndSubmitTransaction(transaction, options);
    // In most cases a dApp will want to wait for the transaction, in these cases you can use the typescript sdk
    const client = new AptosClient('https://testnet.aptoslabs.com');
    client.waitForTransaction(pendingTransaction.hash);
} catch (error) {
    // see "Errors"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# Sign only

IMPORTANT: We don't recommend using this because in most cases you don't need it, and it isn't super safe for users. They will receive an extra warning for this.

The below code example shows how to use the signTransaction() API to only sign the transaction, without submitting it to the Aptos blockchain.

const wallet = getAptosWallet(); // see "Connecting"
// Example Transaction
const transaction = {
    arguments: [address, '717'],
    function: '0x1::coin::transfer',
    type: 'entry_function_payload',
    type_arguments: ['0x1::aptos_coin::TestCoin'],
};
/** Custom gas fee
 *  default {
        "gas_unit_price":"100",
        "max_gas_amount":"10000"
    }
 */
const options = {
    gas_unit_price: 100,
    max_gas_amount:10000
} 
try {
    const signTransaction = await window.safePal.signTransaction(transaction)
    // const signTransaction = await window.safePal.signTransaction(transaction, options)
} catch (error) {
    // see "Errors"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# Signing Messages

A web app can also request the user to sign a message, by using SafePal Wallet API: wallet.signMessage(payload: SignMessagePayload)

  • signMessage(payload: SignMessagePayload) prompts the user with the payload.message to be signed
  • returns Promise<SignMessageResponse>

Types:

export interface SignMessagePayload {
  address?: boolean; // Should we include the address of the account in the message
  application?: boolean; // Should we include the domain of the dapp
  chainId?: boolean; // Should we include the current chain id the wallet is connected to
  message: string; // The message to be signed and displayed to the user
  nonce: string; // A nonce the dapp should generate
}
export interface SignMessageResponse {
  address: string;
  application: string;
  chainId: number;
  fullMessage: string; // The message that was generated to sign
  message: string; // The message passed in by the user
  nonce: string;
  prefix: string; // Should always be APTOS
  signature: string; // The signed full message
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Example message

signMessage({nonce: 1234034, message: "Welcome to dapp!" }) This would generate the fullMessage to be signed and returned as the signature:

    APTOS
    nonce: 1234034
    message: Welcome to dapp!
1
2
3

# Verifying

The most common use case for signing a message is to verify ownership of a private resource.

import nacl from 'tweetnacl';
const message = "hello";
const nonce = "random_string"
try {
  const response = await window.safePal.signMessage({
    message,
    nonce,
  });
  const { publicKey } = await window.safePal.account();
  // Remove the 0x prefix
  const key = publicKey!.slice(2, 66);
  const verified = nacl.sign.detached.verify(Buffer.from(response.fullMessage),
                                             Buffer.from(response.signature, 'hex'),
                                             Buffer.from(key, 'hex'));
  console.log(verified);
} catch (error) {
  console.error(error);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Event Listening

# onNetworkChange() and network()

A DApp may want to make sure a user is on the right network. In this case, you will need to check what network the wallet is using.

network

We support network: Mainnet | Devnet

'Testnet' has been modified to 'Mainnet'`

Default networks provided by the SafePal Wallet:

// default networks in the wallet
enum Network {
  Mainnet = 'Mainnet'
  Devnet = 'Devnet'
}
// Current network
let network = await window.safePal.network();
// event listener for network changing
window.safePal.onNetworkChange((newNetwork) => {
  network = newNetwork; // { networkName: 'Mainnet' }
});
1
2
3
4
5
6
7
8
9
10
11
12
13

# onAccountChange()

In SafePal Wallet, a user may change accounts while interacting with your app. To check for these events, listen for them with: onAccountChange

// get current account
let currentAccount = await window.safePal.account();
// event listener for disconnecting
window.safePal.onAccountChange((newAccount) => {
  // If the new account has already connected to your app then the newAccount will be returned
  if (newAccount) {
    currentAccount = newAccount;
  } else {
    // Otherwise you will need to ask to connect to the new account
    currentAccount = window.safePal.connect();
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13

# Errors

When making requests to SafePal Wallet API, you may receive an error. The following is a partial list of the possible errors and their corresponding codes:

 {
    code: 4100,
    message:"The requested method and/or account has not been authorized by the user."
 }
1
2
3
4
  • 4100 The requested method and/or account has not been authorized by the user.
  • 4000 No accounts found.
  • 4001 The user rejected the request