# Cycle Unit Guide

## 1. Create APP

1. Go to Cycle Unit Manager to log in and create an APP [\[link\]](https://unit.cyclenetwork.io/) and connect your wallet to log in. Each EOA address can create or manage one APP.
2. On your first login, you'll see the page below. Enter your Organization Name and App Name to create your first app.

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

<figure><img src="https://xjl2b5etm07.sg.larksuite.com/space/api/box/stream/download/asynccode/?code=YjA3OGU4ZDQxZDIyNTNlZmI5NmRiYTI1OTI5MjhmOWFfamh0WGx0ZTJxU3JLUnBOU0NqenNUQXZjT2lIOGNmUHBfVG9rZW46UU9pYmJGSk5pb2twR2R4blY3eGx0cHhLZ3VkXzE3NjE3MjEwNjE6MTc2MTcyNDY2MV9WNA" alt=""><figcaption></figcaption></figure>

3. Fill in the relevant details for your newly created app.

<figure><img src="/files/5Eq89QTG6ImXrmmbQnV1" alt=""><figcaption></figcaption></figure>

<figure><img src="https://xjl2b5etm07.sg.larksuite.com/space/api/box/stream/download/asynccode/?code=N2I0MDk4N2IwNTg1YTJmM2NlZDFjMmY0YjY0NDJmZjRfU2hxQmxZWmdKZHUxd2Fwak1SUlltOEF2cndDZVd4WllfVG9rZW46SGNjWGJDbjdrb0VpZTZ4UDd2VmxiNURwZ1JlXzE3NjE3MjEwNjE6MTc2MTcyNDY2MV9WNA" alt=""><figcaption></figcaption></figure>

4. Click + to add asset managers and select the supported tokens. Then click Submit to complete the setup.

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

<figure><img src="https://xjl2b5etm07.sg.larksuite.com/space/api/box/stream/download/asynccode/?code=OWU1ODI1MmJkN2Q2Y2VkOTY5NGFiODIzNGNkOTc0OGRfU25JT1JXSzFnMzVSNHU4M2tNVFQ4YThNUmwwQ3lkQ0VfVG9rZW46U2FvZ2JFQVlpb0owM0N4bE5qemxlVFN5Z3FjXzE3NjE3MjEwNjE6MTc2MTcyNDY2MV9WNA" alt=""><figcaption></figcaption></figure>

Note: You can update your App Info and App Details anytime. If you need to make changes — such as updating, adding, or removing asset managers — you can do so at any time.

## 2. Deploy Vault Contract

The Vault contract is used for users to deposit funds. It must implement the `deposit` method. For specific implementation, please refer to [the documentation](https://github.com/CycleNetwork-Labs/cycle-unit-example-vault-contract).

```solidity
// @param user The staker's account
// @param token The contract address, use address(0) for native token
function deposit(
    address user,
    address token,
    uint256 amount
) external payable;

event Deposit(address user, address token, uint256 amount);
```

## 3. Interfaces

The Cycle Unit SDK helps users implement the withdrawal UI. Withdrawals require the application server to provide a balance query interface and a withdrawal application interface. After configuring the interface addresses, users can initiate withdrawals directly through the client. The application needs to verify the validity of the data and implement the asynchronous withdrawal logic on the server side.

### 3.1 User Withdrawable Balance Query Interface

Request Method: GET

Request Parameters:

| Parameter Name | Type   | Required | Description      |
| -------------- | ------ | -------- | ---------------- |
| userAddress    | string | Yes      | User eoa address |

Request Example:

```go
curl --location 'https://unit-api.cyclenetwork.io/v5/mock/balance?userAddress=0x10Ca44272987fa662cA8C4916361c378b7Da4D50'
```

Response Parameters:

```go
{
    "code": 0,
    "data": [
        {
            "tokenSymbol": "USDT",
            "tokenDecimals": 6,
            "tokenAmount": "5000000",
            "feeSymbol": "USDT",
            "feeDecimals": "6",
            "feeAmount": "1000000"
        },
        {
            "tokenSymbol": "ETH",
            "tokenDecimals": 18,
            "tokenAmount": "2000000000000000000",
            "feeSymbol": "USDT",
            "feeDecimals": "6",
            "feeAmount": "1000000"
        }
    ],
    "message": "success"
}
```

### 3.2 Withdrawal Application Interface

Request Method: POST

Authentication Method: EIP712

Request Parameters:

<table data-header-hidden><thead><tr><th></th><th width="154.5"></th><th></th><th></th></tr></thead><tbody><tr><td>Parameter Name</td><td>Parameter Type</td><td>Required</td><td>Description</td></tr><tr><td>userAddress</td><td>string</td><td>Yes</td><td>User address</td></tr><tr><td>message</td><td>object[Withdraw]</td><td>Yes</td><td>Withdrawal information</td></tr><tr><td>signature</td><td>string</td><td>Yes</td><td>Signature information</td></tr></tbody></table>

Request Parameter Example:

```json
{
    "userAddress": "0x10Ca44272987fa662cA8C4916361c378b7Da4D50",
    "message": {
        "tokenSymbol": "USDT",
        "amount": "2000000",
        "destinationChainId": 421614,
        "chainId": 11155111,
        "timestamp": 1234567890
    },
    "signature": "xxxx"
}
```

\
EIP712 Signature Parameters:

```go
typedData := apitypes.TypedData{
    Types: apitypes.Types{
       "EIP712Domain": {
          {Name: "name", Type: "string"},
          {Name: "version", Type: "string"},
          {Name: "chainId", Type: "uint256"},
          {Name: "verifyingContract", Type: "address"},
       },
       "Withdraw": {
          {Name: "tokenSymbol", Type: "string"},
          {Name: "amount", Type: "uint256"},
          {Name: "destinationChainId", Type: "uint256"},
          {Name: "chainId", Type: "uint256"},
          {Name: "timestamp", Type: "uint256"},
       },
    },
    PrimaryType: "Withdraw",
    Domain: apitypes.TypedDataDomain{
       Name:              "Cycle Network",
       Version:           "1",
       ChainId:           math.NewHexOrDecimal256(params.Message.ChainID),
       VerifyingContract: "0x0000000000000000000000000000000000000000",
    },
    Message: map[string]interface{}{
       "tokenSymbol":        params.Message.TokenSymbol,
       "amount":             amount,
       "destinationChainId": big.NewInt(params.Message.DestinationChainId),
       "chainId":            big.NewInt(params.Message.ChainID),
       "timestamp":          big.NewInt(params.Message.Timestamp),
    },
}
```

\
Response Parameters:

```go
{
    "code": 0,
    "message": "success",
    "data": "PENDING"
}
```

## 4. React Components SDK

### 4.1 Frontend Usage

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

Full documentation is available on <https://github.com/CycleNetwork-Labs/cycle-unit-app>

<pre class="language-typescript"><code class="lang-typescript">
import { Deposit, Withdraw } from "cycle-unit";

const apiBaseUrl = import.meta.env.VITE_ADMIN_API_BASE_URL;

if (!apiBaseUrl) {
<strong>  throw new Error("Missing VITE_ADMIN_API_BASE_URL");
</strong>}

const appId = "your-app-id";
const walletConnectProjectId = "your-walletconnect-project-id";
const vaultChainId = -1; // replace with the numeric chain id that holds your vault
const vaultContract = "your-vault-contract-address";
const shouldProvideProviders = true; // set to false when your app already wraps children in Wagmi/RainbowKit providers

<strong>&#x3C;Deposit
</strong>  appId={appId}
  apiBaseUrl={apiBaseUrl}
  walletConnectProjectId={walletConnectProjectId}
  vaultChainId={vaultChainId}
  vaultContract={vaultContract}
  shouldProvideProviders={shouldProvideProviders}
  onDeposit={(action) => console.log("Deposit completed", action)}
/>;

<strong>&#x3C;Withdraw
</strong>  appId={appId}
  apiBaseUrl={apiBaseUrl}
  walletConnectProjectId={walletConnectProjectId}
  vaultChainId={vaultChainId}
  vaultContract={vaultContract}
  shouldProvideProviders={shouldProvideProviders}
  onWithdraw={(action) => console.log("Withdraw completed", action)}
/>;

- `appId` – Identifier copied from the admin surface for the app you are embedding.
- `apiBaseUrl` – Base URL for the Cycle backend; must be defined as `VITE_ADMIN_API_BASE_URL`.
- `walletConnectProjectId` – WalletConnect project identifier used to launch the connect modal.
- `vaultChainId` – Numeric chain ID that backs the vault handling deposits and withdrawals.
- `vaultContract` – Contract address for the vault on the specified chain.
- `shouldProvideProviders` – Controls whether the SDK mounts its own Wagmi/RainbowKit providers. Leaving it undefined lets the SDK auto-detect existing context; keep it `true` when integrating standalone, and set `false` if your application already supplies these wrappers.
</code></pre>

## 5. Withdrawal SDK

When APP users initiate a withdrawal, they can use the following SDK to construct, sign, and submit the transaction. Alternatively, they can refer to the code to customize their own logic.**Usage:**&#x49;mport:

```go
go get -u github.com/CycleNetwork-Labs/cycle-unit-withdraw-sdk/withdraw-go
```

Usage Example:

```go
package main

import (
    "context"
    "log"
    "math/big"

    "github.com/CycleNetwork-Labs/cycle-unit-withdraw-sdk/withdraw-go/transactions"
    "github.com/davecgh/go-spew/spew"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    ctx := context.Background()
    
    sender := common.HexToAddress("")
    client, err := ethclient.Dial("")
    if err != nil {
       log.Fatal(err)
    }
    nonce, err := client.PendingNonceAt(ctx, sender)
    gasPrice, err := client.SuggestGasPrice(ctx)
    gasLimit := uint64(220000)
    sourceChainID := int64(11155111)
    destinationChainID := int64(421614)
    destinationAddress := common.HexToAddress("0x0")

    params := transactions.WithdrawParams{
       Client:             client,
       Nonce:              nonce,
       GasPrice:           gasPrice,
       GasLimit:           gasLimit,
       TokenSymbol:        "USDT",
       SourceChainID:      sourceChainID,
       DestinationChainID: destinationChainID,
       DestinationAddress: destinationAddress,
       Amount:             big.NewInt(1000000),
    }
    tx, err := transactions.Build(params)
    if err != nil {
       log.Fatal(err)
    }
    spew.Dump(tx)
}
```

\
Withdrawal Parameters:

* `TokenSymbol`: Token symbol defined by Cycle [\[link\]](/developers/connect-to-cycle/connect-to-cycle-mainnet/cycle-frigate.md#token-list)
* `SourceChainID`: Chain ID initiating the transfer
* `DestinationChainID`: Chain ID receiving the tokens
* `DestinationAddress`: Destination address for the withdrawal
* `Amount`: Token transfer amount (full precision)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cyclenetwork.io/developers/cycle-unit-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
