This article provides an end-to-end demonstration of creating a crypto wallet application for your platform or exchange. Throughout the article, you will learn::

  1. How to initialize RestClients with Cobo SDKs.
  2. How to create your first deposit address.
  3. How to retrieve transaction information.
  4. How to make withdraw transactions.

Before you start:

Make sure you have finished your wallet setup based on Quickstart. Before writing your first demo, make sure that the following actions have been completed:

  1. You have pulled your preferred SDK for development.
  2. You have completed key pair generation for API Authentication.
  3. You have added your API Key to your Custodial Wallet, MPC Co-managed Wallet, or MPC Lite Wallet.

Initialize

Cobo SDKs have packaged RestClients to interact with Cobo Wallet-as-a-Service APIs. To start, you need to initialize these Clients as well as the ApiSigner for API Authentication.

Custodial Wallet

from cobo_custody.client import Client
from cobo_custody.config import DEV_ENV
from cobo_custody.signer.local_signer import LocalSigner

# input your API SECRET
signer = LocalSigner("YOUR_API_SECRET")
client = Client(signer=signer, env=DEV_ENV, debug=True)

MPC Wallet

from cobo_custody.client import MPCClient
from cobo_custody.config import DEV_ENV
from cobo_custody.signer.local_signer import LocalSigner

# input your API SECRET
signer = LocalSigner("YOUR_API_SECRET")
mpc_client = MPCClient(signer=signer, env=DEV_ENV, debug=True)

Use the correct Client and Environment

Client is for custodial wallet, MPCClient is for MPC Co-managed and MPC Lite wallet.
DEV_ENV is development environment, PROD_ENV is for production environment.

Create your first deposit address

Now you are able to create your first deposit address. Let us take Goerli ETH as an example. Please make sure that you or your admin have added GETH in the wallet. To verify, you can use Get Account Details for Custodial Wallet or Get Wallet Supported Coins for MPC Wallets.

Cusotidal Wallet

response = client.get_account_info()

MPC Wallet

response = mpc_client.get_wallet_supported_coins()

If GETH is already available, you can create your first deposit address: Cusotidal Wallet

response = client.new_deposit_address("GETH")

MPC Wallet

response = mpc_client.generate_addresses("GETH",1)

Check your first deposit transaction

You can make a deposit transaction to your newly created GETH address from an external address. After that, you can query the transaction by latest transaction time.

Cusotidal Wallet

response = client.get_transactions_by_time(side="deposit", limit="1")

MPC Wallet

response = mpc_client.list_transactions(transaction_type=1000, order_by="created_time", order="DESC", limit=1)

You may find other different ways of transaction query in API References: Custodial Wallet. MPC Wallet.

Make your first withdraw transaction

BBefore making the withdraw, you may want to find out the transaction fees. In Custodial Wallet, abs_estimate_fee in Get Coin Details indicates the withdraw fees in fee_coin. In MPC Wallets, gas_price in Get Estimate Fee indicates the on-chain real-time transaction fees.

Cusotidal Wallet

response = client.get_coin_info("GETH")
print(f"Get Estimated Fee: {response.result['abs_estimate_fee']}")

MPC Wallet

response = mpc_client.estimate_fee("GETH",1,"To_Address")

Now you can create your first withdraw transaction, please use UUID for request_id to prevent any confusion in future reconcilation. From address is required in MPC wallets whereas exampted in Custodial wallet. Meanwhile, pay attention to amount value and decimal format of each coin (amount = abs_amount*10^decimal).
Here is an example of withdrawing 0.01 GETH to an external account:

Cusotidal Wallet

request_id = f"request_id_{sha256(address.encode()).digest().hex()[:8]}_{str(int(time.time() * 1000))}"
response = client.withdraw("GETH","To_addres","10000000000000000",request_id)

MPC Wallet

request_id = f"request_id_{sha256(address.encode()).digest().hex()[:8]}_{str(int(time.time() * 1000))}"
response = mpc_client.create_transaction("GETH",request_id,"From_address","To_Address","10000000000000000")

