# Build with Ready

{% hint style="info" %}
Want to get in touch ? [Join us on Telegram.](https://t.me/+XFTRFHSQRqEwMWZk)
{% endhint %}

Ready is the original smart wallet. We pioneered "Guardians" for social recovery, and have been using Account Abstraction since 2018.

These docs will help you optimise your dapp for smart wallets, enabling you to offer a vastly improved experience to your users.

## Ready Wallet - The first wallet on Starknet

Ready Wallet is the first open-source wallet on Starknet powered by native account abstraction.

Available as a browser extension across different browsers’ web stores and as a mobile app, Ready Wallet helps you create, manage, and connect accounts to decentralized applications built on Starknet.

Learn more about [Ready Wallet](/ready-wallets/ready-wallet)

## **Introducing the StarknetKit SDK**

**The all-in-one SDK for Starknet developers.**

StarknetKit is built with all kinds of users in mind. Developers, crypto experts, mobile users, and complete newbies will find a way to quickly connect to your dapp. For you? only one line of code.

[**Get started with StarknetKit**](https://www.starknetkit.com/docs/latest/getting-started)

## Ready Web Wallet SDK – no download, no seed phrase onboarding

**No wallet? No problem.**

If your target audience doesn't have a crypto wallet, this is for you. They'll create a wallet with an email address and password. No plugin. No download. No seed phrase.

It's the fastest, most familiar way for a normie audience to use your dapp.

[**Build with Web Wallet SDK**](/ready-wallets/web-wallet)

{% hint style="info" %}
[Notice a bug or missing feature in our products ? ](https://argent-engineering.canny.io/argent-x-feedback-and-bugs-report)
{% endhint %}


# Ready Wallet

[Ready Wallet](https://www.ready.co/ready-wallet) is the first open-source wallet on Starknet powered by native account abstraction.

Available as a browser extension across different browsers’ web stores and as a mobile application, Ready Wallet helps you create, manage, and connect accounts to decentralized applications built on Starknet.

In the next few sections, you are going to be learning how to integrate Ready Wallet in your dApps.\
\
[**Got feedback or bugs to report ?** ](https://discord.com/invite/T4PDFHxm6T)


# Adding Custom RPCs

Ready Wallet provides you with the ability to add custom RPCs (Remote Procedure Calls). You could do this following these steps:

1. Open your Ready Wallet extension, then navigate to Settings → Developer settings → Manage Networks&#x20;
2. Click on the **+** icon to add a new network.

<figure><img src="/files/YEBxxkwSBZa9O5if4RYW" alt="" width="357"><figcaption></figcaption></figure>

Fill in the `Network name`, `Chain ID` and `RPC URL`.

3. Next up, click on "Advanced settings", and fill in the `Account class hash`, `Fee token address`, and `Multicall address`. You could optionally fill in the other fields.

* Account class hash - represents the class hash for the account implementation.
* Fee token address - represents the address of the token with which fees are paid on the network.
* Multicall address - address of multicall contract.

<figure><img src="/files/p6kIlZ88uZOzSz5odCiX" alt=""><figcaption></figcaption></figure>

4. Finally, click on Save and your new custom RPC will be added to your Ready Wallet. To add tokens such as ETH to your wallet, simply click on *"New Token"* and fill in the required details.

<figure><img src="/files/b3xKaZSgJnHhDKicBWWV" alt=""><figcaption></figcaption></figure>


# Network Switcher for Dapps

The `wallet_switchStarknetChain` can be used by dapps to request that the wallet switches its active Starknet Network.

### Params

1\. **SwitchStarknetChainParameter** *(required)*

`chainId` (required)

MUST specify the integer ID of the chain as a short string.

```javascript
'SN_MAIN' || 'SN_GOERLI'
```

### Example

#### Request

```javascript
await window.starknet.request({
  type: "wallet_switchStarknetChain",
  params: {
    chainId: "SN_MAIN"
  }
});
```

#### Result

```
"null"
```


# Verify signature of undeployed account

In order to verify the signature of an undeployed account, you will need to provide a flag to Ready Wallet which will let users sign with their undeployed account:

&#x20;Pass `skipDeploy=true` in the `signMessage`

```javascript
account.signMessage(
    {
      domain: {
        name: "Example DApp",
        chainId: windowStarknet.chainId,
        version: "0.0.1",
      },
      types: {
        StarkNetDomain: [
          { name: "name", type: "felt" },
          { name: "chainId", type: "felt" },
          { name: "version", type: "felt" },
        ],
        Message: [{ name: "message", type: "felt" }],
      },
      primaryType: "Message",
      message: {
        message,
      },
    },
    // @ts-ignore
    { skipDeploy: true },
  )
```


# WalletAccount

The WalletAccount starknet.js class allows developers to integrate browser wallets (like Ready Wallet) into their decentralized applications to sign transactions.

It's similar to the regular Ready smart contract class but can interact with browser wallets to manage signatures and transactions. \
\
It is the base object to use in any typescript/js/react project.&#x20;

[See documentation](https://starknetjs.com/docs/next/guides/walletAccount/)


# Ready Multisig

Ready's Multisig is a must-have for companies, protocols and DAOs holding crypto.\
Our Multisig is tailor-made for the Starknet ecosystem, and we’ve harnessed account abstraction to offer unrivaled security, simplicity and extensibility.

{% hint style="info" %}
For more information and support on how to set-up a multisig, please [refer to this page](https://support.argent.xyz/hc/en-us/sections/18583054089757-Multisig-account)
{% endhint %}

### Ready’s Approach to Building a Multisig

The image below shows two different approaches to constructing a multisig:

<figure><img src="/files/kK55nhzCkhTKqpUcDICR" alt=""><figcaption></figcaption></figure>

On the right you can see how traditional multisigs are designed, particularly in the EVM space. The multisig is controlled by standard accounts (i.e. EOAs in EVM space), which are controlled by signers (i.e. private keys). Due to the lack of account abstraction, that was the best solution for designing a multisig.

The illustration on the left shows the design of Ready's Multisig. By leveraging Starknet’s native account abstraction, it is possible to build a much simpler and more direct form of a multisig account. As shown in the illustration, there is no need for single accounts per signer. A signer can directly interact with the multisig account. This brings a few advantages that we will highlight below.

### Advantages of Ready's Multisig

**Security:** Our contracts are already implemented in the new and more secure Cairo1 language. Furthermore, the smart contracts have been carefully audited by Consensys Diligence. Check out the [audit](https://github.com/argentlabs/argent-contracts-starknet/blob/main/audit/Consensys-Diligence-argent-audit-2023-05.pdf) to understand the details.&#x20;

**Simplicity**: Compared to the traditional multisig approach in the EVM space, our approach implements multisig accounts in a much simpler and more direct way. From a technical point of view, the account is like any other account except that it requires more signatures to execute a transaction. This has a couple of advantages:

* Transaction fees: Multisig can pay for its own gas fees, which is better for teams. In a traditional EOA multisig the last owner needs to pay for the transaction execution. It’s also easier to track transaction fees for your team. Your accountants will thank us later.&#x20;
* Transaction execution:Executing a transaction simply needs the required signatures, which can be efficiently synchronised off-chain. This ensures quick and reliable transaction execution, even for extensive multisig setups.

**Extensibility:** The Multisig smart contract fills a crucial gap on Starknet. We designed it to be open for future extensions, free of custom logic or ties to Ready wallets. This allows anyone to build applications on it or customise the basic Multisig contract as needed.

**Flexibility**: We offer great flexibility with our signer options. Aside from your Ready X wallet, you are also provided with the option to use a Ledger hardware wallet as a signer. In the future we also plan to support the Ready mobile wallet, and many more.


# How multisig works

## **Creating/Joining a multisig**

Users can now create or join “multisig accounts” in addition to “Standard accounts” and "Smart Accounts". When a user creates or joins a new multisig account, Ready Wallet generates a private and public keypair for the user (like for individual accounts).

We refer to the private key as “signer key” and to the public key as “signer pubkey”. On the Ready Wallet UI, whenever a user interacts with the other owners, represented by their “signer pubkeys”, they will be shown encoded as “Base58” to avoid any confusion with account addresses or private keys.

## **Setting the owners and the threshold**

The creator can define a multisig with 1 to 32 owners (i.e. signer pubkeys) depending on the needs of the team. And, the creator needs to define a threshold like “3 out of 5”, i.e. the required signatures out of all owners to execute a transaction.

## **Funding and activation**

Once the multisig is defined, the creator needs to fund it with a bit of ETH to be able to activate it. That’s a simple deployment of the smart contract with the defined parameters like signer pubkeys and threshold on Starknet. After completion, the multisig is active and any change to it will require a transaction that needs the required confirmation of the owners.

## **Creating a transaction request**

Every owner can initiate a transaction request (eg. send Eth) at any time by “confirming a transaction” like they are used to with individual accounts. The transaction request and the signatures will be shared off-chain through Ready's backend with the other owners of the multisig.&#x20;

An owner can always check the status of an “transaction request” on the activities.  The transaction will be executed on-chain as soon as the required number of owners have provided their signatures for it.

## **Signing a transaction request**

When an owner opens their multisig account they will see a notification on the activities if there is a pending transaction request. They can review the full transaction details and existing signatures (of the other owners) and then decide to confirm or reject it.

## **Transaction execution**

When the number of confirmations reaches the threshold, the transaction is sent to the sequencer (or RPC node) and will be executed on-chain


# Create a multisig

Step-by-step guide to setting up multisig

At the moment, Ready multisig accounts support 2 types of signers: [Ready signer](/ready-wallets/ready-multisig/create-a-multisig/with-ready-signer) and [Ledger signer](https://app.gitbook.com/o/-MCCpvVJcFHdMHZ6e4GC/s/-MCCsloxVgbn9ByBE-nP/~/changes/114/argent-wallets/argent-multisig/create-a-multisig/with-ledger-signer). You can create a multisig with any combination of these signers.


# With Ready signer

## **1. Download** Ready **Wallet**

Add the [Ready Wallet extension](https://www.argent.xyz/argent-x) to your Chrome browser, open it up, and click "Create Account"

## **2. Select your account**

Select “Multisig Account”

<figure><img src="/files/QDdY1EWTOMmBgO4S5T9e" alt=""><figcaption></figcaption></figure>

## **3. Fill in the signer pubkeys of the other owners**

You will be redirected to an expanded version of Ready Wallet, fill in the signer keys for the Multisig and click “**Next**”. You can add as many signers/owners as you want. It’s required to use signer pubkeys from different Ready wallets for security purposes.

<figure><img src="/files/4QxKkFlBTIi4cSfTYBk3" alt="" width="375"><figcaption></figcaption></figure>

## **4. Get the signer keys from other owners**

To get signer pubkeys from other owners, ask them to follow the same process in step 1. When they are on step 2, they need to select “**Join existing Multisig**”. This will generate their signer pubkey, which they send to you.

<figure><img src="/files/dFoUk64Mi6xba6pZlCLC" alt="" width="358"><figcaption></figcaption></figure>

## **5. Set the multisig threshold**

Select the threshold. This is the number of valid signatures required to execute a transaction. Then click “**create multisig**”

<figure><img src="/files/EAqh5UVTzxizYEyXdwcz" alt="" width="375"><figcaption></figcaption></figure>

## **6. Fund and activate the multisig**

Now that your multisig has been successfully created, you need to add some funds (ETH) to it and activate it with a simple deploy transaction.

<figure><img src="/files/cutTENsVywiQjKZjd43l" alt=""><figcaption><p>Fund the account and click on "Activate Multisig"</p></figcaption></figure>

## **7. Set-up complete ☑️**<br>


# With Ledger signer

By adding Ledger to your Ready Multisig, you’ll combine the security of Ready and of the industry's leading hardware wallets. Trusted by the Starknet Foundation, the Ready Multisig is the go-to wallet for companies, protocols and DAOs building on Starknet.

Before you start, you will need:

* [Ready Wallet](https://www.argent.xyz/) installed on your browser
* A Ledger wallet (Nano X or Nano S Plus)
* The Starknet app installed on your Ledger, using [Ledger Live](https://www.ledger.com/ledger-live) (you will need to enable the developer mode in Settings > Experimental features)

## Step 1: Create a new multisig

Open Ready Wallet, go to accounts and add a new account. Select “Multisig Account”, "Create new multisig" and "Create with Ledger".

<figure><img src="/files/UkPYgnIPh6cIydB30xna" alt=""><figcaption></figcaption></figure>

## Step 2: Connect your Ledger

You will be prompted to plug in and unlock your Ledger. Then, open the Starknet app in Ledger and click “Connect”. Before doing this, ensure the Starknet app is installed on your Ledger from Ledger Live.

<figure><img src="/files/vxYARs3KKhQy57WkGoML" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/G4fts4n9doIMlzbQOhGK" alt=""><figcaption></figcaption></figure>

## Step 3: Add owners

Your signer pubkey is generated from the Ledger. You can now add the signer pubkeys of the other multisig owners and click “Next”. You can add as many signers/owners as you want.

For more information on how additional owners can generate a signer pubkey, see *Join a new multisig with Ledger* section belo&#x77;*.*

<figure><img src="/files/y9EgU1pa1is5D0OI2OmN" alt=""><figcaption></figcaption></figure>

## Step 4: Set the multisig threshold

Select the threshold. This is the number of valid signatures required to execute a transaction.  It is recommended to use a n-of-m signatures scheme with n < m (e.g. 3 out of 4).. Then click “create multisig”.

<figure><img src="/files/pOeKVdWLBaLQMTACu6Mi" alt=""><figcaption></figcaption></figure>

## Step 5: Fund and activate your multisig

Congrats, your multisig has been created ! Don’t forget to fund your Multisig with some ETH to activate it.

<figure><img src="/files/MBReguHWlNcX2Zxxiyie" alt=""><figcaption></figcaption></figure>

## Step 6: Sign with Ledger

Next time you need to sign a multisig transaction, you will be prompted to connect and confirm with Ledger.

<figure><img src="/files/qBrzOYYMm8GORbNurGg5" alt=""><figcaption></figcaption></figure>


# Join a multisig


# With Ready signer

## Step 1: Join a new multisig

Open Ready Wallet, go to accounts and add a new account. Select “Multisig Account”, “Join existing multisig” and “Join with Ready Wallet”.

<figure><img src="/files/pNRbgPWhab2Np24yEOgk" alt=""><figcaption></figcaption></figure>

## Step 2: Share your signer pubkey

Your signer pubkey is generated by Ready. Copy the signer pubkey and share it with the multisig creator. Then click “Finish”.

<figure><img src="/files/WIuqS2H1mC5eQSxdxBmP" alt=""><figcaption></figcaption></figure>

## Step 3: Wait for creator to finish setup

Wait for the multisig creator to add your signer pubkey to the Ready Multisig. If needed, your signer pubkey can be retrieved by clicking on the multisig in the account list.<br>


# With Ledger signer

## Step 1: Join a new multisig

Open Ready Wallet, go to accounts and add a new account. Select “Multisig Account”, “Join existing multisig” and “Join with Ledger”.

If you don’t have a Ledger device, you can also join a multisig using  “Join with Ready”.

<figure><img src="/files/m4tlR3lVk1OLqq3W6wvR" alt=""><figcaption></figcaption></figure>

## Step 2: Connect your Ledger

You will be prompted to plug in and unlock your Ledger. Then, open the Starknet app in Ledger and click “Connect”. Before doing this, ensure the Starknet app is installed on your Ledger from Ledger Live.

<figure><img src="/files/vxYARs3KKhQy57WkGoML" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/QQK2lBaWNHj9NFywyqZB" alt=""><figcaption></figcaption></figure>

## Step 3: Share your signer pubkey

Your signer pubkey is generated from the Ledger. Copy the signer pubkey and share it with the multisig creator. Then click “Finish”.

<figure><img src="/files/PVCffY2oOqOHJIudSlW8" alt=""><figcaption></figcaption></figure>

## Step 4: Wait for creator to finish setup

Wait for the multisig creator to add your signer pubkey to the Ready Multisig. If needed, your signer pubkey can be retrieved by clicking on the multisig in the account list.

<figure><img src="/files/84uImZIOgpyVZNTDg8Tt" alt=""><figcaption></figcaption></figure>


# Replace a multisig signer

## Replace your current signer yourself

At the moment, you can’t replace your current signer (Ready or Ledger) with another signer yourself. This feature is coming soon.

## Ask another multisig owner to replace your current signer with the new one

You can ask another owner of the multisig to replace your current signer pubkey with your newly generated signer pubkey.

Ask the other owner to open the multisig account for which you want to replace your signer. Go to “Settings”, click on the account name, choose “Manage owners”, then click the settings wheel beside your name and click “Replace owner”.

Paste your newly generated signer pubkey, add a name and click “Next”.\
\
The other owner will then be prompted to sign a transaction to replace a new multisig owner.

<figure><img src="/files/CMTrcThgHr7exmr4UrHT" alt=""><figcaption></figcaption></figure>


# Airgap

The ultimate security for your Starknet operations

For maximum security, you can use your Ready Multisig in combination with Ledger and an air-gap device.

An air-gap device is a device kept offline (often a computer or phone with wifi and bluetooth removed) and whose isolation ensures its integrity. You can use that device to verify that the client you are using to broadcast transactions does not act maliciously.

**Prerequisite:**

* An air-gap device
* [A Ledger device with Starknet app installed](https://www.argent.xyz/blog/ledger-argent-integration/)

### Step 1: Set-up your air-gap device

Download the [Ready air-gap script](https://github.com/argentlabs/x-airgap) and install it on your air-gap device

### Step 2: Enable air-gap support in Ready Wallet

Go to Settings, then preferences and enable "Air Gap transaction with Ledger"

<figure><img src="/files/VoXZNjfIZDBxXFdI6a01" alt=""><figcaption><p>Enable air-gap in Argent X settings</p></figcaption></figure>

### Step 3: Initiate a transaction with your multisig

{% hint style="info" %}
Air-gap support is only available on multisigs with a Ledger signer
{% endhint %}

Connect your Ledger device and initiate a transaction with your multisig. Then, before confirming, click on "Review on air-gapped device" below the transaction review. Ready Wallet will display the transaction in the form of a QR-code.&#x20;

<figure><img src="/files/wXARewmy4mvEEUdntsEW" alt=""><figcaption></figcaption></figure>

### Step 4: Verify the transaction on your air-gap device

Launch the Ready airgap script on your airgap device and scan the QR-code displayed on Ready Wallet.

The script will decode the transaction locally and compute its hash.&#x20;

✅ If both hashes are identical and the transaction review matches your intent, you can be confident that you’re broadcasting the intended transaction to the blockchain.&#x20;

<figure><img src="/files/HCIwSvL8zIlCwUUf7Q6V" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/6O5KsqpZuthTG8jNL6KY" alt=""><figcaption></figcaption></figure>


# Web Wallet

No wallet? No problem.

{% hint style="info" %}
Need a custom web wallet implementation ? Reach out !
{% endhint %}

{% embed url="<https://www.youtube.com/watch?v=vUkSu5M8MkE&ab_channel=Argent>" %}
&#x20;Web Wallet announcement
{% endembed %}

One of our goals at Ready has always been to bring crypto adoption to the masses, and we're excited that's now possible by taking advantage of account abstraction.

In line with this, we launched Web Wallet on Starknet, which solves the frictions related to using dApps on Starknet.

## What is Web Wallet?

Web wallet is a self-custodial wallet in your browser. It takes advantage of account abstraction to bring you the best experience from both web2 and web3. You create a wallet with an email address and password, eliminating the friction that come with traditional blockchain wallets.

## Features

### 📵 **No downloads**

With web wallet, users can now interact with dapps on Starknet, without downloading a mobile app or installing a Chrome extension!

All that is needed is an email address, thereby introducing the best parts of the web2 experience we all love!

### 🌱 **No seed phrases**

Web3, decentralized money, NFTs. Such exciting, revolutionary ideas!

Until you lose your life savings because you misplaced your wallet's seed phrase.

With the advent of web wallet, you no longer need to fear losing your assets, as you can now access your wallet using just an email and a password, which is easily recoverable if lost!

### 🛡️ **Security**

Web wallet is secured by Ready Guardian which can help to keep your funds secure and detects and alerts you of malicious dapp interactions.

Of course, it is fully self-custodial, meaning that you remain in full custody/possession of your asset at all times. Your key is generated by your password,&#x20;

### 👩‍💻 Multi-device

Just like with web2 application, you can use your web wallet across multiple devices with no friction. All you need to do is log in with your email and password!

## Community

We're excited to see the community adopt Web Wallet, raise issues, and provide feedback. Whether it's a feature request, a bug report, or a project to showcase, please get involved!

* Raise an [issue](https://github.com/argent-labs)
* Follow on [Twitter](https://twitter.com/argentHQ)
* Join [Discord](https://discord.gg/argenthq)


# Set up guide

{% hint style="info" %}
For more information on web wallet integrations, refer to the [StarknetKit documentation](https://www.starknetkit.com/docs/latest/connectors/web-wallet)
{% endhint %}

### Installation

To get started with integrating the web wallet SDK in your dApp, you will need to install the **\`starknetkit\`** package and its peer dependencies:

```bash
  yarn add starknetkit
```

or for usage with NPM:

```bash
  npm install starknetkit
```

#### Imports

After installation, we get access to different methods, such as `connect` , `disconnect`, etc which we should import for use in our application:

```js
import { connect, disconnect } from 'starknetkit'
```

#### Establishing a connection

To establish a wallet connection, we need to call the `connect` method which was imported earlier like this:

```javascript
const connection = await connect();
```

Below is an example function that establishes a connection, then sets the `connection`, `provider`, and `address` states:

```js
const connectWallet = async() => {
  const connection = await connect({webWalletUrl: "https://web.argent.xyz"});

  if(connection && connection.isConnected) {
    setConnection(connection)
    setProvider(connection.account)
    setAddress(connection.selectedAddress)
  }
 }
```

And to reconnect to a previously connected wallet on load:

```js
const connection = await connect({modalMode: "neverAsk", webWalletUrl: "https://web.argent.xyz"})
```

{% hint style="info" %}
It's important to note that web wallet is only available for users on mainnet. If as a dApp for integration and testing purposes, you need access to an internal testnet environment, please contact Argent privately.
{% endhint %}

For a detailed guide on how to integrate web wallet in starknet-react based applications, please refer to the [StarknetKit documentation](https://www.starknetkit.com/docs/latest/starknetkit-with-starknet-react/basics).

### Signing transactions

Signing transactions in web wallet is similar to how it's done using the Argent X browser extension.

```javascript
const tx = await connection.account.execute({
   //let's assume this is an erc20 contract
   contractAddress: "0x...",
   selector: "transfer",
   calldata: [
	"0x...",
	// ...
   ]
})
```

It will show up like this to the user:

<figure><img src="/files/x8lcOSYJNtNpn82XXejm" alt=""><figcaption></figcaption></figure>

If the user's wallet is already funded it will ask the user to confirm the transaction. The dapp will get feedback if the user has confirmed or rejected the transaction request. If confirmed, the dapp will get a transaction hash.

**Users wallet is not funded**

In a case where the user has no funds, the user is guided through the “Add funds” screens where they can go to on-ramps and more. We tried to make the funding process of new wallets as easy as possible with regards KYC. Once this process is completed, the user's wallet will be funded and now ready to be deployed.

**Users wallet is not deployed**

After a user has funded their wallet, they are ready for their first transaction. The wallet deployment will be done along the first transaction and is almost invisible to the user. Just note that a connected wallet may not be deployed yet.


# Web Wallet UX

customization tips, UX guidelines

### Dapp theming

The Web Wallet SDK gives developers the option to customize the look of the connect Modal.

You could choose which wallet options you would like to make available to your users, or decide to go email only!

<figure><img src="/files/OreeKAMeLo321zwDQ9oP" alt=""><figcaption><p>All modal variants</p></figcaption></figure>

For full connection options (1st option shown):

```js
const connection = await connect();
```

For an alternative look (2nd option shown):

<pre class="language-js"><code class="lang-js">const connection = await connect({
<strong>   modalWalletAppearance: "all" 
</strong>});
</code></pre>

For email only (3rd option shown):

```js
const connection = await connect({
  include: ["argentWebWallet"]
  modalWalletAppearance: "email_only",
});
```

To exclude web wallet from the modal:

```js
const connection = await connect({
  exclude: ["argentWebWallet"]
});
```

### Detecting Web Wallet

&#x20;Often times, you'll need to implement checks to see if a user is already connected to web wallet, and if yes, carry out actions such as providing a button to access the user's dashboard. You could do this by simply checking for the `id` field in the `window` object, but first you need to establish a connection.

<pre class="language-javascript"><code class="lang-javascript"><strong>const connectWallet = async() => {
</strong>  const connection = await connect({webWalletUrl: "https://web.ready.co"});

  if(connection &#x26;&#x26; connection.isConnected) {
    setConnection(connection)
    setProvider(connection.account)
    setAddress(connection.selectedAddress)
  }

  console.log(connection)
 }
</code></pre>

Then we could simply check that `id` is equal to `argentWebWallet`, and if yes, show a button that links to the [dashboard](https://web.ready.co/).

```jsx
{
    connection.id == 'argentWebWallet' ? <a href='https://web.ready.co/'><button className='connectbtn'>Dashboard</button></a>
    : ''
}
```

### UX guidelines

In this section, we are going to be looking at certain UX tips dApps could implement from their end to make the web wallet user experience better:

1. **Easy access to web wallet dashboard:** We provide a dashboard for web wallet, where users can carry out basic activities such as funding their wallet, sending funds to other accounts, viewing connected dApps etc. We recommend that dApps show a button somewhere in the UI to “go to wallet”, where they link to [<mark style="background-color:yellow;">web.ready.co</mark>](https://web.ready.co/)<mark style="background-color:yellow;">.</mark>

<figure><img src="/files/4GjEWkIMf67OQsAwG05E" alt=""><figcaption><p>Starknet.id web wallet custom button</p></figcaption></figure>

2. **Adding a transaction tracker:** Since web wallet is not one-click accessible like we have with browser extensions, users might find it difficult to track the progress of their transactions. To solve this, dApps will need to come up with custom solutions to communicate the progress of transactions with the users.
3. **Custom transaction history**: Following the issue mentioned in the second tip above, users will most likely also not be able to access a list of previous transactions carried out from interacting with the dApps. dApps could also come up with custom solutions to help users monitor and track their past activities on the dApp.

<div data-full-width="false"><figure><img src="/files/GhGIvT0GXJXcMPxLI7nH" alt=""><figcaption><p>Briq custom transaction history</p></figcaption></figure></div>


# API reference

The `starknetkit` package exposes two major methods `connect` and `disconnect.` (You could reference the Guides section to see how they are used).

The `connect` method further exposes other methods you could find useful in your dapps:

1. `isConnected` - This method available after an attempt to establish a connection, can be used to confirm if an account was truly connected.

```json
isConnected: true
```

2. `selectedAddress` - This method can be called to get the wallet address of a connected account.

```json
selectedAddress?: string
```

3. `account` - This method gives us access to the account object. It uses [starknet.js AccountInterface](https://www.starknetjs.com/docs/next/API/account) and extends the starknet.js Provider.

```json
account?: AccountInterface
```

4. `chainId` - This method returns the connected network chain ID.

```json
chainId?: string
```

5. `provider` - This method gives us access to the Provider object when called. It uses [starknet.js Provider Interface](https://www.starknetjs.com/docs/next/api/provider/) enabling you to interact with the network without signing transactions or messages.

```json
provider: ProviderInterface
```

6. `enable` - This method can be used to create a connection to a specific **get-starknet** version.

```json
enable: (options?: { starknetVersion?: 'v3' | 'v4' }) => Promise<string[]>
```


# Key Management

### Architecture

#### Guardian

The Web Wallet is a smart-account wallet, with the Ready Backend acting as a co-signer/guardian. The account is secured by 2 keys: the Signer Key and Guardian Key. The security model requires both signer and guardian signatures to submit a valid transaction (except for recovery-related actions, where one signer is enough).

The Guardian Key is stored in the Ready backend while the Signer Key is **encrypted** and stored in the Ready backend in two different versions: password-encrypted and device-encrypted.

#### Password-encrypted Signer Key

When a user creates a new Web Wallet account, a signer key is randomly generated, encrypted by the user’s password, and securely stored in Ready's backend.

<figure><img src="/files/qBBIFLdGCrS0WNhsAv16" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
At no point, does Ready have access to an unencrypted form of the signer key (thus making it a proper self-custodial wallet).
{% endhint %}

#### Signing transactions

In order to sign a transaction, the users needs to:

1. Authenticate with Ready's backend through a password-less flow to retrieve the password encrypted signer key
   1. The user is asked to input his email address
   2. They receive an email with a 6-digit verification code
   3. If the correct verification code is inputted, the user is successfully authenticated.
2. Decrypt the password-encrypted signer key with their password

{% hint style="info" %}
To avoid users having to input their password for every transaction, every time a user inputs their password and decrypts their Signer Key at login or to sign a transaction, the key will be re-encrypted with an ephemeral key and stored in the Ready backend.

If the user needs to sign a transaction within 5 minutes time frame, this encrypted key will be fetched from the backend and decrypted locally with the ephemeral key.
{% endhint %}

#### Device-encrypted Signer Key

In addition to the password-encrypted Signer Key, a device-encrypted signer key used for recovery is also generated and stored in the Ready backend:

1. Web wallet generates a device encryption key that is stored in the browser local storage
2. The device encryption key is used to encrypt the signer key
3. The device-encrypted signer key is stored in the Ready backend

<figure><img src="/files/x7yCvOVdmoUxoige7NrX" alt=""><figcaption></figcaption></figure>

So, the Ready Backend holds two versions of the signer private key: one encrypted with the password and another encrypted with the device key.

### Recovery

Two recovery mechanisms are in place in case the user forgets their password:

* Offchain recovery: uses the device-encrypted or password-encrypted Signer Key
* Onchain recovery: relies on the smart account security model, i.e. the Guardian Key is able to trigger a recovery (with a time lock)

#### Offchain recovery

**Scenario 1: the user forgot their password but still have access to a trusted device**

In this case, the user can still authenticate with the Ready backend using their email address and retrieve their device-encrypted signer key which can, in turn, be decrypted using the device encryption key stored in the local storage.

**Scenario 2: the user still have their password but lost access to their device**

In this case, the user can authenticate with the Ready backend using their email address on a new device (browser), retrieve the password-encrypted signer key and decrypt it with their password.

**Scenario 3: the user have lost both their password and trusted device**

*See onchain recovery*

{% hint style="info" %}
Additionally, users can choose to back-up (export) their private key and use it for offchain recovery.
{% endhint %}

#### Onchain recovery

The on-chain recovery is a process at the blockchain level, where the account’s guardian is allowed to replace the account’s signer. The user will generate a new signer key and encrypt it with a new password.

1. The user authenticates with Ready using the email-based passwordless flow and requests an onchain recovery
2. This triggers a 7-days timelock where the user will regularly receive emails informing them that a recovery has been started. If they did not initiate that recovery themselves, they can halt it.
3. After 7 days, the signer will be replaced, and the user will receive a confirmation email letting them know they can now use their account.

#### Guardian removal

If they wish to remove the guardian, users can trigger an escape mechanism that will remove the guardian after a timelock of minimum 7 days.

{% hint style="info" %}
The timelock, or security period, gives users time to react if an attacker is attempting to remove the guardian
{% endhint %}

<figure><img src="/files/921yXpHSmG2PExRvpwsI" alt=""><figcaption></figcaption></figure>


# Telegram wallet (DEPRECATED)

Connecting Telegram's users to Ethereum.

### 🚨 <mark style="color:red;">UNFORTUNATELY, DUE TO NEW TELEGRAM RULES, IT IS NO LONGER POSSIBLE TO USE ARGENT TELEGRAM WALLET AND READY TELEGRAM SDK.</mark>

The Ready Telegram Wallet is a self-custody, embedded wallet within Telegram. By leveraging account abstraction, users benefit from a best-in-class experience while retaining ownership of their assets. The goal here is to abstract away the concept of blockchain.

To set up and use the wallet, please follow this guide: [**How to use the Argent Telegram Wallet**.](https://www.argent.xyz/blog/how-to-use-argent-telegram-wallet)

Talking about the Ready Telegram Wallet, we have to differentiate two features: the wallet and the SDK.

The wallet/bot enables end-users to:

* Send (including Gifting)
* Send with bot (including Gifting)
* Add Funds
* Unlock with biometrics

The SDK enables mini-app developers to:

* Seamlessly establish connection between the dapp and the wallet (like [StarknetKit](https://www.starknetkit.com/))
* Leverage [session keys](https://docs.argent.xyz/aa-use-cases/session-keys) to highly improve the user experience.

Under the hood, our Telegram wallet leverages the same smart-account technology that is used for other Argent wallets, like the Mobile wallet. Part of the signing process is handled by our backend. It is somewhat similar to a 2-2 multisig wallet. To make a transaction, both the Telegram wallet signature and the Argent backend signature are required. The private key of the Telegram wallet is stored on the user’s Telegram cloud space.

The private key is encrypted using your pin or secure enclave if your enable biometric.


# Setup guide

#### 1. [Create a telegram test account](https://docs.ton.org/v3/guidelines/dapps/tma/guidelines/testing-apps#using-bots-in-the-test-environment)

#### 2. Add a username to your test account

#### 3. Install dependencies

```tsx
npm install @argent/tma-wallet starknet
```

[@argent/tma-wallet](https://www.npmjs.com/package/@argent/tma-wallet) is the Telegram wallet library.

[starknet.js](https://starknetjs.com/docs/guides/intro) is used to interact with Starknet.

#### 4. Create a Telegram Bot

Start a chat with [@BotFather](https://telegram.me/BotFather).

Prompt `/newbot` and follow the instructions.

#### 5. Create a Telegram mini-app

Run `/newapp` and follow the instructions.

You’ll be asked by BotFather to send a webapp url. You can either send anything and change it later or complete this after deploying your webapp.


# Implementation

SDK implementation guide.

#### 1. Import dependencies in your project

```tsx
import { ArgentTMA, SessionAccountInterface } from '@argent/tma-wallet';
```

#### 2. Initialize the ArgentTMA object

Initialize the `ArgentTMA` object with your app configuration:

```tsx
const argentTMA = ArgentTMA.init({
  environment: "sepolia", // "sepolia" | "mainnet" (Whitelisting required)
  appName: "My TG Mini Test Dapp", // Your Telegram app name
  appTelegramUrl: "<https://t.me/my_telegram_bot/app_name>", // Your Telegram app URL
  sessionParams: {
    allowedMethods: [
      // List of contracts/methods allowed to be called by the session key
      {
        contract:
          "0x036133c88c1954413150db74c26243e2af77170a4032934b275708d84ec5452f", // contract address
        selector: "increment", //function selector
      }
    ],
    validityDays: 90 // session validity (in days) - default: 90
  },
});
```

#### 3. Request a connection

If the user is not connected, call the `requestConnection()` method to open the wallet and ask the user to approve the connection. At the same time, you can ask user for token approvals:

```tsx
const handleConnectButton = async () => {
  await argentTMA.requestConnection({
        callbackData: 'custom_callback',
        approvalRequests: [
          {
            tokenAddress: '0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7',
            amount: BigInt(1000000000000000000).toString(),
            spender: 'spender_address',
          }
        ],
      });
};

```

The wallet will redirect back to your app and the account will be available from the `connect()` method.

#### 4. Check connection status

You can check if the user is connected at any time using the `isConnected()` method:

```tsx
const isConnected = argentTMA.isConnected();
```

#### 5. Connect to the wallet

Call the `connect()` method when your app loads to check if the user is already connected. It is also used to fetch the `account` object. It is an extended `starknet.js` account object.

For instance, you could wrap this in a `useEffect` hook.

```tsx
useEffect(() => {
    // Call connect() as soon as the app is loaded
    argentTMA
      .connect()
      .then((res) => {
        if (!res) {
          // Not connected
          setIsConnected(false);
          return;
        }
        
        const { account, callbackData } = res;

        if (account.getSessionStatus() !== "VALID") {
          // Session has expired or scope (allowed methods) has changed
          // A new connection request should be triggered

          // The account object is still available to get access to user's address
          // but transactions can't be executed
          const { account } = res;

          setAccount(account);
          setIsConnected(false);
          return;
        }

        // The session account is returned and can be used to submit transactions
        setAccount(account);
        setIsConnected(true);
        // Custom data passed to the requestConnection() method is available here
        console.log("callback data:", callbackData);
      })
      .catch((err) => {
        console.error("Failed to connect", err);
      });
  }, []);
```

#### 6. Interact with Starknet using the account

You can interact with your contracts using starknet.js. For instance, you could do this:

```tsx
const { transaction_hash } = await account.execute(myCall, {
      version: 3,
      maxFee: 10 ** 15,
      feeDataAvailabilityMode: RPC.EDataAvailabilityMode.L1,
      resourceBounds: {
        l1_gas: {
          max_amount: num.toHex(maxQtyGasAuthorized),
          max_price_per_unit: num.toHex(maxPriceAuthorizeForOneGas),
        },
        l2_gas: {
          max_amount: num.toHex(0),
          max_price_per_unit: num.toHex(0),
        },
      },
    });
```

#### 7. Check account session status

```tsx
const sessionStatus = account.getSessionStatus();
// "VALID" | "EXPIRED" | "INVALID_SCOPE" | "INVALID_SIGNATURE"
```

#### 8. Request approval

It is possible to ask to user to sign new approval transactions with `requestApprovals()`.

```typescript
async function handleApproval() {
    try {
      const res = await argentTMA.requestApprovals(
        [
          {
            tokenAddress: '0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7',
            amount: BigInt(1000000000000000000).toString(),
            spender: 'spender_address',
          }
        ],
      );
    } catch (error) {
      console.error('Approval failed:', error);
    }
  }
```

#### 9. Clear session

Calling `clearSession` removes the session object from local storage. It is mostly used for debugging. The session would still be valid on-chain.

We could imagine doing something like this:

```tsx
const handleClearSessionButton = async () => {
    await argentTMA.clearSession();
    setAccount(undefined);
  };
```

***

List of useful ressources:

* [npm package](https://www.npmjs.com/package/@argent/tma-wallet)
* [Tamagotchi coding tutorial](https://www.argent.xyz/blog/argent-telegram-tamagotchi)
* [Building a Telegram Game on Starknet](https://hackmd.io/@manoah22/Sk_eRyi1Jx#Building-a-Telegram-Game-on-Starknet-with-Argents-Wallet-SDK-A-Step-by-Step-Guide)


# Types and interfaces

List of important types.

```tsx
type SessionParameters = {
  allowedMethods: Array<{
    contract: string;
    selector: string;
  }>;
  validityDays?: number;
};
```

```tsx
type ConnectResponse = {
    account: SessionAccountInterface;
    initData?: InitDataParsed;
    callbackData?: string;
};
```

```tsx
interface SessionAccountInterface extends AccountInterface {
  isDeployed(): Promise<boolean>;
  getDeploymentPayload(): Promise<DeployAccountContractPayload>;
  getOutsideExecutionPayload({ calls }: { calls: Call[] }): Promise<Call>;
  getSessionStatus(): SessionStatus; // "VALID" | "EXPIRED" | "INVALID_SCOPE"
}
```

```typescript
interface ArgentTMAInterface {
    provider: ProviderInterface;
    sessionAccount?: SessionAccountInterface;
    connect(): Promise<ConnectResponse | undefined>;
    requestConnection(callbackData: string): Promise<never>;
    isConnected(): boolean;
    exportSignedSession(): Promise<ArgentTMASession | undefined>;
    clearSession(): Promise<void>;
}
```

```typescript
type ArgentTMASession = {
    version: number;
    privateKey: string;
    publicKey: string;
    sessionInfo: OffChainSession;
    deploymentPayload?: AccountDeploymentPayload;
    signature?: Signature;
    address?: string;
};
```


# Ready Card

Crypto in, cash out

{% embed url="<https://card.ready.co>" %}

{% hint style="info" %}
[Refer to the FAQ for more information](https://www.ready.co/blog/card-faqs)
{% endhint %}


# Ready Mobile for your react native app

You can connect your mobile native application to Ready with Wallet Connect.

### Step 1: Install packages

First, install the required packages from WalletConnect (now Reown):

```sh
pnpm install @walletconnect/universal-provider @walletconnect/types @walletconnect/core @walletconnect/react-native-compat
```

### Step 2: Configure URL Schemes

For an EXPO project, update your app.json:

```json
{
  "expo": {
    "scheme": "yourappscheme",
    "ios": {
      "infoPlist": {
        "LSApplicationQueriesSchemes": [
          "argent",
          "argentx",
          "argentmobile"
        ]
      }
    }
  }
}
```

### Step 3: Initialize the WalletConnect Provider

```typescript
const initializeProvider = async () => {
  try {
    console.log('Initializing provider...');

    const projectId = 'your wallet connect project id';

    const metadata = {
      name: 'Wallet connect Test',
      description: 'Test app for connecting to Ready',
      url: 'https://walletconnect.com/',
      icons: ['https://avatars.githubusercontent.com/u/37784886'],
    };

    const providerInstance = await UniversalProvider.init({
      projectId,
      metadata,
      relayUrl: 'wss://relay.walletconnect.com',
    });

    console.log('Provider initialized successfully');
    return providerInstance;
  } catch (err: any) {
    console.error('Error initializing provider:', err);
    throw err;
  }
};
```

### Step 4: Initialize the Provider on Component Mount

Add a useEffect hook to initialize the provider when the component mounts:

```typescript
useEffect(() => {
  initializeProvider()
    .then((prov) => {
      console.log('Provider initialized successfully');
      setProvider(prov);

      // Check if we already have an active session
      const activeSessions = Object.values(prov.session || {});
      if (activeSessions.length > 0) {
        console.log('Found active session:', activeSessions[0]);
        setSession(activeSessions[0] as SessionTypes.Struct);

        // Extract account if available
        const starknetAccounts =
          activeSessions[0]?.namespaces?.starknet?.accounts;
        if (starknetAccounts && starknetAccounts.length > 0) {
          const accountAddress = starknetAccounts[0].split(':')[2];
          setAccount(accountAddress);
        }
      }
    })
    .catch((err) => {
      console.error('Provider initialization failed:', err);
      setError('Setup failed: ' + (err?.message || 'Unknown error'));
    });
}, []);
```

### Step 5: Implement Deep Linking to Ready Mobile

Add a function to open the Ready Mobile wallet:

```typescript
const openWallet = async (uri: string) => {
  const encodedUri = encodeURIComponent(uri);

  // Use Argent's deep link scheme
  const argentScheme = `ready://wc?uri=${encodedUri}`;
  console.log('Opening Ready with scheme:', argentScheme);

  try {
    await Linking.openURL(argentScheme);
    console.log('Successfully opened Ready');
  } catch (err) {
    console.error('Failed to open Ready:', err);
    setError(
      'Failed to open Ready. Please make sure it is installed.'
    );
  }
};
```

### Step 6: Connect to Ready Mobile

```typescript
const connect = async () => {
  if (!provider) return;
  
  try {
    // Request connection
    const { uri, approval } = await provider.client.connect({
      requiredNamespaces: {
        starknet: {
          chains: ['starknet:SNMAIN'], // Use SNSEPOLIA for Sepolia testnet
          methods: ['starknet_account', 'starknet_requestAddInvokeTransaction'],
          events: ['accountsChanged', 'chainChanged']
        }
      }
    });
    
    // Open wallet with URI
    if (uri) {
      const encodedUri = encodeURIComponent(uri);
      await Linking.openURL(`ready://wc?uri=${encodedUri}`);
    }
    
    // Wait for approval
    const newSession = await approval();
    setSession(newSession);
    
    // Extract account
    if (newSession?.namespaces?.starknet?.accounts?.length > 0) {
      setAccount(newSession.namespaces.starknet.accounts[0].split(':')[2]);
    }
  } catch (err) {
    setError(err.message);
  }
};
```

### Step 7: Disconnect from the wallet

```jsx
const disconnect = async () => {
  if (!provider || !session) return;
  
  try {
    await provider.disconnect();
    setSession(null);
    setAccount(null);
    setTxHash(null);
  } catch (err) {
    setError(err.message);
  }
};
```

### Step 8: Send a Transaction

To send requests to the client, the chainId is required.

Use the following chainID:

* Starknet mainnet: `starknet:SNMAIN`
* Starknet Sepolia: `starknet:SNSEPOLIA`

```jsx
const sendTransaction = async () => {
  if (!provider || !session || !account) return;
  
  try {
    // Try to open Ready
    await Linking.openURL('ready://');
    
    // Create transaction
    const transaction = {
      accountAddress: account,
      executionRequest: {
        calls: [
          {
            contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7', // ETH token
            entrypoint: 'transfer',
            calldata: [
              account, // to (self)
              amount, // u256.low
              '0x0' // u256.high
            ]
          }
        ]
      }
    };
    
    // Send transaction request
    const result = await provider.client.request({
      topic: session.topic,
      chainId: 'starknet:SNMAIN', // Or starknet:SNSEPOLIA
      request: {
        method: 'starknet_requestAddInvokeTransaction',
        params: {
          accountAddress: transaction.accountAddress,
          executionRequest: transaction.executionRequest
        }
      }
    });
    
    if (result?.transaction_hash) {
      setTxHash(result.transaction_hash);
    }
  } catch (err) {
    setError(err.message);
  }
};
```

The full example is in this repo: [demo-walletconnect-rn-mobile](https://github.com/0xEniotna/demo-walletconnect-rn-mobile.git)

You will also need the specific [Wallet Connect  RPC reference for Starknet](https://docs.walletconnect.com/advanced/multichain/rpc-reference/starknet-rpc#starknet_requestaddinvoketransaction).


# Invisible SDK (DEPRECATED)

Seamless blockchain experience.

### 🚨 <mark style="color:red;">THE INVISIBLE SDK IS NO LONGER MAINTAINED. THERE WILL NOT BE NEW FEATURES OR BUG FIXES.</mark> &#x20;

The Ready Invisible SDK provides a seamless blockchain experience to your users. Invisible SDK is a combination of two Ready products: [WebWallet](/ready-wallets/web-wallet) and [Session Keys](/aa-use-cases/session-keys).&#x20;

Users can interact with your Dapp using just their email address - no more seed phrases or private keys. Behind the scenes, the SDK combines a self-custodial web integrated wallet with session keys to make blockchain interactions completely invisible to the user.

### The SDK provides:

#### For Users

✅ Sign up with an email address

✅ No wallet extension needed

✅ No transaction popups during dApp usage

✅ Completely seamless blockchain interactions

✅ Self-custodial security

🔄 Passkeys

#### For Devs

✅ Quick and easy integration with your Dapp

✅ Session keys management

✅ Paymaster support

✅ Free account deployment

{% hint style="success" %}
Ready is sponsoring every account deployments. You don't need to worry about deploying your users' accounts anymore. &#x20;
{% endhint %}

\
↗️ [More about web wallet](https://www.ready.co/blog/exploring-web-wallets-architecture)

↗️ [Tutorial](https://www.ready.co/blog/implement-invisible-sdk)

{% hint style="info" %}
Need a tailored Invisible SDK implementation ? Reach out !
{% endhint %}


# Implementation

SDK implementation guide.

#### 1. Install the package

```sh
pnpm add @argent/invisible-sdk
```

#### 2. Import dependencies in your project

```tsx
import { ArgentWebWallet, SessionAccountInterface } from '@argent/invisible-sdk';
```

#### 3. Initialize the web wallet object with your app configuration:

```tsx
const argentWebWallet = ArgentWebWallet.init({
  environment: "sepolia", // "sepolia" | "mainnet" (Whitelisting required)
  appName: "My App", // Your app name
  sessionParams: {
    allowedMethods: [
      // List of contracts/methods allowed to be called by the session key
      {
        contract:
          "0x036133c88c1954413150db74c26243e2af77170a4032934b275708d84ec5452f", // contract address
        selector: "increment", //function selector
      }
    ],
    validityDays: 30 // optional - session validity (in days) - default: 30
  },
  paymasterParams: {
    apiKey: "avnu paymaster api key" 
  }
});
```

{% hint style="danger" %}
To use session keys on mainnet, you will need to whitelist your contract with us. Please reach out.
{% endhint %}

#### 4. Paymaster

Ready will automatically sponsor the deployment of accounts but you might want to sponsor additional transactions for a best-in-class UX. See [Gas abstraction](/tools/invisible-sdk-deprecated/gas-abstraction)

You can get your paymaster API key by contacting the AVNU team.\
The paymaster doc is [here](https://doc.avnu.fi/avnu-paymaster/overview).&#x20;

The `paymasterParams` is optional. If you pass it to the `init` function, every transactions will be executed through your paymaster configuration.&#x20;

#### 5. Request a connection

If the user is not connected, call the `requestConnection()` method to open the wallet and ask the user to approve the connection. At the same time, you can ask user for token approvals:

```tsx
const handleConnect = async () => {
      try {
         const response =  await argentWebWallet.requestConnection({
            callbackData: "custom_callback_data",
            approvalRequests: [ // array of tokens
               {
                  tokenAddress: "0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7",
                  amount: BigInt("100000000000000000").toString(),
                  // Your dapp contract
                  spender: "0x7e00d496e324876bbc8531f2d9a82bf154d1a04a50218ee74cdd372f75a551a",
               },
            ],
         });		 
         const { account: sessionAccount } = response
         // rest of your connection logic
      } catch (err) {
         console.error(err);
      }
   };

```

The wallet will redirect back to your app and the account will be available from the `connect()` method.

#### 6. Check connection status

You can check if the user is connected at any time using the `isConnected()` method:

```tsx
const isConnected = argentWebWallet.isConnected();
```

#### 7. Connect to the wallet

Call the `connect()` method when your app loads to check if the user is already connected. It is also used to fetch the `account` object. It is an extended `starknet.js` account object.

For instance, you could wrap this in a `useEffect` hook.

```tsx
 useEffect(() => {
      argentWebWallet
        .connect() // call connect as soon as the app is loaded
        .then((res) => {
								
           if (!res) {
              console.log("Not connected");
              return;
           }

           console.log("Connected to Argent Web Wallet", res);
           const { account, callbackData, approvalTransactionHash } = res; // extract useful objects

           if (account.getSessionStatus() !== "VALID") {
              console.log("Session is not valid");
              return;
           }

           setAccount(account);
           console.log("Callback data", callbackData); // -- custom_callback_string
           console.log("Approval transaction hash", approvalTransactionHash); // -- custom_callback_string
        })
        .catch((err) => {
           console.error("Failed to connect to Web Wallet", err);
        });
   }, []);
```

#### 8. Interact with Starknet using the account

You can interact with your contracts using starknet.js. For instance, you could do this:

```tsx
const call = {
   contractAddress: "contract_address",
   entrypoint: "do_something",
   calldata: ["0x1"],
};

const { resourceBounds: estimatedResourceBounds } = await account.estimateInvokeFee(call, {
   version: "0x3",
});

const resourceBounds = { // configure fees
   ...estimatedResourceBounds,
   l1_gas: {
      ...estimatedResourceBounds.l1_gas,
      max_amount: "0x28",
   },
};

const { transaction_hash } = await account.execute(call, {
   version: "0x3",
   resourceBounds,
});

// Wait for transaction to be mined
await account.waitForTransaction(transaction_hash);
```

#### 9. Check account session status

```tsx
const sessionStatus = account.getSessionStatus();
// "VALID" | "EXPIRED" | "INVALID_SCOPE" | "INVALID_SIGNATURE"
```

#### 10. Request approval

It is possible to ask to user to sign new approval transactions with `requestApprovals()`.

```typescript
async function handleApproval() {
    try {
      const res = await argentWebWallet.requestApprovals(
        [
          {
            tokenAddress: '0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7',
            amount: BigInt(1000000000000000000).toString(),
            spender: 'spender_address',
          }
        ],
      );
    } catch (error) {
      console.error('Approval failed:', error);
    }
  }
```

#### 11. Clear session

Calling `clearSession` removes the session object from local storage. It is mostly used for debugging. The session would still be valid on-chain. In terms of UX, this pretty much looks like a disconnect feature.&#x20;

We could imagine doing something like this:

```tsx
const handleClearSessionButton = async () => {
    await argentWebWallet.clearSession();
    setAccount(undefined);
  };
```

***

List of useful ressources:

* [npm package](https://www.npmjs.com/package/@argent/invisible-sdk)
* [Invisible SDK tutorial](https://www.argent.xyz/blog/implement-invisible-sdk)


# Other useful endpoints

The account object returned by the SDK is an extended `starknet.js`  account object.\
It contains functions that might be useful for you.

1. Outside execution

This function accepts a list of Call objects and returns the calldata/payload required to perform an `execute_from_outside` .

```typescript
await account.getOutsideExecutionPayload({calls: [calls]})
```

2. Sign Messages from outside

Takes a `typedData` object and a list of `Call` .

Returns&#x20;

```typescript
await account.signMessageFromOutside(typedData, [calls])
```

3. Deployment of account

By default, Ready subsidises the deployment of all the accounts. If the deployment fails on our side, it is possible to deploy the account for your users. \
You can get the deployment data either from the returned object of the `connect()` function of the SDK or from this endpoint:

```typescript
await account.getDeploymentPayload()
```

This will return a `DeployAccountContractPayload` which will allow you to deploy the account as explained here: [Deploy accounts on behalf of users](/aa-use-cases/deploy-accounts-on-behalf-of-users)


# Types and interfaces

List of important types.

```typescript
declare type InitParams = {
    appName: string;
    sessionParams: SessionParameters;
    paymasterParams?: PaymasterParameters;
    webwalletUrl?: string;
    environment?: keyof typeof ENVIRONMENTS;
    provider?: ProviderInterface;
};
```

```tsx
type SessionParameters = {
  allowedMethods: Array<{
    contract: string;
    selector: string;
  }>;
  validityDays?: number;
};
```

```typescript
type PaymasterParameters = {
    baseUrl?: string;
    apiKey?: string;
    tokenAddress?: Address;
};
```

```tsx
type ConnectResponse = {
    account: SessionAccount;
    user?: User;
    callbackData?: string;
    approvalTransactionHash?: string;
    approvalRequestsCalls?: Call[];
    deploymentPayload?: AccountDeploymentPayload;  
};
```

<pre class="language-tsx"><code class="lang-tsx">interface SessionAccountInterface extends AccountInterface {
  isDeployed(): Promise&#x3C;boolean>;
  getDeploymentPayload(): Promise&#x3C;DeployAccountContractPayload>;
  getOutsideExecutionPayload({ calls }: { calls: Call[] }): Promise&#x3C;Call>;
  getSessionStatus(): SessionStatus; // "VALID" | "EXPIRED" | "INVALID_SCOPE"
  signMessageFromOutside(typedData: TypedData, calls: Call[]): Promise&#x3C;ArraySignatureType>;
<strong>}
</strong></code></pre>

```typescript
declare interface ArgentWebWalletInterface {
    provider: ProviderInterface;
    sessionAccount?: SessionAccountInterface;
    isConnected(): Promise<boolean>;
    connect(): Promise<ConnectResponse | undefined>;
    requestConnection({ callbackData, approvalRequests, }: {
        callbackData?: string;
        approvalRequests?: ApprovalRequest[];
    }): Promise<ConnectResponse | undefined>;
    requestApprovals(approvalRequests: ApprovalRequest[]): Promise<string>;
    exportSignedSession(): Promise<SignedSession | undefined>;
    clearSession(): Promise<void>;
}
```


# Gas abstraction

How to best handle transactions sponsoring

Gas abstraction is crucial to provide users a seamless interaction with your application. Ideally, end-users should not have to care about paying gas or having gas tokens in their wallet.

#### Abstracting account deployment

By default, Ready will automatically deploy and pay for the deployment of accounts generated through the Invisible SDK.

However, you should have a fallback in case the Ready service is down and unable to pay for accounts deployment.

Calling the `requestConnection` method will return `ConnectResponse`

```
approvalTransactionHash?: string
approvalRequestsCalls?: Call[]
deploymentPayload?: any
```

* If `deploymentPayload` is `undefined`, that means that the wallet account is deployed
* If not, you'll need to deploy it using `deployAndExecuteWithPaymaster`&#x20;
* As a second fallback, you can notify the user in the UI that the account needs to be funded

#### Abstracting ERC-20 approvals

The Invisible SDK lets you bundle ERC-20 approvals together with the approval of a session. **These particular approvals are also sponsored by Ready.** \
\
In some cases, you might need users to sign additional ERC-20 approvals later in their journey (not part of the session approval). **These ERC-20 approvals are not sponsored by Ready.**

{% hint style="info" %}
Again, make sure to have a fallback in case our relayer service is unavailable.
{% endhint %}

#### Abstracting other types of transactions

We recommend that you totally abstract gas for users and hence sponsor all other types of transactions (onchain recordings, swaps, transfers etc...) using the AVNU paymaster.

You can also airdrop/sell your own token to users and let them pay gas fees with it.


# Session Keys

{% hint style="info" %} <mark style="color:orange;">Session keys require that you whitelist specific contracts and calls with Ready on mainnet.</mark> Please reach out to <ecosystem@ready.co>\
\
On Sepolia testnet, there is no whitelist
{% endhint %}

{% hint style="success" %}
To use session keys, make sure your Ready account has co-signers enabled (cfr. the bottom of this page)
{% endhint %}

## What are session keys ?

Solving UX issues in the crypto space have always been the main focus of Ready. With session keys, a user can perform several actions in a dapp without having to manually sign each transactions. In fact, the user authorizes the app the act on his behalf for a limited period of time and within certain constraints (only a few function calls for instance).

#### Use cases

**A great use case is** **gaming**. Session keys enhance the user experience of games by allowing uninterrupted gameplay. Users can authorize dapps to sign required transactions on their behalf, creating a more immersive gaming experience. To experience session keys firsthand, play Influence.

**We could also imagine new payment possibilities.** Dapps could implement new payment models such as recurring payments, dollar-cost-averaging, subscriptions and more.

**The DeFi space could also benefit from Session keys**. Apps such as DEXs can achieve the ease and smoothness of CEXs without their many drawbacks. Potential uses include:

* Automatic claim of DeFi rewards
* Automatic rebalancing of liquidity pools
* User safety protections in lending applications, such as the automatic closing of positions approaching liquidation

💡 You can see sessions in action by [playing Influence](https://game.influenceth.io/) with web wallet. Session keys are also powering the Ready card and the Ready Telegram wallet.

<figure><img src="/files/kgDwcEQVa6obJZA7xiq9" alt="" width="375"><figcaption><p>Session key on Influence</p></figcaption></figure>

#### Security considerations

Sessions maintain security through multiple features:

1. User-defined permissions specify exactly what actions are allowed
2. Time-bounded sessions automatically expire
3. On-chain revocation is always possible and so independently from the Ready backend
4. Ready's backend co-signs each transaction
5. Sessions become inactive if backend verification is unavailable

#### **Under the hood**

Initializing a session.

<figure><img src="/files/RS5TAFUu6fpYjxeEGodW" alt=""><figcaption></figcaption></figure>

Use a session

<figure><img src="/files/PlG4MlegE3wsTV3s0liI" alt=""><figcaption></figcaption></figure>

The Dapp generates a public/private key pair on its side. With this key pair, the dapp can cosign transactions with Ready Backend on behalf of the user. Of course, the dapp can only send transactions that the user specifically allowed. No surprises are possible!

***

\
To use session keys, users’ accounts must have enabled [Ready as a co-signer](/aa-use-cases/verifying-signatures-and-cosigners). This is the case for Ready Wallet Smart Accounts, Ready and Web Wallet.

The table below shows which accounts are compatible with session keys:

|         | Ready Wallet standard account | Ready Wallet smart account |         Web wallet        | Ready |
| ------- | :---------------------------: | :------------------------: | :-----------------------: | :---: |
| Testnet |               ✖️              |              ✅             | <p>✅ <br>(contact us)</p> |   ✖️  |
| Mainnet |               ✖️              |              ✅             |             ✅             |   ✅   |


# Implement session keys

**It is strongly advised to only implement session keys in a project using starknetkit.**

####

#### 1. Installation

```bash
npm install @argent/x-sessions
```

#### 2. Import packages

```tsx
import {
  SignSessionError,
  CreateSessionParams,
  createSession,
  buildSessionAccount,
  bytesToHexString
} from "@argent/x-sessions"
import { ec } from "starknet"
```

#### 3. Session Configuration

The dapp will need to create a `sessionKey` . This is simply a private/public key pair.

```tsx
const privateKey = ec.starkCurve.utils.randomPrivateKey();
const sessionKey: SessionKey = {
  privateKey, //string
  publicKey: ec.starkCurve.getStarkKey(privateKey), //string
};
```

Define your session parameters:

```tsx
const sessionParams: CreateSessionParams = {
  allowedMethods: [{
    "Contract Address": "0x00000...000",
    selector: "do_something"
  }],
  expiry: Math.floor((Date.now() + 1000 * 60 * 60 * 24) / 1000) as any, // 1 day
  sessionKey: sessionKey,
  metaData: {
    projectID: "your-dapp",
    txFees: [{
      tokenAddress: ETHTokenAddress,
      maxAmount: parseUnits("0.1", 18).value.toString()
    }]
  }
}

```

The `allowedMethods` params represents which contracts calls the user will authorize the dapp to send on his behalf.

`Expiry` is a security measure. After the expiry date, the session becomes invalid.

#### 3. Creating a Session

```tsx
// Compute the typed data to be signed
const sessionRequest = createSessionRequest({
  sessionParams,
  chainId
})

// wallet is a StarknetWindowObject. There are others ways to sign typed data.
// You could use the starknet-react hook useSignTypedData
const authorisationSignature = await wallet.request({
  type: "wallet_signTypedData",
  params: sessionRequest.sessionTypedData
})

// Build session request
const session = await createSession({
  sessionRequest, // SessionRequest
  address, // Account address
  chainId, // StarknetChainId
  authorisationSignature // Signature
})

// Create session account. This is the account that will be used to execute transactions. 
const sessionAccount = await buildSessionAccount({
  useCacheAuthorisation: false, // optional and defaulted to false, will be added in future developments
  session,
  sessionKey,
  provider: new RpcProvider({
    nodeUrl: "<https://starknet-sepolia.public.blastapi.io/rpc/v0_7>",
    chainId: constants.StarknetChainId.SN_SEPOLIA
  }),
  argentSessionServiceBaseUrl: ARGENT_SESSION_SERVICE_BASE_URL // Optional: defaulted to mainnet url. This is basically the backend api. 
})

```

#### 4. Executing Transactions

```tsx
try {
  const tx = await sessionAccount.execute({
    contractAddress: "0x...",
    selector: "transfer",
    calldata: ["0x..."]
  })
} catch (e) {
  console.error((e as SignSessionError).cause, e.message)
}

```

### Best Practices

1. Set appropriate expiry times based on your use case
2. Limit allowed methods to only necessary functions
3. Set reasonable token spending limits
4. Implement proper error handling for session operations
5. Consider implementing session refresh mechanisms for long-running applications


# Session keys with outside execution

[Outside Execution](/aa-use-cases/outside-execution) (Meta-transactions in the Ethereum world)  allows external contracts to execute transactions from outside an account contract, thereby opening up new use-cases such as sponsored transactions, deploying an account on behalf of a user, transaction scheduling (limit orders) etc.

The setup is exactly the same as the "basic" session keys.  We simply have a few more steps to do:

#### 1. Prepare the contract call

```tsx
// example for creating the calldata
const erc20Contract = new Contract(
  Erc20Abi as Abi,
  ETHTokenAddress,
  sessionAccount
)

const calldata = erc20Contract.populate("transfer", {
  recipient: address,
  amount: parseInputAmountToUint256(amount)
})

```

#### 2. Prepare Execution from outside

Here you have two possibilities. Depending on your setup, you can chose between a "higher level" function with `createOutsideExecutionCall`  which returns a signed call and a "lower level" with `createOutsideExecutionTypedData`  which returns the session acout signature and the typed data.&#x20;

#### a. Get the raw Execute from outside call

```typescript
import { createOutsideExecutionCall } from "@argent/x-sessions"

const efoExecutionCall = await createOutsideExecutionCall({
        session, // same object as before
        sessionKey, // same object as before
        calls: [calldata],
        argentSessionServiceUrl: ARGENT_SESSION_SERVICE_BASE_URL,
        network:
          CHAIN_ID === constants.NetworkName.SN_SEPOLIA ? "sepolia" : "mainnet",
      })
```

#### 2.b. Get the signed Execute from outside call

```typescript
import { createOutsideExecutionTypedData } from "@argent/x-sessions"

const { signature, outsideExecutionTypedData } =
  await createOutsideExecutionTypedData({
    session,
    sessionKey,
    calls: [calldata],
    argentSessionServiceUrl: ARGENT_SESSION_SERVICE_BASE_URL
    network // values "mainnet" | "sepolia", default to "mainnet"
  })
```


# Demo App

Demo dapp implementing session keys + execute from outside

{% embed url="<https://github.com/argentlabs/demo-dapp-starknet>" %}


# FAQ

Frequently asked questions about session keys

### Can session keys be used to sign a message on behalf of the user ?

For now, session keys only support transactions and meta-transactions

### Does the dapp need to manage nonces ?

Yes ! With session keys, the users interact directly with the dapp, meaning that the Ready wallets cannot take care of nonce management.

It is up to the dapp to keep track of nonces locally and increment them as you can't rely on a RPC call to `get_nonce` .


# Types

The types used by the Session Keys project.

```tsx
export type SessionKey = {
  publicKey: string
  privateKey: string
}

export interface AllowedMethod {
  "Contract Address": string
  selector: string
}

export type MetadataTxFee = {
  tokenAddress: string
  maxAmount: string
}

export type SessionMetadata = {
  projectID: string
  txFees: MetadataTxFee[]
  projectSignature?: Signature
}

export type BuildSessionAccountParams = {
  session: Session
  sessionKey: SessionKey
  provider: ProviderInterface
  useCacheAuthorisation?: boolean
  argentSessionServiceBaseUrl?: string
}

export type CreateSessionParams = {
  sessionKey: SessionKey
  allowedMethods: AllowedMethod[]
  expiry: bigint
  metaData: SessionMetadata
}

```

<br>


# Paymasters

Abstract gas

If you want to sponsor transactions for your users, we recommend using the [AVNU Starknet Paymaster](https://doc.avnu.fi/starknet-paymaster/introduction).

{% hint style="info" %}
The AVNU paymaster requires an [Outside Execution ](https://docs.argent.xyz/aa-use-cases/outside-execution)transaction, we will need to enable it in our products. Please reach out to us at <ecosystem@ready.co>
{% endhint %}


# Verifying signatures and cosigners

Providing multi-signature verification support for dApps

A good example can be found in this repo: [off-chain signatures](https://github.com/argentlabs/starknet-off-chain-signature)

## Signing

All the different Starknet libs give you the ability to sign messages from an account. Let's take [starknet.js](https://starknetjs.com/docs/guides/signature) or [starknet-react](https://www.starknet-react.com/docs/hooks/use-sign-typed-data) for example.&#x20;

Most of the time, you will try to make your users sign a [SNIP-12](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) typed data message.&#x20;

With starknet.js, you would do something like this:

```typescript
const account = new Account(provider, address, pk);
const typedData: TypedData = {
    // your typed data
}
const sig = await account.signMessage(typedData);
```

With starknet-react's hook, it will look like that:

```tsx
// declare hook
const { signTypedDataAsync } = useSignTypedData({
    // your typedData
})
// use hook
const doSomething = async () => {
    // rest of the code
    const signature = await signTypedDataAsync({
        // your typedData
    })
    // do something with sig
}
```

You'll notice that a signature is an array of several numbers. If the account is a standard account, then the sig length will be 5 and if it's a smart-account, it will be 9 (because you have both the account and the guardian signatures). The members of the sig array are explained [below](#verifying-multi-signatures).&#x20;

## Verifying signatures&#x20;

There are several ways of verifying a signature, on-chain or off-chain. Most of the time, you will use one of the on-chain methods. The starknet.js doc has an example of [off-chain verification](https://starknetjs.com/docs/guides/signature#verify-outside-of-starknet).&#x20;

#### On-chain verification method 1 - Calling the contract

Ready account signatures can be verified by calling the `isValidSignature` or `is_valid_signature` method of the account contract:

```javascript
const contractAccount = new Contract(abi, accountAddress, provider);
const msgHash = typedData.getMessageHash(data, accountAddress);
await contractAccount.isValidSignature(msgHash, [signature.r, signature.s])
```

<mark style="color:red;">**Be aware that most of Ready accounts will return more that one signature that should all be verified. See below.**</mark>

Signature r and s are the the 4th and 5th member of the sig array so `signature[3]` and `signature[4]` .&#x20;

#### On-chain verification method 2 - with Typed data

Most of the time, you will get your users to sign a typed data message following the SNIP-12 standard. There is an easy way to verify such a signature.&#x20;

```typescript
const provider = new RpcProvider({
  nodeUrl: rpcUrl
});
const isValidSig = await provider.verifyMessageInStarknet(
      typedData, // typed data json your user signed
      signature, // raw user sig, no need to filter r and s
      account // user address
    );
```

This method also accepts message hash instead of the full json.&#x20;

## Guardians and co-signers

A guardian is a trusted party, added by the user, that acts as a cosigner/co-validator for the user's account when carrying out typical wallet operations or for recovery purposes.

For most of Ready's products e.g Ready, Web Wallet, Smart Accounts in Ready Wallet etc, the guardian is usually Ready's backend.&#x20;

In the next section, let's take a look at how you can verify multi-signatures for accounts with an active guardian.

## Verifying multi-signatures

From a dApp's end, explicit support has to be provided for verifying multi-signatures, or account owners with guardians will be unable to sign transactions.

The signature is verified by calling the `isValidSignature` or  `is_valid_signature()` method. If the user has a guardian, the signature returned by the wallet will be longer and include more data. &#x20;

<figure><img src="/files/d9JAZgslKQY2LlgRpnmm" alt=""><figcaption></figcaption></figure>

`0:` number of signers (i.e. 2 in this example)

`1:` type of signer 1

`2:` pubkey 1

`3:` r1

`4:` s1

`5:` type of signer 2 (guardian)

`6:` pubkey 2 (guardian)

`7:` r2 (guardian)

`8:` s2 (guardian)

```javascript
const contractAccount = new Contract(abi, accountAddress, provider);
const msgHash = typedData.getMessageHash(data, accountAddress);
await contractAccount.isValidSignature(msgHash, [signature1.r, signature1.s, signature2.r, signature2.s])
```

{% hint style="info" %}
Different Starknet accounts or wallets might return different signatures. Only the signature verification with `isValidSignature` should be sent as a payload
{% endhint %}


# Identifying a smart account onchain

You can check onchain whether an account has a guardian by calling `get_guardian` on the account. If it returns a value other than 0, then the account has a guardian.

<figure><img src="/files/Fpg375nisdrCiwTZzsrr" alt=""><figcaption></figcaption></figure>


# Multicalls

Multicall is a key advantage of Account abstraction that enables you to aggregate multiple transactions into one.

Think about the Approve + Swap feature present on most DEXes. What if you could aggregate both calls into one? That would create a huge impact on dApps UX right? Welcome to Multicalls.

To understand how to aggregate calls, we need to first take a look at the `execute` method on the `account` object.

### The `execute` method

The `execute` method executes one or multiple calls using the account contract. If there is only one call, *transactions* will be an object that contains the parameters below. If there are multiple calls, *transactions* will be an array of *transactions* objects:

The *transactions* object structure:

* contractPayload.**contractAddress** - the address of the contract
* contractPayload.**entrypoint** - the entrypoint of the contract
* contractPayload.**calldata** - (defaults to \[]) the calldata
* contractPayload.**signature** - (defaults to \[]) the signature

*abi* - (optional) the abi of the contract for better displaying

The *transactionsDetail* object may include any of:

* transactionsDetail.**maxFee** - Max Fee that will be used to execute the call(s)
* transactionsDetail.**nonce** - Nonce for the transaction
* transactionsDetail.**version** - Version for the transaction (default is 1)

### Single vs Multicalls

In this section, we are going to take a look at how you perform single vs multiple calls using the  `execute` method.

Single call:

```javascript
const call = await account.execute(
  {
    contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',  // ETH contract address
    entrypoint: 'approve',
    calldata: starknet.stark.compileCalldata(
      {
        spender: "0x15e90f807a00a01df845460324fbcd33986f2df3cc9d981e9e8b5005b7f595e",
        amount: {
          type: 'struct',
          low: '1',   // 1 wei
          high: '0',
        }
      }
    ),
  },
  undefined,
  {
    nonce: '10',
  }
);
```

multicalls:

```javascript
const multiCall = await account.execute(
  [
    {
      contractAddress: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',  // ETH contract address
      entrypoint: 'approve',
      calldata: starknet.stark.compileCalldata(
        {
          spender: "0x15e90f807a00a01df845460324fbcd33986f2df3cc9d981e9e8b5005b7f595e",
          amount: {
            type: 'struct',
            low: '1',   // 1 wei
            high: '0',
          }
        }
      ),
    },
    {
      contractAddress: '0x15e90f807a00a01df845460324fbcd33986f2df3cc9d981e9e8b5005b7f595e',
      entrypoint: 'transfer_ether',
      calldata: ['1', '0'],  // 1 wei
    }
  ],
  undefined,
  {
    nonce: '10',
  }
);
```


# Outside Execution

Enabling meta-transactions on Starknet

{% hint style="info" %}
`Outside Execution` will work for everyone on Sepolia testnet but if you need to provide support for it in your dApp on **mainnet**, please reach out to us on Telegram: <https://t.me/+vn3OaTh-eehiMzg0>
{% endhint %}

Outside execution allows external contracts the ability to execute transactions from outside an account contract, thereby creating opportunities for meta-transactions, transaction scheduling (limit orders) etc.

While we wait for native paymasters on Starknet, there are certain use cases that requires giving external contracts access to execute transactions through an account contract. This is currently not possible due to the structure of the `execute` entrypoint in existing account contracts.&#x20;

In a bid to prevent re-entrancy attacks, the `execute` entrypoint prevents calls from external contracts, which means in order to enable meta-transactions we need to introduce a new entrypoint that allows calls from external contracts, `execute_from_outside`.

```rust
fn execute_from_outside(
    ref self: ContractState, outside_execution: OutsideExecution, signature: Array<felt252>
) -> Array<Span<felt252>>

```

Studying the interface above, we notice the `execute_from_outside` entrypoint requires two&#x20;

paramenters:&#x20;

* The `OutsideExecution` struct
* A valid signature

In the next section, let's take a look at how you can execute "outside transactions" as an application builder.

### Executing from Outside as a dApp developer

To get started executing outside transactions:

1. **Build your `OutsideExecution` Struct**

An `OutsideExecution` struct contains the details of the transaction to be executed from outside.&#x20;

```rust
struct OutsideExecution {
    caller: ContractAddress,
    nonce: felt252,
    execute_after: u64,
    execute_before: u64,  
    calls: Span<Call>
}
```

For an outside execution transaction to be valid, it needs to contain a `caller` (the address allowed to call the `execute_from_outside`), a `nonce` (a unique value to prevent signature reuse), an `execute_after` value (specifying the time after which the transaction can succeed), an `execute_before` value (specifying the time before which the transaction should succeed), and finally an array of calls to be executed.

\
2\. **Sign it using EIP-712 typed data hashing**

The signature signs over the EIP712 message encoding of `outside_execution`. Dapps are encouraged to  request signatures following the EIP712 standard for a clearer UX.

Refer to the standard [here](https://community.starknet.io/t/snip-off-chain-signatures-a-la-eip712/98029).

3. **Call the `execute_from_outside`  method on the account contract**

To do this we advise that you first verify that the account contract being interacted with has support for outside execution. To do this, simply call the `supports_interface` method on the account contract:

```rust
let acccount = IErc165Dispatcher { contract_address: acount_address };
let is_supported = account.supports_interface(ERC165_OUTSIDE_EXECUTION_INTERFACE_ID);
```

The interface ID to be queried for is: `0x68cfd18b92d1907b8ba3cc324900277f5a3622099431ea85dd8089255e4181`.

If it returns true, then you can go ahead to call the `execute_from_outside` method:

```rust
let acccount = IOutsideExecutionDispatcher { contract_address: acount_address };
```


# Deploy accounts on behalf of users

Ready allows dapps to deploy accounts on behalf of users, enhancing user experience by simplifying the onboarding process.

## Step 1: Install StarknetKit

You'll need [StarknetKit](broken://pages/JDEIa4GXFCVFIqOz9R9s)

* Version 2.2.7 or newer
* required in order to get the deployment data for an account
* can be installed with:

```javascript
pnpm add starknetkit
```

## Step 2: Retrieve the deployment data

Using this [SNIP](https://community.starknet.io/t/snip-deployment-interface-between-dapps-and-wallets/101923), your dapp can retrieve the deployment data required to deploy the user’s account.

When connecting with starknetkit, use the `wallet` object returned by `connect` .

If an account is already deployed, this will throw an exception (so it will need to be managed on client side)

```javascript
const { wallet, connectorData } = res; 
const deploymentData = await wallet.request({ 
type: "wallet_deploymentData",
 })
```

`deploymentData`  is an object of type:

```typescript
type DeployAccountContractPayload = {
    classHash: string;
    constructorCalldata?: RawArgs;
    addressSalt?: BigNumberish;
    contractAddress?: string;
};
```

## Step 3: Deploy on behalf of the user

Option 1: Now that you have the user's deployment data, you can deploy the account

Option 2: You can use AVNU’s paymaster feature to deploy the account at the same time as a paymaster transaction.  See [iteration flow](https://doc.avnu.fi/starknet-paymaster/guides-and-examples#interation-flow).

### Option 1 detailed workflow:&#x20;

1. Create a relayer in your code:

```typescript
const provider = new RpcProvider({
    nodeUrl: "https://free-rpc.nethermind.io/sepolia-juno/rpc/v0_7",
  });

  const relayer = new Account(
    provider,
    process.env.REACT_APP_ADDRESS,
    process.env.REACT_APP_PK
  );
```

2. Configure transaction params

```typescript
const fees = await account.estimateAccountDeployFee(deployPayload, {version: "0x03"});
const deployDetails = {
  maxFee: fees.suggestedMaxFee, 
  resourceBounds: fees.resourceBounds,
  version: "0x03",
};
```

3. Execute the deployment transaction using `account.deployContract`&#x20;

```typescript
const tx = await account.deployContract({
    unique: false,
    classHash: deployPayload.classHash,
    constructorCalldata: deployPayload.constructorCalldata,
    salt: deployPayload.addressSalt,
    }, deployDetails)  
```

That's it, the account contract should be deployed.&#x20;


# Dappland

Optimize your dapp visibility with Argent users

With 75% market share in the Starknet ecosystem, Ready's wallets are a great distribution channel for your products.

[Dappland](https://www.dappland.com/) is our curated repository of Starknet dapps. Having your dapp featured on Dappland grants several benefits:

1. Your dapp is showcased on one of the most popular ecosystem portals
2. Easy dapp-discovery directly from the Argent mobile in-app browser
3. Prerequisite to receive the "Known Dapp" checkmark in our fraud monitor
4. Send push notifications to users *(soon)*

{% hint style="info" %}
[Add your dapp to Dappland](https://github.com/argentlabs/dappland#-add-your-dapp-to-dappland)
{% endhint %}


# Known dapps

We attribute green Known Dapp checkmarks to established dapps in the ecosystem which have earned a solid reputation and user base. Green checkmarks give confidence to our users that the dapp is known to us.&#x20;

If you think we should attribute your dapp the checkmark, please reach-out.

<figure><img src="/files/3Ujb2Q7s0dhyLodFYFVV" alt="" width="359"><figcaption><p>Green Known Dapp checkmark on <a href="https://www.vesu.xyz/">www.vesu.xyz</a></p></figcaption></figure>


# Transaction reviews

In order to protect users, we run transactions simulations against some security checks. Find below some transaction reviews and how you can improve them for your users.

## Risky approval of your funds

This transaction review means that some of the assets that are approved are not spent in the same transaction.&#x20;

On Starknet, [multiple calls can be bundled in a single transaction](https://docs.argent.xyz/aa-use-cases/multicalls) which means that open approvals are often avoidable. Make sure to spend 100% of the approved amounts in the same transaction.

If you have a specific use case that requires open approvals, please reach-out to us so we can figure out how handle the warning.

<figure><img src="/files/8jbP1KeGsogLTw1a6SGf" alt=""><figcaption></figcaption></figure>


# Brand your token

Have a token on Starknet ? You can customize it [here](https://static.argent.net/brand-your-token/index.html).\
\
Note that Ready follows internal guidelines to ensure uniformity of tokens in the wallets. The final design of your token might differ from the one you submitted


# Spoks

Starknet Proof of Kudos

Spok stands for Starknet Proof-of-Kudos. It’s like a POAP, but for Starknet.

Starknet users can claim Spoks by completing quests and attending virtual or physical events.

<figure><img src="/files/ctyAmEL9qvCn3DFNYgoG" alt="" width="188"><figcaption><p>Starknet Summit Spok</p></figcaption></figure>

{% hint style="info" %}
Want to run your own Spok campaign ? Reach out to us and we will onboard you to our self-serve tool.
{% endhint %}

## FAQ

**Is Spok wallet agnostic?**

Yes ! Spoks can be claimed using any type of Starknet Wallet (Ready Wallet, Ready, web wallet, Braavos).

Our mobile app Ready has a built-in claiming flow for the best user experience.

**Is Spok free ?**

Yes !


# Perkz

Real benefits for your onchain activity

{% hint style="info" %}
Perkz is not yet self-served. If you wish to run a campaign, please reach out to us
{% endhint %}

## What is Perkz ? 🍭

[Perkz](https://perkz.xyz/) is a Starknet application that allows users to claim perks as a reward for onchain actions.

Examples of onchain actions that can be rewarded with perkz:

* 🤑 Own more than 100 $STRK before 01/09/2024
* 🚁 Have claimed the Starknet airdrop
* 🚀 Own a blue-chip Starknet NFT
* 💍 Own a StarkCity Spok

## Perkz at physical events 🌏

Perkz is poweful because it bridges onchain activity and real-life interactions. Users can be rewarded for their onchain activity at physical events. Swag, drinks and perks are not distributed blindly anymore but can be awarded to your most loyal users.

Examples of perks at real-life events

* 🕶 Access to a VIP evening
* 👕 Claim swag
* 🍲 Claim drinks and food
* ➗ Discount on exclusive items
* ….

## Perkz & Spoks 🧠

Perkz can be combined with Spoks to offer an end-to-end claiming experience at a physical event:

1. Users perform actions e.g. hacker house participation, attend meetups, pass by a booth at Devcon, etc..
2. Each action awards the user a Spok
3. Spoks unlock perks for the user&#x20;


# Argent Vault on Ethereum L1

How to make sure your dapp works seamlessly with Argent!

## What is Argent Vault?

Ready (formerly Argent) is the first smart wallet for Ethereum. It’s the only non-custodial mobile wallet that combines easy access to dapps and security features such as recovery without seed phrases, trusted contacts and multisig. These features are made possible by Ready’s smart contract architecture.

Ready website: <https://www.ready.co/>

Smart Contracts Repository: <https://github.com/argentlabs/argent-contracts/>

## What is WalletConnect?

[WalletConnect](https://walletconnect.org) is an open source protocol for connecting decentralized applications ("dapps") to mobile wallets, via QR code scanning or deep linking. A user can interact securely with any dapp from their mobile phone, making WalletConnect-enabled wallets a safer choice compared to desktop or browser extension wallets.

## WalletConnect and Argent

As a mobile wallet, Argent fully supports the WalletConnect protocol. Since Argent is a smart contract based wallet, you need to pay attention to some specific features.

### Checking the correct signature

Externally Owned Accounts (EOA) can sign messages with their associated private keys, however, smart contracts cannot. [EIP-1271](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md) outlines a standard way for contracts to verify if a provided signature is valid when an account is a contract.&#x20;

The Argent wallet implements the`isValidSignature()` method, as per EIP-1271. A dapp that wants to verify the signature of an Argent user should therefore call `isValidSignature()` on the Argent wallet instead of  `ecrecover()` (as would be used to verify signatures from EOA accounts).

```javascript
contract ERC1271 {

  // bytes4(keccak256("isValidSignature(bytes32,bytes)")
  bytes4 constant internal MAGICVALUE = 0x1626ba7e;

  /**
   * @dev Should return whether the signature provided is valid for the provided data
   * @param _hash EIP-191 compliant hash of the message
   * @param _signature Signature byte array associated with _data
   *
   * MUST return the bytes4 magic value 0x1626ba7e when function passes.
   * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
   * MUST allow external calls
   */ 
  function isValidSignature(
    bytes32 _hash, 
    bytes memory _signature
  )
    public
    view 
    returns (bytes4 magicValue);
}
```

The parameter `_hash` should be [EIP-191](https://eips.ethereum.org/EIPS/eip-191) compliant. See full example here in JavaScript (using [ethers.js](https://docs.ethers.io/v5/) library):

```javascript
const argentABI = [
  'function isValidSignature(bytes32 _message, bytes _signature) public view returns (bool)'
];

const walletAddress = "0x...";
const message = "Lorem ipsum dolor sit amet";

const argentWallet = new ethers.Contract(walletAddress, argentABI, provider);
const hashMessage = ethers.utils.hashMessage(message);

try {
  const returnValue = await argentWallet.isValidSignature(hashMessage, signature)
} catch (error) {
  // signature is not valid
}  

```

### Wallet detection

We have developed and deployed a simple contract to detect if a given address corresponds to an Argent wallet. The contract exposes a single `isArgentWallet(address)` method that returns true if the code deployed at the input address matches a deployed version of the Argent wallet.

```javascript
contract ArgentWalletDetector {

  /**
   * @notice Checks if an address is an Argent wallet
   * @param _wallet The target wallet
   */
  function isArgentWallet(address _wallet) external view returns (bool);
  
}
```

The detector contract is deployed on Ropsten testnet and Mainnet:

```
Ropsten: 0xF230cF8980BaDA094720C01308319eF192F0F311
Mainnet: 0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8
```

### Multicall

Argent wallets support the ability to batch transactions into a single transaction, for example an ERC20 approval followed by a contract call.

```javascript
const argentABI = [
  "function isValidSignature(bytes32 _message, bytes _signature) public view returns (bool)",
  "function wc_multiCall((address to, uint256 value, bytes data)[] _transactions)",
];

const walletAddress = "0x...";

const argentWallet = new ethers.Contract(walletAddress, argentABI, provider);

const result = await argentWallet.wc_multiCall([
  // approve USDC
  {
    to: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
    value: 0,
    data: "0x095ea7b3000000000000000000000000def1c0ded9bec7f1a1670819833240f027b25eff0000000000000000000000000000000000000000fffffffffff096fb4da20000",
  },
  // call contract
  {
    to: "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
    value: 0,
    data: "0x........",
  },
]);
```

The best practice is to check if the wallet is an Argent wallet using the wallet detector contract and then batch the transactions:

```javascript
const walletDetectorAddress = "0xeca4B0bDBf7c55E9b7925919d03CbF8Dc82537E8";
const walletDetectorABI = [
   "function isArgentWallet(address _wallet) external view returns (bool)"
];

const walletDetector = new ethers.Contract(walletDetectorAddress, walletDetectorABI, provider);
const isArgent = await walletDetector.isArgentWallet(address);

if (isArgent) {
   // do a multicall
} else {
   // do single calls
}
```

### Meta transactions and relayers

Argent wallet uses the concept of meta transactions. These are a particular type of transaction which are signed by one or more key pairs (in our case the wallet's owner and potentially their guardians) but are submitted to the Ethereum network by a relayer. The relayer pays the gas fee (in ETH) and the wallet will refund the relayer (in ETH or ERC20 tokens) up to an amount signed by the wallet's owner.

From the dapp's perspective, this is managed by the Argent mobile application. The dapp will submit a regular `{ to, value, data }` transaction to the web3 provider. This transaction will be transmitted to the Argent mobile application through WalletConnect. The mobile wallet will transform the data into a meta transaction:

* `to` will be the Argent `RelayerManager` contract address
* `data` will be the encoded data of the call to the `execute()` method with the relevant parameters

The dapp will receive the transaction hash in order to monitor the status of the transaction and events will be emitted as usual.

Our relayer has the ability to replay a transaction with a higher gas price due to fluctuating network conditions. The transaction hash is modified and the dapp will not be aware of the new transaction hash.

One solution could be for the dapp to observe a specific event being emitted instead of transaction status. We are working on defining a standard for a dapp to be notified when a transaction is replaced and the transaction hash changes (contact us if you are interested in this).

### Login UX best practice

To improve the login experience for Argent users, we recommend showing an Argent branded login button at the top level. This ensures people less familiar with WalletConnect can log in to your app. When clicking on the Argent login, you then present the WalletConnect QR code.  &#x20;

You can find an example of this implementation on <https://app.flexa.network/connect>

![](/files/-MO5yn7qsxkvdws5Jz70)

## FAQ

### Can I use the ERC20 permit function?

It depends on how the ERC20 smart contract implements the `permit()` method. If you look below (source [Etherscan](https://etherscan.io/address/0x6b175474e89094c44da98b954eedeac495271d0f#code)) at the Maker DAI implementation, you will notice at line 24 the use of `ecrecover()` and not EIP-1271 to verify the signature. Here, the call will fail with Argent wallets.

```javascript
function permit(
   address holder, 
   address spender, 
   uint256 nonce, 
   uint256 expiry,
   bool allowed, 
   uint8 v, 
   bytes32 r, 
   bytes32 s
) external {
    bytes32 digest =
        keccak256(abi.encodePacked(
            "\x19\x01",
            DOMAIN_SEPARATOR,
            keccak256(abi.encode(PERMIT_TYPEHASH,
                                 holder,
                                 spender,
                                 nonce,
                                 expiry,
                                 allowed))
    ));

    require(holder != address(0), "Dai/invalid-address-0");
    require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
    require(expiry == 0 || now <= expiry, "Dai/permit-expired");
    require(nonce == nonces[holder]++, "Dai/invalid-nonce");
    uint wad = allowed ? uint(-1) : 0;
    allowance[holder][spender] = wad;
    emit Approval(holder, spender, wad);
}
```

### I'm asking for ERC20 approval of an amount of$$10^{53}$$but it doesn't seem to work

Argent may override the "infinite value" and ask a user to input a smaller amount due to the additional security risk of allowing large persistent approvals. When checking the allowance in your dapp you need to check for the exact amount the user wants to spend.&#x20;

### Can I use 3rd party relayers with Argent?

Yes, but the relayer needs to implement a call to the `execute()` method of our `RelayerManager` smart contract. You will have to get the wallet owner signing the correct payload which is not straightforward. Please contact us if you're interested in this topic.&#x20;

### Do you estimate gas?

Yes, we use `eth_estimateGas` before sending any transaction.

### Do you support WalletConnect mobile deeplinks?

Yes, WalletConnect will work on mobile browsers (or native mobile apps) and will deep link to the Argent wallet.

### How can I test the integration?

You can test Argent on Ropsten on both iOS and Android. Contact <dapps@argent.xyz> to receive a test build.


# Contracts and audits

Security first

Ready's smart contracts are open-source and audited. Please refer to the links below for more information.

* [Contracts](https://github.com/argentlabs/argent-contracts-starknet/tree/main?tab=readme-ov-file)
* [Class hashes](https://github.com/argentlabs/argent-contracts-starknet/tree/main/deployments)
* [Audits](https://github.com/argentlabs/argent-contracts-starknet/tree/main/audit)


# Get in touch

Let us help

You can  through multiple channels:

💬 [Official Ready Devs telegram](https://t.me/c/1650490560/1)

📌[ X Ready Engineering account](https://x.com/argentdeveloper)


