Cycle Unit Integration Guide

1. Create APP

  1. Go to Cycle Unit Manager to log in and create an APP [link] 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.

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

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

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.

// @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:

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

Response Parameters:

{
    "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:

Parameter Name

Parameter Type

Required

Description

userAddress

string

Yes

User address

message

object[Withdraw]

Yes

Withdrawal information

signature

string

Yes

Signature information

Request Parameter Example:

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

EIP712 Signature Parameters:

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:

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

4. React Components SDK

4.1 Frontend Usage

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


import { Deposit, Withdraw } from "cycle-unit";

const apiBaseUrl = import.meta.env.VITE_ADMIN_API_BASE_URL;

if (!apiBaseUrl) {
  throw new Error("Missing VITE_ADMIN_API_BASE_URL");
}

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

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

<Withdraw
  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.

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:Import:

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

Usage Example:

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 [Insert link to doc for unit mainnet token symbol 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)

最后更新于