Then you may use the request_id to query the transaction status. Please note that the transaction will only be confirmed once the on-chain confirmation blocks reach confirming_threshold. Before that, you may use the GET /v1/custody/pending_transactions/ endpoint to query the details of a pending transaction under a Custodial Wallet. For an MPC Wallet, you may refer to the status field with code 501 PENDING_CONFIRMATION in any transactional APIs to retrieve the details of a pending transaction. Prior to using any endpoints, however, you need to first head to Cobo Custody Web and enable the “Transaction Notification - Includes Block Confirmation Number” Status feature. Failure to enable this feature will result in the inability to fetch transaction information. Do note that some transactions cannot be retrieved due to fast on-chain confirmations (e.g., TRON).

Cusotidal Wallet

response = client.get_transactions_by_request_ids(request_ids="your request_id")

MPC Wallet

response = mpc_client.transactions_by_request_ids("your request_id")

Congratulations! You have successfully created your first wallet application with Cobo Wallet-as-a-Service.

Code Samples

The sample codes are for reference only. Please use Cobo SDKs for your development.

Note: The code samples for Custodial Wallet and MPC Wallet are different.

Custodial Wallet

from cobo_custody.client import Client
from cobo_custody.config import DEV_ENV
from cobo_custody.signer.local_signer import LocalSigner
import time

api_secret = "your_api_secret"  # Your wallet api secret
coin_code = "GETH"  # Your testing coin
amount = 10000000000000000  # Withdraw amount:0.01GETH
to_address = "your address"  # Your external address

# Initialize Cobo Client
client = Client(signer=LocalSigner(api_secret), env=DEV_ENV, debug=False)

# Check if GETH has been added in your wallet
response = client.get_coin_info(coin=coin_code)
print(f"Get Coin Info: {response.result}")

# Create GETH address
response = client.new_deposit_address(coin=coin_code)
print(f"New Deposit Address: {response.result}")

# Get deposit transaction
response = client.get_transactions_by_time(side="deposit", limit="1")
print(f"Get Transactions By Time: {response.result}")

# Get estimated withdraw fee
response = client.get_coin_info(coin=coin_code)
print(f"Get Estimated Fee: {response.result['abs_estimate_fee']}")

# Withdraw 0.01GETH
request_id = f"ApiTransaction-{int(time.time() * 1000)}"    # Your custom request_id
response = client.withdraw(
    coin=coin_code,
    request_id=request_id,
    amount=amount,
    address=to_address,
)
print(f"Withdraw: {response.result}")

# Get transaction by request_id
response = client.get_transactions_by_request_ids(request_ids=request_id)
print(f"Get Transactions By Request Ids: {response.result}")


MPC Wallet

from cobo_custody.client.mpc_client import MPCClient
from cobo_custody.config import DEV_ENV
from cobo_custody.signer.local_signer import LocalSigner
import time


api_secret = "your api secret"  # Your wallet api secret
chain_code = "GETH"  # Your testing chain
coin_code = "GETH"  # Your testing coin
amount = "10000000000000000"  # Withdraw amount:0.01GETH
from_address = "your mpc wallet address"  # Your MPC wallet address
to_address = "your address"  # Your external address

# Initialize Cobo Client
mpc_client = MPCClient(signer=LocalSigner(api_secret), env=DEV_ENV, debug=False)

# Check if GETH has been added in your wallet
response = mpc_client.get_wallet_supported_coins()
geth_coin_found = any(coin['coin'] == coin_code for coin in response.result['coins'])
is_coin_added = f"{coin_code} supports deposits and withdrawals." if geth_coin_found \
    else f"Your wallet does not have the {coin_code} coin. Please configure it on Cobo Custody Web."
print(is_coin_added)

# Create GETH address
response = mpc_client.generate_addresses(chain_code=chain_code, count=1)
print(f"New Deposit Address: {response.result}")

# Get deposit transaction
response = mpc_client.list_transactions(transaction_type=1000, order_by="created_time", order="DESC", limit=1)
print(f"Get Transactions By Time: {response.result}")

# Get estimated gas fee
response = mpc_client.estimate_fee(coin=coin_code, amount=1, address=to_address)
print(f"Get Estimated Gas Fee: {response.result}")

# Withdraw 0.01GETH
request_id = f"MPCTransaction-{int(time.time() * 1000)}"  # Your custom request_id
response = mpc_client.create_transaction(
    coin=coin_code,
    request_id=request_id,
    amount=amount,
    from_addr=from_address,
    to_addr=to_address,
)
print(f"Withdraw: {response.result}")

# Get transaction by request_id
response = mpc_client.transactions_by_request_ids(request_id)
print(f"Get Transactions By Request Ids: {response.result}")