# OVERVIEW

{% content-ref url="/pages/GHLkf4vXFSbH4OLp2bpI" %}
[What is Broearn Wallet?](/overview/what-is-broearn-wallet)
{% endcontent-ref %}

{% content-ref url="/pages/qBuBLlzi31zYB9AtHqNS" %}
[Security](/overview/security)
{% endcontent-ref %}

{% content-ref url="/pages/jWXifaeCLZQrcKAc4bXd" %}
[Available Networks](/overview/available-networks)
{% endcontent-ref %}


# What is Broearn Wallet?

Broearn Wallet is a crypto wallet that can be used to manage digital assets and access decentralized applications on PUT, Solana, EVM series.

Broearn Wallet is  currently available as：

* [An IOS app](https://apps.apple.com/ae/app/broearn-browser-for-web3-0/id6444156587?platform=iphone)
* [An Android app](https://play.google.com/store/apps/details?id=com.broearn.browser)
* [A browser extension](https://chrome.google.com/webstore/detail/ppohmjakiedocgjiigmabnhcnemnphcn)

At its core, Broearn Wallet works by creating and managing private keys on behalf of its users. These keys can then be used within the Broearn Wallet to store funds and sign transactions.&#x20;

Developers can interact with Broearn Wallet via both web applications as well as iOS and Android applications.

To interact with web applications, the Broearn wallet mobile in-app browser injects a bw object into the javascript context of every site the user visits. A given web app may then interact with Broearn Wallet, and ask for the user's permission to perform transactions, through this injected provider.

It's also possible to interact with the Broearn mobile app through universal links and deeplinks. With deeplinks, mobile apps can prompt their users to connect, sign, and send with Broearn Wallet directly. Once complete, Broearn Wallet will redirect users back to their referring applications.<br>

This documentation is intended for developers who are building applications with Broearn Wallet.&#x20;


# Security

Private keys are the most valuable possessions in the blockchain space. If the user loses their private keys or they are compromised, they will never recover their currencies.

To provide our extremely secure services:&#x20;

**No one, except the user themself, has full control**&#x20;

Only the user can initiate the signing process. Other parties, including developers, can never access users' funds.


# Available Networks

PUT、Bitcoin、Solana and all EVM-compatible chains are supported now; more are coming.

The `mainnet` and `testnet` are both available for all the following chains.

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2Fv6VxIPFAS5tDqK288eZK%2Flogo.svg?alt=media&amp;token=7986c3d4-9f0a-48cb-97a5-65c03ea58c54" alt="" data-size="line">[Parallel Universe Chain](/overview/available-networks/parallel-universe-chain)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FyUUaKUpyET2Y8lLYSTIW%2F63f05b33af084f5c.png?alt=media&amp;token=9a9dc33e-a968-40b2-9be6-c5b590e2056c" alt="" data-size="line">[Bitcoin](/overview/available-networks/bitcoin)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FPSBA8oJVOCKugnQz6Rox%2Fbd521e7ca5bf6699.png?alt=media&amp;token=9678cc4e-d610-4798-abc5-0e188cf479aa" alt="" data-size="line">[Ethereum](/overview/available-networks/ethereum)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FjjAeW2Y9va5C9383w0yn%2Fimage.png?alt=media&amp;token=19187708-ed15-4dc3-89dd-13e5d049ce7e" alt="" data-size="line">[BNB Chain](/overview/available-networks/bnb-chain)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FWQg7RHjoKB0WkNjRaiyC%2Fbeb66e8ccc7a621f.png?alt=media&amp;token=3ad89edc-c25e-4d64-82a5-71c28da671ec" alt="" data-size="line">[Tron](/overview/available-networks/tron)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2F0bc9MaQxqjiZaobfi00Z%2F14704055a393eb39.png?alt=media&amp;token=2f9ae9e4-566e-49f5-9603-6ab0b48d57ef" alt="" data-size="line">[Solana](/overview/available-networks/solana)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FHFVAQufElVhm9W5vKYaR%2Fd0d3932b5d84285f.png?alt=media&amp;token=2ebf4291-b074-486e-b0b5-ec3e3c8ef154" alt="" data-size="line">[OKX Chain](/overview/available-networks/okx-chain)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FWMHl2D8pRwlEzCQR0jXT%2F37cbe140816a5589.webp?alt=media&amp;token=5ec4d2f1-abd5-415a-95d9-4c857f33f4e1" alt="" data-size="line">[Optimism](/overview/available-networks/optimism)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FNzjFxGLHa5WrxJw4Kn7P%2Fbbb49d683c56c9a4.png?alt=media&amp;token=19652186-0604-4271-b533-d29e2dba2f86" alt="" data-size="line">[Fantom](/overview/available-networks/fantom)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FV2d56DkrM4q9Qa8CObsz%2Ffcbb2b10fa287892.png?alt=media&amp;token=aab3d92e-b36f-4bc2-8e79-69f05acf6744" alt="" data-size="line">[Ethereum Classic](/overview/available-networks/ethereum-classic)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FIVyynjwhzWj2ZiCN1Wne%2Fc57507f9067872dd.png?alt=media&amp;token=3a27f3d4-5f25-4ec8-ba9d-fa221a32cc2c" alt="" data-size="line">[Polygon](/overview/available-networks/polygon)

<img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2Fn1eiYiUykwyOYAhM77LX%2F836f0b46f07f03da.png?alt=media&amp;token=0b93668a-f6d9-425a-a37d-c59c4b2d1795" alt="" data-size="line">[Avalanche](/overview/available-networks/avalanche)


# Parallel Universe Chain

## Introduction

The [Parallel Universe chain](https://www.put.com) aims to boost the evolution from traditional Web2.0 to Web3.0. All participants can enjoy a faster, cheaper, and more secure Web3.0 decentralized transaction experience. The parallel universe network enables us to build these applications and services more conveniently and easily.

### **Chain Information**

{% embed url="<https://docs.put.com/learn/introduction-to-put>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) |
| ------------- | ------------------ |
| -1            | PUT                |
| -2            | PUT                |


# Bitcoin

[Bitcoin](https://bitcoin.org/) is a decentralized cryptocurrency originally described in a 2008 whitepaper by a person, or group of people, using the alias Satoshi Nakamoto. It was launched soon after, in January 2009.

Bitcoin is a peer-to-peer online currency, meaning that all transactions happen directly between equal, independent network participants, without the need for any intermediary to permit or facilitate them. Bitcoin was created, according to Nakamoto’s own words, to allow “online payments to be sent directly from one party to another without going through a financial institution.”

Some concepts for a similar type of a decentralized electronic currency precede BTC, but Bitcoin holds the distinction of being the first-ever cryptocurrency to come into actual use.

### **Chain Information**

{% embed url="<https://bitcoin.org/en/getting-started>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) |
| ------------- | ------------------ |
| -3            | Bitcoin Mainnet    |
| -4            | Bitcoin Testnet    |


# Ethereum

## Introduction

[**Ethereum**](https://ethereum.org) is a decentralized, open-source blockchain platform with smart contract functionality. It enables developers to build and deploy decentralized applications (dApps) and supports a vast ecosystem of projects in the fields of DeFi, NFTs, and beyond. Ethereum's flexibility and robust community have made it a popular choice for developers entering the Web3 space.

### **Chain Information**

{% embed url="<https://ethereum.org/en/developers/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains              |
| ------------- | ------------------ | ----------------------- |
| 1             | ethereum           | Ethereum Mainnet        |
| 5             | ethereum           | Ethereum Goerli Testnet |


# BNB Chain

## Introduction

[**BNB Chain**](https://www.bnbchain.org/), formerly known as Binance Smart Chain (BSC), is a fast and efficient decentralized blockchain platform that offers EVM-compatible smart contract functionality. It is designed to provide a user-friendly and cost-effective environment for developers to build and deploy decentralized applications (dApps) and supports a rapidly growing ecosystem of DeFi, NFT, and gaming projects.

### **Chain Information**

{% embed url="<https://docs.bnbchain.org/docs/overview>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains        |
| ------------- | ------------------ | ----------------- |
| 56            | bsc                | BNB Chain Mainnet |
| 97            | bsc                | BNB Chain Testnet |


# Tron

## Introduction

[**TRON**](https://tron.network/) is an open source public blockchain platform that supports smart contracts. TRON is compatible with Ethereum, which means that you can migrate smart contracts on Ethereum to TRON directly or with minor modifications. TRON relies on a unique consensus mechanism to realize the high TPS of the TRON network that is far beyond Ethereum, bringing developers a good experience of a faster transaction.

### **Chain Information**

{% embed url="<https://developers.tron.network/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains   |
| ------------- | ------------------ | ------------ |
| 728126428     | tron               | Tron Mainnet |
| 2494104990    | tron               | Tron Shasta  |
| 3448148188    | tron               | Tron Nile    |


# Solana

## Introduction

[**Solana**](https://solana.com/) is a high-performance blockchain platform designed to support scalable and secure decentralized applications. It achieves high throughput and low transaction costs by leveraging its unique Proof of History consensus algorithm and parallel processing architecture. With its focus on performance and scalability, Solana has attracted a growing ecosystem of developers and users.

### **Chain Information**

{% embed url="<https://docs.solana.com/>" %}
Official Documentation
{% endembed %}

| chainId (int) | Solana Network |
| ------------- | -------------- |
| -8            | Mainnet        |
| -9            | Testnet        |
| -10           | Devnet         |


# OKX Chain

## Introduction

A Super Scalable, Compatible L1 Blockchain [**OKT Chain**](https://www.okx.com/oktc) (OKTC) is an EVM-compatible L1 built on Cosmos with a focus on true interoperability (IBC) and maximized performance. At high scalability, developers can build and scale with low gas fees. The OKT Chain ecosystem and infrastructure, including the all-in-one multi-chain Web3 interface, enables a seamless experience for both developers and users.

### **Chain Information**

{% embed url="<https://www.okx.com/oktc/docs/dev/quick-start/overview>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains  |
| ------------- | ------------------ | ----------- |
| 66            | okc                | OKC Mainnet |
| 65            | okc                | OKC Testnet |


# Optimism

## Introduction

[**Optimism**](https://www.optimism.io/) is a Layer 2 scaling solution for Ethereum that employs Optimistic Rollups to significantly improve transaction throughput and reduce gas fees. It provides a seamless experience for developers and users alike, offering a highly-scalable environment for building and deploying Ethereum-based decentralized applications (dApps). Optimism aims to address the scalability challenges of Ethereum while maintaining compatibility with existing Ethereum development tools and resources.

### **Chain Information**

{% embed url="<https://community.optimism.io/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains              |
| ------------- | ------------------ | ----------------------- |
| 10            | optimism           | Optimism Mainnet        |
| 420           | optimism           | Optimism Testnet Goerli |


# Fantom

## Introduction

[**Fantom**](https://fantom.foundation/) is a high-performance, scalable, and secure smart-contract platform designed to overcome the limitations of previous generation blockchain platforms. It is designed to support decentralized applications (dApps) and facilitate instant transactions, making it ideal for DeFi and other applications.

### **Chain Information**

{% embed url="<https://docs.fantom.foundation/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains            |
| ------------- | ------------------ | --------------------- |
| 250           | fantom             | Fantom Mainnet(Opera) |
| 4002          | fantom             | Fantom Testnet        |


# Ethereum Classic

[Ethereum Classic](https://ethereumclassic.org/) (ETC) is a hard fork of Ethereum (ETH) that launched in July 2016. Its main function is as a smart contract network, with the ability to host and support decentralized applications (DApps). Its native token is ETC.

### **Chain Information**

{% embed url="<https://ethereumclassic.org/development>" %}
Official Documentation
{% endembed %}

<table><thead><tr><th width="257">chainId (int)</th><th width="181.33333333333331">chainName (string)</th><th>EVM Chains</th></tr></thead><tbody><tr><td>61</td><td>ethereum classic</td><td>Ethereum Classic Mainnet</td></tr><tr><td>6</td><td>ethereum classic</td><td>ETC Kotti Testnet</td></tr></tbody></table>


# Polygon

## Introduction

[**Polygon**](https://polygon.technology/), formerly known as Matic Network, is a Layer 2 scaling solution for Ethereum that offers a highly-scalable and cost-efficient environment for building and deploying decentralized applications (dApps). It aims to provide a seamless experience for users and developers by leveraging a multi-chain approach with Ethereum-compatible sidechains.

### **Chain Information**

{% embed url="<https://wiki.polygon.technology/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains               |
| ------------- | ------------------ | ------------------------ |
| 137           | polygon            | Polygon Mainnet          |
| 80001         | polygon            | Polygon Testnet (Mumbai) |


# Avalanche

## Introduction

[**Avalanche**](https://www.avax.network/) is an open-source platform for launching decentralized applications (dApps) and enterprise-grade blockchain deployments in one interoperable, highly-scalable ecosystem. It aims to deliver a seamless experience for users and developers by enabling the creation of custom, private, and public blockchains, as well as digital asset trading.

### **Chain Information**

{% embed url="<https://docs.avax.network/>" %}
Official Documentation
{% endembed %}

| chainId (int) | chainName (string) | EVM Chains                 |
| ------------- | ------------------ | -------------------------- |
| 43114         | avalanche          | Avalanche Mainnet(C-Chain) |
| 43113         | avalanche          | Avalanche Testnet(Fuji)    |


# Extension & in Broearn app


# Events


# Disconnect

```
// Some code
window.bw.on('disconnect', ({ address: string }) => {
    console.log('lost connection to the rpc')
})

window.bw.put.on('disconnect', ({ address: string }) => {
    console.log('lost connection to the rpc')
})
```


# Accounts Changed

```
// Some code
window.bw.on('accountsChanged', (newAccounts: string[]) => {
    console.log(newAccounts);
})

window.bw.put.on('accountsChanged', (newAccounts: string[]) => {
    console.log(newAccounts);
})
```


# Detecting the Provider

To detect if a user has already installed Broearn Wallet, a web application should check for the existence of a `bw` object. Browser extension and mobile in-app browser will both inject a `bw` object into the [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) of any web application the user visits.

If a `bw` object exists, PUT apps can interact with PUT via the API found at `window.bw.put`

If Broearn Wallet is not installed, we recommend you redirect your users to our [website](https://www.broearn.com). Altogether, this may look like the following.

```
// Some code
const getProvider = () => {
  if ('bw' in window) {
    const provider = window.bw.put;

    return provider;
  }

  window.open('https://www.broearn.com', '_blank');
};
```


# Establishing a Connection

Once an application has [detected the provider](/put/detecting-the-provider), it can then request to connect to Broearn Wallet. This connection request will prompt users for permission to share their public key, indicating that they are willing to interact further. Users must approve a connection request before the app can make additional requests such as [signing a message](/provider-methods/signmessage) or [sending a transaction](/provider-methods/signandsendtransaction).

Once permission is established for the first time, the web application's domain will be whitelisted for future connection requests. After a connection is established, it is possible to terminate the connection from both the application and the user side.

## Connecting

The **recommended** and **easiest** way to connect to Broearn Wallet is by calling `window.bw.put.connect()`. However, the provider also exposes a `request` JSON RPC interface.

{% tabs %}
{% tab title="connect()" %}

```javascript
const provider = getProvider(); // see "Detecting the Provider"
try {
    const resp = await provider.connect();
    console.log(resp.address);
    // 26qv4GCcx98RihuK3c4T6ozB3J7L6VwCuFVc7Ta2A3Uo 
} catch (err) {
    // { code: 4001, message: 'User rejected the request.' }
}
```

{% endtab %}

{% tab title="request()" %}

```javascript
const provider = getProvider(); // see "Detecting the Provider"
try {
    const resp = await provider.request({ method: "connect" });
    console.log(resp.address);
    // 26qv4GCcx98RihuK3c4T6ozB3J7L6VwCuFVc7Ta2A3Uo 
} catch (err) {
    // { code: 4001, message: 'User rejected the request.' }
}
```

{% endtab %}
{% endtabs %}

The `connect()` call will return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that resolves when the user accepts the connection request, and reject (throw when awaited) when the user declines the request or closes the pop-up. See [Errors](/errors) for a breakdown of error messages Broearn Wallet may emit.

## Disconnecting

Disconnecting mirrors the same process as connecting. However, it is also possible for the wallet to initiate disconnection, rather than the application itself.

{% tabs %}
{% tab title="disconnect()" %}

```javascript
provider.disconnect({ session: '' });
```

{% endtab %}

{% tab title="request()" %}

```javascript
provider.request({ method: "disconnect", params: { session: "" } });
```

{% endtab %}
{% endtabs %}

## Changing Accounts

Broearn Wallet allows users to seamlessly manage multiple accounts from within a single extension or mobile app. Whenever a user switches accounts, Broearn Wallet will emit an `accountChanged` event.

If a user changes accounts while already connected to an application, and the new account has already whitelisted that application, then the user will stay connected and Broearn Wallet will pass the address of the new account:

```javascript
provider.on('accountChanged', (addresses) => {
   console.log(`Switched to account ${addresses}`);
});
```


# PROVIDER METHODS


# Connect

In order to start interacting with Broearn Wallet, an app must first establish a connection. This connection request will prompt users for permission to share their public keys, indicating that they are willing to interact further.

Once a user connects to Broearn Wallet, Broearn Wallet will return the promise type param that should be used on all subsequent methods.

### Query Function

```javascript
// New Connect
window.bw.put.connect()
// Check if the Dapp is linked to a wallet
window.bw.put.connect({
    session: '...'
}}
```

### Query String Parameters

Check if the Dapp is linked to a wallet

```javascript
// Some code
{
    session: string
}
```

### Returns

#### Approve

* `data`: An JSON object.

  ```json
  // content of decrypted `data`-parameter
  {
    // base58 encoding of user public key
    "address": "BSFtCudCd4pR4LSFqWPjbtXPKSNVbGkc35gRNdnqjMCU",

    // session token for subsequent signatures and messages
    // dapps should send this with any other deeplinks after connect
    "session": "..."
  }
  ```

  * address: The public key of the user, represented as a base58-encoded string.
  * `session`: A string type. This should be treated as opaque by the connecting app, as it only needs to be passed alongside other parameters. Sessions do not expire.

```
// Sample code
{
    "data": {
        "address": "",
        "session": ""
    }
}
```

#### Reject

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```json
{
    "errorCode": "",
    "errorMessage": ""
}
```


# Disconnect

After an initial [Connect](/provider-methods/connect) event has taken place, an app may disconnect from Broearn Wallet at anytime. Once disconnected, Broearn Wallet will reject all signature requests until another connection is established.

### Query Function

```javascript
window.bw.put.disconnect({ session: "" })
```

### Query String Parameters

```json
// Query code
{
    session: '...'
}
```

### Returns

#### :white\_check\_mark: Approve

```json
{
  "data": "success"
}
```

#### :x:Reject

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```json
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignMessage

Once it's connected to Broearn Wallet, an app can request that the user signs a given message. Applications are free to write their own messages which will be displayed to users from within Broearn Wallet's signature prompt. Message signatures do not involve network fees and are a convenient way for apps to verify ownership of an address.

In order to send a message for the user to sign, an application must:

1. Provide a **hex** or **UTF-8** encoded string as a Uint8Array and then **base58-encoded it**.
2. Request that the encoded message is signed via the user's Broearn wallet.

### Query String Parameters

```json
// Some code
window.bw.put.signMessage({
    "message": "...", // the message, base58 encoded
    "session": "...", // token received from connect-method
    "display": "utf8" | "hex", // the encoding to use when displaying the message
})
```

* `message` **(required)**: The message that should be signed by the user, encoded in base58. Broearn wallet will display this message to the user when they are prompted to sign.
* `session` **(required)**: The session token received from the [Connect](/provider-methods/connect) method.&#x20;
* `display` **(optional)**: How you want us to display the string to the user. Defaults to `utf8`

### Returns

#### :white\_check\_mark: Approve

* `data`: An encrypted JSON object.&#x20;

  ```json
  // content of decrypted `data`-parameter
  {
      signature: "...", // message-signature
  }
  ```

  * `signature`: The message signature, encoded in base58.

#### :x:Reject

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```json
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignTransaction

The **easiest** and **most recommended** way to send a transaction is via [SignAndSendTransaction](/provider-methods/signandsendtransaction). It is safer for users, and a simpler API for developers, for Broearn Wallet to submit the transaction immediately after signing it instead of relying on the application to do so.

However, it is also possible for an app to request just the signature from Broearn Wallet. Once signed, an app can submit the transaction itself .

### Query String Parameters

* ```json
  window.bw.put.signTransaction({
      "transaction": "...", // serialized transaction, base58 encoded
      "session": "...", // token received from connect-method
  })
  ```
  * `transaction` **(required)**: The transaction that Broearn wallet will sign, serialized and encoded in base58.
  * `session` **(required)**: The session token received from the [Connect](/provider-methods/connect) method.

### Returns

#### :white\_check\_mark: Approve

* `data`: An encrypted JSON object.&#x20;

  ```json
  // content of decrypted `data`-parameter
  {
      transaction: "...", // signed serialized transaction, base58 encoded
  }
  ```

  * `transaction`: The signed, serialized transaction that is base58 encoded. Broearn wallet will not submit this transactions.&#x20;

#### :x:Reject

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignAllTransactions

Once an app is connected, it is also possible to sign multiple transactions at once. Unlike [SignAndSendTransaction](/provider-methods/signandsendtransaction), Broearn Wallet will not submit these transactions to the network.&#x20;

#### Query String Parameters <a href="#query-string-parameters" id="query-string-parameters"></a>

```json
window.bw.put.signAllTransactions({
  "transactions": [
    "...", // serialized transaction, bs58-encoded
    "...", // serialized transaction, bs58-encoded
  ],
  "session": "...", // token received from connect-method
})

```

* `transactions` **(required)**: An array of transactions that PUT will sign, serialized and encoded in base58.
* `session` **(required)**: The session token received from the [Connect](/provider-methods/connect) method.&#x20;

#### Returns <a href="#returns" id="returns"></a>

**​✅Approve**

* `data`: An encrypted JSON string. Refer to [Encryption](broken://pages/WZ5QJqS5c5F0UYHvz1Sz) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

  ```json
  // content of decrypted `data`-parameter
  {
      transactions: [
          "...", // signed serialized transaction, bs58-encoded
          "...", // signed serialized transaction, bs58-encoded
      ] 
  }
  ```

  * `transactions`: An array of signed, serialized transactions that are base58 encoded. Broearn Wallet will not submit these transactions.&#x20;

**​❌Reject**

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# SignAndSendTransaction

Once an application is connected to Broearn Wallet, it can prompt the user for permission to send transactions on their behalf.

In order to send a transaction, an application must:

1\. Create an unsigned transaction.\
2.Have the transaction be signed and submitted to the network by the user's Broearn Wallet.\
3.Optionally await network confirmation using a PUT JSON RPC connection.

#### Query String Parameters <a href="#query-string-parameters" id="query-string-parameters"></a>

```json
window.bw.put.signAndSendTransaction({
  "transaction": "...", // serialized transaction, base58 encoded
  "session": "...", // token received from connect-method
})
```

* `transaction` **(required)**: The transaction that Broearn wallet will sign, serialized and encoded in base58.
* `session` **(required)**: The session token received from the [Connect](/provider-methods/connect) method.&#x20;

#### Returns <a href="#returns" id="returns"></a>

​✅ **Approve**

* `data`: An encrypted JSON string. Refer to [Encryption](broken://pages/WZ5QJqS5c5F0UYHvz1Sz) to learn how apps can decrypt `data` using a shared secret. Encrypted bytes are encoded in base58.

  ```json
  {
    "signature": "..." // transaction-signature
  }
  ```

  * `signature`: The first signature in the transaction, which can be used as its transaction id

**​❌ Reject**

An `errorCode` and `errorMessage` as query parameters. Please refer to [Errors](/errors) for a full list of possible error codes.

```
{
  "errorCode": "...",
  "errorMessage": "..."
}
```


# Getting Started with Ethereum and EVM

The Broearn Wallet browser extension and mobile in-app browser are both designed to interact with web applications. EVM web apps can interact with Broearn via the provider that is injected at `window.bw.eth`. This provider conforms to the [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) standard and is also injected at `window.ethereum` to support legacy integrations.

This documentation is dedicated to covering all aspects of the provider. For guidance on how to integrate Broearn Wallet into an EVM wallet adapter library, check out our following tutorials:


# Detecting the Provider

To detect if a user has already installed Broearn Wallet, a web application should check for the existence of a `bw` object. Broearn Wallet's browser extension and mobile in-app browser will both inject a `bw` object into the [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) of any web application the user visits.

If a `bw` object exists, Ethereum dApps can interact with Broearn Wallet via the API found at `window.bw.eth`. This `eth`provider is also made available at `window.ethereum` but is prone to namespace collisions from other injected wallets.

If Broearn Wallet is not installed, we recommend you redirect your users to [our website](https://www.broearn.com/en/wallet). Altogether, this may look like the following.

{% tabs %}
{% tab title="window\.bw" %}

```typescript
const getProvider = () => {
  if ('bw' in window) {
    const anyWindow: any = window;
    const provider = anyWindow.bw.eth;
   
    if (provider) {
      return provider;
    }
  }

  window.open('https://broearn.com/', '_blank');
};
```

{% endtab %}
{% endtabs %}


# Establishing a Connection

Once an application has [detected the provider](/ethereum-and-evm/detecting-the-provider), it can then request to connect to Broearn Wallet. This connection request will prompt the user for permission to share their public key, indicating that they are willing to interact further. Users must approve a connection request before the app can make additional requests such as [signing a message](/ethereum-and-evm/signing-a-message) or [sending a transaction](/ethereum-and-evm/sending-a-transaction).

Once permission is established for the first time, the web application's domain will be whitelisted for future connection requests. After a connection is established, it is possible to terminate the connection from both the application and the user side.

## Connecting

The default way to connect to Broearn Wallet is by calling `window.ethereum.request` function.

```javascript
const provider = getProvider(); // see "Detecting the Provider"
try {
    const accounts = await provider.request({ method: "eth_requestAccounts" });
    console.log(accounts[0]);
    // 0xb233696514F192Da7F0f0Fb1332f18c68cfB6c23 
} catch (err) {
    // { code: 4001, message: 'User rejected the request.' }
}
```

The `eth_requestAccounts` method will return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). If it resolves, it is an array where the connected address is in the 0th index, and rejects (throw when awaited) when the user declines the request or closes the pop-up. See [Errors](/errors) for a breakdown of error messages Broearn Wallet may emit.

When the user accepts the request to connect, the provider will also emit a `connect` event that contains the chainId of the network the user is connected to.

{% code overflow="wrap" %}

```typescript
provider.on("connect", (connectionInfo: { chainId: string }) => console.log(`Connected to chain: ${connectionInfo.chainId}`));
```

{% endcode %}

Once the web application is connected to Broearn Wallet, it will be able to read the connected account's address and prompt the user for additional transactions. It also exposes a convenience `isConnected` boolean.

```javascript
console.log(provider.selectedAddress);
// 0xb233696514F192Da7F0f0Fb1332f18c68cfB6c23 
console.log(provider.isConnected());
// true
```

## Disconnecting

There is no way to programmatically disconnect a user from their connection once they have established one.\
\
Once a user has established a connection, Broearn Wallet will add the website they opened a connection with to a list of "trusted apps." The user can then revoke access through the UI at any time, and will then need to reconnect. Broearn Wallet will attempt to reconnect to any application that is added to the users "trusted apps" automatically.

## Changing Accounts

Broearn Wallet allows users to seamlessly manage multiple accounts (i.e. addresses) from within a single extension or mobile app. Whenever a user switches accounts, Broearn Wallet will emit an `accountsChanged` event.

If a user changes accounts while already connected to an application, and the new account had already whitelisted that application, then the user will stay connected and Broearn Wallet will pass the public key of the new account:

```typescript
provider.on('accountsChanged', (publicKeys: String[]) => {
    if (publicKeys) {
        // Set new public key and continue as usual
        console.log(`Switched to account ${publicKeys[0]}`);
    } 
});
```

If Broearn Wallet does not pass the public key of the new account, an application can either do nothing or attempt to reconnect:

```typescript
provider.on('accountsChanged', (publicKeys: String[]) => {
    if (publicKeys) {
      // Set new public key and continue as usual
      console.log(`Switched to account ${publicKeys[0].toBase58()}`);
    } else {
      // Attempt to reconnect to Broearn Wallet
      provider.request({ method: "eth_requestAccounts" }).catch((error) => {
        // handle connection failure
      });
    }
});
```


# Sending a Transaction

Once a web application is connected to Broearn Wallet, it can prompt the user for permission to send transactions on their behalf.

To send a transaction, you will need to have a valid transaction object. It should look a little like this:

```json
{
  from: "0x95222290DD7278Aa3Ddd389Cc1E1d165CC4BAfe5",
  to: "0xb233696514F192Da7F0f0Fb1332f18c68cfB6c23",
  gasLimit: "21000",
  maxFeePerGas: "300",
  maxPriorityFeePerGas: "10",
  nonce: "0",
  value: "10000000000"
}
```

However, this transaction object needs to be signed using the sender's private key. This ensures that only the person that holds the private key can send transactions from the public address.

\
To prompt Broearn Wallet to send a transaction to the network, refer to the following code snippet

```javascript
const result = await provider.request({
        method: 'eth_sendTransaction',
        params: [
          {
            from: accounts[0],
            to: '0xb233696514F192Da7F0f0Fb1332f18c68cfB6c23',
            value: '0x0',
            gasLimit: '0x5028',
            gasPrice: '0x2540be400',
            type: '0x0',
          },
        ],
});
```

This is the building blocks of what you will need to send a transaction. However, if you were to copy/paste this, it would likely fail. There are several pieces of a transaction that are best provided in a dynamic manner. Take a look at our [sendTransaction function](/ethereum-and-evm/sending-a-transaction) in our sandbox for reference.


# Signing a Message

When a web application is connected to Broearn Wallet, it can also request that the user signs a given message. Applications are free to write their own messages which will be displayed to users from within Broearn Wallet's signature prompt. Message signatures do not involve network fees and are a convenient way for apps to verify ownership of an address.&#x20;

{% code overflow="wrap" %}

```javascript
const message = 'To avoid digital dognappers, sign below to authenticate with CryptoCorgis.';
const from = accounts[0];
const msg = `0x${Buffer.from(message, 'utf8').toString('hex')}`;
const sign = await provider.request({
        method: 'personal_sign',
        params: [msg, from, 'Example password'],
    });
```

{% endcode %}

## Support for "Sign In With" Standards

Applications that rely on signing messages to authenticate users can choose to opt-in to one of the various Sign In With (SIW) standards. You can read more about them [here](broken://pages/YaABz9ynXH7f2rnU0K1l).


# Provider API Reference

Broearn Wallet provider API is exposed to the user through the `window.ethereum` object that is injected into the browser. This same provider is made available at `window.bw.eth`to prevent namespace collisions.&#x20;

This API is how a dApp will make requests to the user; reading account data, connecting to the website, signing messages, and sending transactions will all be done through this provider object.\
\
This provider API is specified in greater detail in [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193).\
\
This area of the documentation will contain information about the API's properties, events, and methods.


# Properties

Here you will find a list of all of the properties available to you once the `window.bw.eth`object has been injected.\
\
These are all exactly the same as the `window.ethereum` object. However, we recommend using the `window.bw.eth`object to prevent namespace collisions.

```json
{
    chainId: HexString
    networkVersion: String
    selectedAddress: HexString
    _events: Object
    _eventsCount: Number
}
```


# eth\_chainId

## window\.bw\.eth.chainId

The chainId of the network you are currently connected to, returned as a hexadecimal string.

```javascript
const chainId = window.bw.eth.chainId;
console.log(chainId);
// "0x1"
// hexidecimal representation of Ethereum Mainnet
```


# eth\_networkVersion

## window\.bw\.eth.networkVersion

The network number of the blockchain that you are connected to. This property is available for legacy purposes. It is recommended that modern dapps refer to the `chainId` property to determine what chain a user is connected to currently.

```javascript
const networkVersion = window.bw.eth.networkVersion;
console.log(networkVersion);
// "1"
// Ethereum Mainnet's Network Version
```


# eth\_selectedAddress

## window\.bw\.eth.selectedAddress

The address of the wallet that is currently connected to the dapp. This value will update upon [accountsChanged ](/ethereum-and-evm/provider-api-reference/events/accounts-changed)and  [connect](/ethereum-and-evm/provider-api-reference/events/connect) events.\
\
Returns a hexadecimal string.

```javascript
const address = window.bw.eth.selectedAddress;
console.log(address);
// "0xDAFEA492D9c6733ae3d56b7Ed1ADB60692c98Bc5"
```


# \_events

## window\.bw\.eth.\_events

An object containing all of the events that the provider has emitted or logged.

```javascript
const events = window.bw.eth._events;
console.log(events);
// Events {chainChanged: Array(2), accountsChanged: EE}
```

This is **not** a recommended way to keep track of different events. The provider implements a Node.js `EventEmitter` API to emit different events happening within the wallet and/or dapp. See [Events](/ethereum-and-evm/provider-api-reference/events) for more details.


# \_eventsCount

## window\.bw\.eth.\_eventsCount

An object containing the number of events that have happened

```javascript
const eventsCount = window.bw.eth._eventsCount;
console.log(eventsCount);
// 2
```

This is **not** a recommended way to keep track of different events. The provider implements a Node.js `EventEmitter` API to emit different events happening within the wallet and/or dapp.&#x20;


# Events

Broearn Wallet's provider API available at `window.ethereum` implements a Node.js style [`EventEmitter` ](https://nodejs.org/api/events.html)API, that allows you to hook into different events that are emitted upon certain actions that take place in either the dapp, or the wallet. Each page in this section will be an isolated piece of information that informs you of all the technical details you need to know about each event Broearn Wallet supports.


# Connect

Event emitted upon connecting to a dapp.

```typescript
interface connectionInfo {
  chainId: string;
}

window.ethereum.on('connect', (connectionInfo: connectionInfo) => {
      console.log(connectionInfo.chainId);
      // "0x1" On Ethereum
});
```


# Accounts Changed

Event emitted upon changing accounts within your Broearn wallet.

````typescript
window.ethereum.on('accountsChanged', (newAccounts: String[]) => {
      // "newAccounts" will always be an array, but it can be empty.      
      if (newAccounts) {
        console.log(`switched to new account: ${newAccounts}`);
        accounts = newAccounts;
      } else {
        /**
         * In this case dApps could...
         *
         * 1. Not do anything
         * 2. Only re-connect to the new account if it is trusted
         *
         * ```
         * provider.send('eth_requestAccounts', []).catch((err) => {
         *  // fail silently
         * });
         * ```
         *
         * 3. Always attempt to reconnect
         */
  }
})
````


# Disconnect

Event emitted upon the wallet losing connection to the RPC provider.

This is **not** a user "disconnecting" from a dapp, or otherwise revoking access between the dapp and the wallet.

```typescript
 window.ethereum.on('disconnect', () => {
      console.log('lost connection to the rpc)
});
```


# Chain Changed

Event emitted upon the dapp or wallet changing the network/chain you are connected to

Broearn Wallet abstracts the concept of networks, and network switching. So there is no action required on your end as a dapp developer.

{% code overflow="wrap" %}

```typescript
ethereum.on('chainChanged', (chainId: string) => {
  console.log(chainId);
  // "0x1" on Ethereum
  /* Broearn Wallet will handle all of the internal changes needed to handle the new chain.
   * As the dapp developer, 
   * you just need to make sure all of your transaction requests
   * populate the correct chainId
   */
});
```

{% endcode %}


# Methods

In the following pages you will find information about the individual methods that are available to you through Broearn Wallet's `window.bw.eth`object. As a dapp developer, you will use these methods to programmatically interact with the wallet. From sending requests to/from the blockchain, to connecting to your website — these methods will help you interact with your users.


# isConnected

Checks if the wallet is connected to the dapp

Parameters: None&#x20;

Returns: Boolean&#x20;

```javascript
window.bw.eth.isConnected() 
// true if connected 
// false if not
```


# request

Sends a JSON RPC request to the wallet

Params: `method: string;` `params?: unknown[] | object;`

Returns: `Promise<unknown>`

`Example:`

```javascript
const accounts = await window.bw.eth.request({ 
    method: "eth_requestAccounts", params: [] 
})
console.log(accounts)
// ["0xb233696514F192Da7F0f0Fb1332f18c68cfB6c23"]
```

The code above demonstrates how you can use the `request` method to ask the user to connect to your dapp.\
\
The `request` method is the go to way for you to interface with the wallet in your dapp. It accepts most [JSON RPC requests](https://ethereum.org/en/developers/docs/apis/json-rpc/#json-rpc-methods) that would need to interact with the wallet. \
\
However it **will not** work for methods that don't make sense for a wallet. E.g. you can't use the provider object Broearn Wallet injects to call something like `eth_getTransactionByHash`. If you send a method that the provider object does not support, it will throw an error. You can see a list of errors, and the shape that they will take on [this](/errors) page.


# Demo Applications

Live Demo: <https://www.broearn.com/wallet/demo-applications/>


# ERRORS

When making requests to Broearn wallet in Establishing a Connection, Sending a Transaction, or Signing a Message, Wallet may respond with an error. The following is a list of all possible error codes

<table data-header-hidden><thead><tr><th width="220.33333333333331"></th><th></th><th></th></tr></thead><tbody><tr><td>4100</td><td>Unauthorized</td><td>The requested method and/or account has not been authorized by the user.</td></tr><tr><td>4001</td><td>User Rejected Request</td><td>The user rejected the request through Broearn wallet.</td></tr><tr><td>-32000</td><td>Invalid Input</td><td>Missing or invalid parameters.</td></tr><tr><td>-32002</td><td>Requested resource not available</td><td>This error occurs when a dapp attempts to submit a new transaction while Broearn wallet's approval dialog is already open for a previous transaction. Only one approve window can be open at a time. Users should approve or reject their transaction before initiating a new transaction.</td></tr><tr><td>-32003</td><td>Transaction Rejected</td><td>Broearn wallet does not recognize a valid transaction.</td></tr><tr><td>-32601</td><td>Method Not Found</td><td>Broearn wallet does not recognize the method.</td></tr><tr><td>-32603</td><td>Internal Error</td><td>Something went wrong within Broearn wallet.</td></tr></tbody></table>


# Auth

Wallet Auth is an authentication protocol, this protocol can be used in various applications that include blockchain wallet functionality.

### Example Introduction[​](https://docs.walletconnect.com/2.0/api/auth#introduction) <a href="#introduction" id="introduction"></a>

Wallet Auth is an authentication protocol, this protocol can be used in various applications that include blockchain wallet functionality. The API not only has a simple and elegant interface but also enables a single signing request to verify wallet address ownership for a single login. Wallet Auth enables your application to create a decentralized and password-free login process.

<figure><img src="https://1634294778-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs00Z9yBFmZUCXsfEmKMS%2Fuploads%2FCQOOezyl7vQJ6oLn61o7%2Fdemo.png?alt=media&amp;token=1d1c9299-e504-45b0-a1f9-f660074d1474" alt=""><figcaption><p>Example</p></figcaption></figure>

### Key Features&#x20;

1. A lightweight SDK for quick integration : Wallet Auth is designed to initiate a single signature request. Present the user with a customized wallet signature prompt.
2. Simplify the user login process: Wallet Auth's API features a simple, clean interface that verifies wallet address ownership with a single signature request, realizing the vision of one-signature-at-a-time login.
3. Easy access to user information: Using Wallet Auth, a large number of Dapps can easily confirm user identity information. Wallet Auth enables applications to establish a decentralized and password-free login process.

### Implementation steps

1. User request to [connect](/provider-methods/connect) to Broearn Wallet.
2. User confirms connection to wallet.
3. The web page requests the server for login instructions.
4. The web page sends the login instructions to the wallet for [signature](/provider-methods/signmessage).
5. The wallet receives the signature instructions and submits it string to the server for verification.
6. The server verifies that whether the signature is correct or not.
7. Signature verification fails: the user fails to log in/register.
8. Signature verification success: prompts the user to log in/register successfully (the centralized system can treat the wallet address as a UID, which the user owns)

For a sample signing a message, check out our [developer demo](https://www.broearn.com/wallet/web/demo).

### Getting Started <a href="#getting-started" id="getting-started"></a>

There are getting started guides for the following clients platforms:

[Web - Javascript demo](https://www.broearn.com/wallet/web/demo)

[Web - Java](/advanced/auth/web-java)

[Web - GoLang](/advanced/auth/web-golang)

[Web - PHP](/advanced/auth/web-php)


# Web Java

Code sample for verifying wallet signature and wallet address.

```
<dependency>
    <groupId>net.i2p.crypto</groupId>
    <artifactId>eddsa</artifactId>
    <version>0.3.0</version>
</dependency>
```

<pre class="language-java" data-overflow="wrap"><code class="lang-java">package com.broearn.wallet.crypto;

import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.PublicKey;
import java.security.SignatureException;
import java.util.Arrays;

public class CryptoEd25519Verify {
	
    // Copy for displaying on wallet signature page, allowing customization
    private static String sprintf_str = "Welcome to %s!\n\nClick to sign in and accept the %s Terms of Service: %s\n\nThis request will not trigger a blockchain transaction or cost any gas fees.\n\nNonce:%s";
    private String companyName   = "Your Project Name";                   // The project name used to display on the wallet signature page
    private String serviceDomain = "https://www.youdomain.com";           // Current website address for services provided
    private static final boolean CHECK_TIME = false;
	
    // Example
    public static void main(String[] args) {
    	// Wallet signature string, encoded with base58
    	String signature = "21SNZbbXyhUkN9RXyfKBthzCq8fKA3asV5xcZ6RuQpDcsGRzr6aRreMfrV63jjE5Wc9yx1TzmSuf8h1nvtzSe9Rz";  
    	// Base58 encoding of signed data
    	String message   = "3Qm87Hq6eP6pgoyMa5SraCsWJFB1HcwoTYWbmvhzhFVBTr7Sbm2NgX7JvZ5DEcEXXirwewpsPzDmLoV8Bz8HmQSv4ZJ1kJzbg2NKhk7HcshtczUssJSrfJosev87EcwpXb5GAjJGJunv96P63n36v9WHjaqkqSiRwRetx8GhGPZ3jVCFphEo96Ciz8oQaggqG9TnxP9P1JiyGKuewJkcWnEXyc581yjEF3iwqEVQcmL8BDoLS9kpa17oLPmiPLNXxUXhUXd8bGUrncQmfhG8yNjNQ44wpacbxMZXrtw4ACrBY6qUBRGPbU469RmmWEenF4R8R4rH9Wb22YmRWUmvBPCDVJCCauLvpjwA6Gapv9Lb5HSMtix3241pxd2JhoqhkWK";
    	// wallet address ==> publicKey encoded with base58
    	String publicKey = "7x9XDk1JZTukhN2KQSGqSL1SaoEbGwzdMR3tYLpiJeex";

    	CryptoEd25519Verify cryptoEd25519 = new CryptoEd25519Verify();
    	System.out.println("getSignMsg: " + cryptoEd25519.getSignMsg());
    	try {
    	    String res = cryptoEd25519.checkSign(signature, message, publicKey);
    	    if (!res.isEmpty()) {
    	        System.out.println("Verification passed, wallet address is: " + res);
    	        //TODO This implements login or registration logic. If there is a return here, it indicates that the wallet address is valid and the real owner
    	    } else {
    	        System.out.println("Verification failed, signature error");
    	    }
    	} catch (Exception e) {
    		System.out.println("Error Message: " + e.getMessage());
    	}
<strong>    } 
</strong> 
    /**
     * getSignMsg
     * @return string sign message str
     */
    public String getSignMsg()
    {
    	String msg = "";
    	try {
			msg = urlEncode(String.format(sprintf_str, companyName, companyName, serviceDomain, time()));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        return msg;
    }
    
    
    public String checkSign(String signature, String message, String publicKey) throws Exception {
    	if (signature.isEmpty() || message.isEmpty() || publicKey.isEmpty()) {
            throw new Exception("Parameter error");
        }
    	//Verify expiration time
        if (CHECK_TIME) {
            String messageText = new String(Base58.decode(message));
            int len = messageText.length() - 18;
            String nonce = messageText.substring(len);
            if (nonce.length() == 18 &#x26;&#x26; messageText.contains("Nonce%3A")) {
                Long clientTime = Long.valueOf(nonce.substring(8));
                if (!checkTime(clientTime)) {
                    throw new Exception("Signature Expiration");
                }
            } else {
                throw new Exception("Format error, please keep ending with the string \"Nonce%3A\" and a timestamp of length 10, like this \"Nonce%3A1689054559\"");
            }
        }
        message = new String(Base58.decode(message));
        byte[] publicKeyByte = Base58.decode(publicKey);
        if(ed25519VerifySign(publicKeyByte, message, signature)) {
        	return publicKey;
        }else {
        	return "";
        }
    }
	
    /**
     * ed25519 VerifySign
     * @param data
     * @param signData
     * @return
     * @throws SignatureException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     */
    public static Boolean ed25519VerifySign(byte[] publicKey, String data, String signData) {
        EdDSAEngine edEng  = new EdDSAEngine();
        EdDSANamedCurveSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);  
        PublicKey pk = null;
        Boolean isSuccess = false;
        try {
        	pk = new EdDSAPublicKey(new EdDSAPublicKeySpec(publicKey, spec));
		} catch (Exception e) {
			return isSuccess;
		}
        try {
			edEng.initVerify(pk);
		} catch (InvalidKeyException e) {
			return isSuccess;
		}
        try {
			edEng.setParameter(EdDSAEngine.ONE_SHOT_MODE);
		} catch (InvalidAlgorithmParameterException e) {
			return isSuccess;
		}
        
        try {
			edEng.update(data.getBytes());
			isSuccess = edEng.verify(Base58.decode(signData));
		} catch (SignatureException e) {
		}
        return isSuccess;
    }
    
    /**
     * time
     * @return Long
     */
    public static Long time() {
		return System.currentTimeMillis() / 1000L;
    }
	
    /**
     * CheckTime Check if the client time is within a certain range
     * @param int $clientTime
     * @return bool
     */
	private boolean checkTime(Long clientTime) {
		Long sysTime = time();
		Long time = sysTime + Long.valueOf("120");
		Long time2 = sysTime - Long.valueOf("120");
		if(clientTime &#x3C; time &#x26;&#x26; clientTime > time2) {
			//Client time is less than system time -60 and client time is greater than system time -60
			return true;
		}else {
			return false;
		}
	}
	
	private String urlEncode(String msg) throws UnsupportedEncodingException {
		return URLEncoder.encode(msg, "UTF-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
	}
	
}


class Base58 {

    public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
    private static final char ENCODED_ZERO = ALPHABET[0];
    private static final int[] INDEXES = new int[128];
    static {
        Arrays.fill(INDEXES, -1);
        for (int i = 0; i &#x3C; ALPHABET.length; i++) {
            INDEXES[ALPHABET[i]] = i;
        }
    }

    /**
     * Base58 encode
     * @param input
     * @return String
     */
    public static String encode(byte[] input) {
        if (input.length == 0) {
            return "";
        }
        int zeros = 0;
        while (zeros &#x3C; input.length &#x26;&#x26; input[zeros] == 0) {
            ++zeros;
        }
        input = Arrays.copyOf(input, input.length);
        char[] encoded = new char[input.length * 2];
        int outputStart = encoded.length;
        for (int inputStart = zeros; inputStart &#x3C; input.length;) {
            encoded[--outputStart] = ALPHABET[divmod(input, inputStart, 256, 58)];
            if (input[inputStart] == 0) {
                ++inputStart;
            }
        }
        while (outputStart &#x3C; encoded.length &#x26;&#x26; encoded[outputStart] == ENCODED_ZERO) {
            ++outputStart;
        }
        while (--zeros >= 0) {
            encoded[--outputStart] = ENCODED_ZERO;
        }
        return new String(encoded, outputStart, encoded.length - outputStart);
    }

    /**
     * Base58 decode
     * @param input
     * @return byte[]
     */
    public static byte[] decode(String input) {
        if (input.length() == 0) {
            return new byte[0];
        }
        byte[] input58 = new byte[input.length()];
        for (int i = 0; i &#x3C; input.length(); ++i) {
            char c = input.charAt(i);
            int digit = c &#x3C; 128 ? INDEXES[c] : -1;
            if (digit &#x3C; 0) {
                String msg = i +"Invalid characters,c=" + c;
                throw new RuntimeException(msg);
            }
            input58[i] = (byte) digit;
        }
        int zeros = 0;
        while (zeros &#x3C; input58.length &#x26;&#x26; input58[zeros] == 0) {
            ++zeros;
        }
        byte[] decoded = new byte[input.length()];
        int outputStart = decoded.length;
        for (int inputStart = zeros; inputStart &#x3C; input58.length;) {
            decoded[--outputStart] = divmod(input58, inputStart, 58, 256);
            if (input58[inputStart] == 0) {
                ++inputStart;
            }
        }
        while (outputStart &#x3C; decoded.length &#x26;&#x26; decoded[outputStart] == 0) {
            ++outputStart;
        }
        return Arrays.copyOfRange(decoded, outputStart - zeros, decoded.length);
    }

    /**
     * divmod
     * @param number
     * @param firstDigit
     * @param base
     * @param divisor
     * @return byte
     */
    private static byte divmod(byte[] number, int firstDigit, int base, int divisor) {
        int remainder = 0;
        for (int i = firstDigit; i &#x3C; number.length; i++) {
            int digit = (int) number[i] &#x26; 0xFF;
            int temp = remainder * base + digit;
            number[i] = (byte) (temp / divisor);
            remainder = temp % divisor;
        }
        return (byte) remainder;
    }
}
</code></pre>


# Web Golang

Code sample for verifying wallet signature and wallet address.

{% code overflow="wrap" %}

```go

package main

import (
	"crypto/ed25519"
	"errors"
	"fmt"
	"github.com/btcsuite/btcd/btcutil/base58"
	"net/url"
	"strconv"
	"time"
)

var (
	// Copy for displaying on wallet signature page, allowing customization
	sprintfStr = "Welcome to %s!\\n\\nClick to sign in and accept the %s Terms of Service: %s\\n\\nThis request will not trigger a blockchain transaction or cost any gas fees.\\n\\nNonce:%d"
	// The project name used to display on the wallet signature page
	companyName = "Your Project Name"
	// Current website address for services provided
	serviceDomain = "https://www.youdomain.com"
	CheckTime     = false
)

// sign message str
func getSignMsg() string {
	return url.PathEscape(fmt.Sprintf(sprintfStr, companyName, companyName, serviceDomain, time.Now().Unix()))
}

// verify signature
func checkSign(signature, message, publicKey string) (string, error) {
	if signature == "" || message == "" || publicKey == "" {
		return "", errors.New("parameter error")
	}

	// verify expiration time
	if CheckTime {
		messageText := base58.Decode(message)
		if len(messageText) > 16 {
			clientTime := sprintfStr[len(messageText)-16:]
			clientTimeInt, _ := strconv.ParseInt(clientTime, 10, 64)
			if checkTime(clientTimeInt) {
				return "", errors.New("signature error")
			}
		} else {
			return "", errors.New("format error, please keep ending with the string \"Nonce%3A\" and a timestamp of length 10, like this \"Nonce%3A1689054559")
		}
	}

	verify := ed25519.Verify(base58.Decode(publicKey), base58.Decode(message), base58.Decode(signature))
	if verify {
		return publicKey, nil
	}
	return "", errors.New("signature error")
}

// CheckTime Check if the client time is within a certain range
func checkTime(clientTime int64) bool {
	sysTime := time.Now().Unix()
	time1 := sysTime + 120
	time2 := sysTime - 120
	return clientTime < time1 && clientTime > time2
}

// Example
func main() {
	fmt.Println(getSignMsg())

	publicKey, err := checkSign("21SNZbbXyhUkN9RXyfKBthzCq8fKA3asV5xcZ6RuQpDcsGRzr6aRreMfrV63jjE5Wc9yx1TzmSuf8h1nvtzSe9Rz",
		"3Qm87Hq6eP6pgoyMa5SraCsWJFB1HcwoTYWbmvhzhFVBTr7Sbm2NgX7JvZ5DEcEXXirwewpsPzDmLoV8Bz8HmQSv4ZJ1kJzbg2NKhk7HcshtczUssJSrfJosev87EcwpXb5GAjJGJunv96P63n36v9WHjaqkqSiRwRetx8GhGPZ3jVCFphEo96Ciz8oQaggqG9TnxP9P1JiyGKuewJkcWnEXyc581yjEF3iwqEVQcmL8BDoLS9kpa17oLPmiPLNXxUXhUXd8bGUrncQmfhG8yNjNQ44wpacbxMZXrtw4ACrBY6qUBRGPbU469RmmWEenF4R8R4rH9Wb22YmRWUmvBPCDVJCCauLvpjwA6Gapv9Lb5HSMtix3241pxd2JhoqhkWK",
		"7x9XDk1JZTukhN2KQSGqSL1SaoEbGwzdMR3tYLpiJeex")

	if err == nil {
		fmt.Println("Verification passed, wallet address is: " + publicKey)
	} else {
		fmt.Println(err)
	}
}

```

{% endcode %}


# Web PHP

Code sample for verifying wallet signature and wallet address.

```
PHP environment:
version > 7.2
extension support: --enable-sodium  Enable "php-sodium-ext" 
```

{% code overflow="wrap" %}

```php
<?php
class CryptoEd25519Verify
{
    const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
    // Copy for displaying on wallet signature page, allowing customization
    const SPRINTF_STR = "Welcome to %s!\n\nClick to sign in and accept the %s Terms of Service: %s\n\nThis request will not trigger a blockchain transaction or cost any gas fees.\n\nNonce:%s";
    const COMPANY_NAME = "Your Project Name";                   // The project name used to display on the wallet signature page
    const SERVICE_DOMAIN = "https://www.youdomain.com";           // Current website address for services provided
    const CHECK_TIME = false;

    /**
     * getSignMsg
     * @return string sign message str
     */
    public function getSignMsg()
    {
        return rawurlencode(sprintf(self::SPRINTF_STR, self::COMPANY_NAME, self::COMPANY_NAME, self::SERVICE_DOMAIN, time()));
    }

    /**
     * checkSign
     * @param string $signature base58 format
     * @param string $message  base58 format
     * @param string $publicKey  base58 format
     * @return string address || empty string
     */
    public function checkSign($signature, $message, $publicKey)
    {
        if (empty($signature) || empty($message) || empty($publicKey)) {
            throw new Exception('Parameter error');
        }

        if (!function_exists('sodium_crypto_sign_verify_detached')) {
            throw new Exception('--enable-sodium  Enable "php-sodium-ext" extension support');
        }

        //Verify expiration time
        if (self::CHECK_TIME) {
            $messageText = $this->base58_decode($message);
            $len = mb_strlen($messageText) - 18;
            $nonce = substr($messageText, $len);
            if (mb_strlen($nonce) == 18 && strpos($messageText, 'Nonce%3A') !== false) {
                $clientTime = intval(substr($nonce, 8));
                if (!$this->checkTime($clientTime)) {
                    throw new Exception('Signature Expiration');
                }
            } else {
                throw new Exception('Format error, please keep ending with the string "Nonce%3A" and a timestamp of length 10, like this "Nonce%3A1689054559"');
            }
        }

        $message = $this->base58_decode($message);
        $signature = $this->base58_decode($signature);
        $publicKey = $this->base58_decode($publicKey);

        if (\sodium_crypto_sign_verify_detached($signature, $message, $publicKey)) {
            return $this->base58_encode($publicKey);
        } else {
            return "";
        }
    }

    /**
     * base58_encode
     * @param string str
     * @return string base58 str
     */
    public function base58_encode($string)
    {
        $base = mb_strlen(self::ALPHABET);
        if (is_string($string) === false) {
            return false;
        }
        if (mb_strlen($string) === 0) {
            return '';
        }
        $bytes = array_values(unpack('C*', $string));
        $decimal = $bytes[0];
        for ($i = 1, $l = count($bytes); $i < $l; $i++) {
            $decimal = bcmul($decimal, 256);
            $decimal = bcadd($decimal, $bytes[$i]);
        }
        $output = '';
        while ($decimal >= $base) {
            $div = bcdiv($decimal, $base, 0);
            $mod = bcmod($decimal, $base);
            $output .= self::ALPHABET[$mod];
            $decimal = $div;
        }
        if ($decimal > 0) {
            $output .= self::ALPHABET[$decimal];
        }
        $output = strrev($output);
        foreach ($bytes as $byte) {
            if ($byte === 0) {
                $output = self::ALPHABET[0] . $output;
                continue;
            }
            break;
        }
        return (string) $output;
    }

    /**
     * base58_decode
     * @param string base58
     * @return string
     */
    public function base58_decode($base58)
    {
        $base = strlen(self::ALPHABET);
        if (is_string($base58) === false) {
            return false;
        }
        if (strlen($base58) === 0) {
            return '';
        }
        $indexes = array_flip(str_split(self::ALPHABET));
        $chars = str_split($base58);
        foreach ($chars as $char) {
            if (isset($indexes[$char]) === false) {
                return false;
            }
        }
        $decimal = $indexes[$chars[0]];
        for ($i = 1, $l = count($chars); $i < $l; $i++) {
            $decimal = bcmul($decimal, $base);
            $decimal = bcadd($decimal, $indexes[$chars[$i]]);
        }
        $output = '';
        while ($decimal > 0) {
            $byte = bcmod($decimal, 256);
            $output = pack('C', $byte) . $output;
            $decimal = bcdiv($decimal, 256, 0);
        }
        foreach ($chars as $char) {
            if ($indexes[$char] === 0) {
                $output = "\x00" . $output;
                continue;
            }
            break;
        }
        return $output;
    }

    /**
     * CheckTime Check if the client time is within a certain range
     * @param int $clientTime
     * @return bool
     */
    private function checkTime($clientTime)
    {
        $sysTime = time();
        $time = $sysTime + 120;
        $time2 = $sysTime - 120;
        if ($clientTime < $time && $clientTime > $time2) {
            //Client time is less than system time -60 and client time is greater than system time -60
            return true;
        } else {
            return false;
        }
    }
}


// Example
$signature = '21SNZbbXyhUkN9RXyfKBthzCq8fKA3asV5xcZ6RuQpDcsGRzr6aRreMfrV63jjE5Wc9yx1TzmSuf8h1nvtzSe9Rz';  // Wallet signature string, encoded with base58
$message   = '3Qm87Hq6eP6pgoyMa5SraCsWJFB1HcwoTYWbmvhzhFVBTr7Sbm2NgX7JvZ5DEcEXXirwewpsPzDmLoV8Bz8HmQSv4ZJ1kJzbg2NKhk7HcshtczUssJSrfJosev87EcwpXb5GAjJGJunv96P63n36v9WHjaqkqSiRwRetx8GhGPZ3jVCFphEo96Ciz8oQaggqG9TnxP9P1JiyGKuewJkcWnEXyc581yjEF3iwqEVQcmL8BDoLS9kpa17oLPmiPLNXxUXhUXd8bGUrncQmfhG8yNjNQ44wpacbxMZXrtw4ACrBY6qUBRGPbU469RmmWEenF4R8R4rH9Wb22YmRWUmvBPCDVJCCauLvpjwA6Gapv9Lb5HSMtix3241pxd2JhoqhkWK'; // Base58 encoding of signed data
$publicKey = '7x9XDk1JZTukhN2KQSGqSL1SaoEbGwzdMR3tYLpiJeex';                                              // wallet address  ==> publicKey encoded with base58

$cryptoEd25519 = new CryptoEd25519Verify();
echo $cryptoEd25519->getSignMsg();

try {
    $res = $cryptoEd25519->checkSign($signature, $message, $publicKey);
    if (!empty($res)) {
        echo 'Verification passed, wallet address is: ' . $res;
        //TODO This implements login or registration logic. If there is a return here, it indicates that the wallet address is valid and the real owner
    } else {
        echo 'Verification failed, signature error';
    }
} catch (Exception $e) {
    echo 'Error Message: ' . $e->getMessage();
}
```

{% endcode %}


