Use this file to discover all available pages before exploring further.
Try Cobo WaaS Skill in your AI coding assistant (Claude Code, Cursor, etc.). Describe your needs in natural language to auto-generate production-ready SDK code and debug faster 🚀
Set up a Safe{Wallet} and configure transaction policies
Deposit and withdraw tokens
Call a smart contract
This guide uses the development environment in all its code samples. It is recommended that you use the development environment to test your new features first before deploying them to the production environment.
You have been assigned the Operator role or a custom role with equivalent permissions.
For using the WaaS API, ensure the following:
Follow the instructions in Send your first request to set up your account and send your first API request to the WaaS 2.0 service.
If you choose to use a WaaS SDK instead of manually writing the API requests, refer to the SDK guide corresponding to the programming language of your choice (Python, Java, Go, JavaScript to integrate the SDK into your project.
Prepare some test tokens as you will need them when testing the deposit feature. To know which test tokens you can use, refer to Query chain and token information. In most cases, you can use XTN as the test token.
It is highly recommended that you set up a callback endpoint to receive and approve withdrawal requests and a webhook endpoint to receive real-time notifications regarding transaction status updates and other events of your concern. To learn how to set up and register webhook and callback endpoints, refer to Introduction to webhooks and callbacks.
Before you begin setting up your wallet and generating deposit addresses, it’s important to know which chains and tokens you can use. To retrieve the chains you can use for Safe{Wallet} and their corresponding chain IDs, call List enabled chains and specify the query parameters as follows:
wallet_type: SmartContract.
wallet_subtype: Safe{Wallet}.
Sample code in Python
import jsonimport cobo_waas2from cobo_waas2 import ( WalletType, WalletSubtype,)configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret api_private_key="<YOUR_API_SECRET>", # Use the development environment host="https://api.dev.cobo.com/v2")# Enter a context with an instance of the API clientwith cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsApi(api_client) try: # Query enabled chains api_response = wallet_api_instance.list_enabled_chains( wallet_type=WalletType.SMARTCONTRACT, wallet_subtype=WalletSubtype.SAFE_WALLET ) print(f"The response of WalletsApi->list_enabled_chains:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling WalletsApi->list_enabled_chains, %s\n", e)
If you want to use a chain that is not already on the list, you need to enable the chain first on Cobo Portal. To learn how to do so, see Transfer (deposit / withdraw).If you have reached the limit on the number of chains you can use, consider upgrading your pricing plan.
To retrieve the tokens you can use for Safe{Wallet} and their corresponding token IDs, call List enabled tokens and specify the query parameters as follows:
wallet_type: SmartContract.
wallet_subtype: Safe{Wallet}.
chain_ids: Specify the chain of your choice. You can also leave this parameter empty to query enabled tokens on all chains.
Sample code in Python
import jsonimport cobo_waas2from cobo_waas2 import ( WalletType, WalletSubtype,)configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret api_private_key="<YOUR_API_SECRET>", # Use the development environment host="https://api.dev.cobo.com/v2")# Enter a context with an instance of the API clientwith cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsApi(api_client) try: # Query enabled tokens api_response = wallet_api_instance.list_enabled_tokens( wallet_type=WalletType.SMARTCONTRACT, wallet_subtype=WalletSubtype.SAFE_WALLET ) print(f"The response of WalletsApi->list_enabled_tokens:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling WalletsApi->list_enabled_tokens, %s\n", e)
To allow Delegates to perform single-signature operations, you must set up on-chain transaction policies on Cobo Portal to automatically approve certain transactions initiated by the Delegates. In this guide, we will use the MPC Wallet address you have prepared in the Prerequisites section as the Delegate.
Configure policies to automatically approve token withdrawals and contract calls initiated via the MPC Wallet. Refer to the provided screenshot as an example.
A multi-sig confirmation from Safe signers is required. Click Submit to initiate the multi-sig transaction.
Follow the instructions in Deposit assets to deposit tokens into your Safe{Wallet}.After depositing tokens to the addresses you have generated, you can track the status of your deposit using one of the following two options. Compared with using API to query the transaction status, webhooks can give you real-time notifications and are thus the recommended option.
Option 1: Use webhooks for real-time notifications
Webhook is an essential mechanism for the WaaS service to communicate with your application. After you register a webhook endpoint on Cobo Portal, the WaaS service sends push messages to the designated URL when an event occurs.To learn how to set up a webhook endpoint and register it on Cobo Portal, refer to Introduction to webhooks and callbacks.To track the status of your deposit, you can subscribe to the following webhook event types:
To query the status of a deposit transaction, call the List all transactions operation and set the query parameters as follows:
types: Deposit.
statuses: Confirming, Completed. If you are depositing from an external address, you will be able to query the transaction details when the transaction is waiting for the required number of confirmations or when it is successfully executed.
wallet_ids: The ID of the wallet you have created in the first step. You can get the wallet ID from the wallet list on Cobo Portal.
Sample code in Python
import jsonimport uuidimport cobo_waas2from cobo_waas2 import ( CreateAddressRequest, AddressEncoding, TransferParams, TransferSource, MpcTransferSource, WalletSubtype, TransferDestination, AddressTransferDestination, TransferDestinationType, AddressTransferDestinationAccountOutput,)configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret. api_private_key="<YOUR_API_SECRET>", # Use the development environment. host="https://api.dev.cobo.com/v2")# Enter a context with an instance of the API clientwith cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class transaction_api_instance = cobo_waas2.TransactionsApi(api_client) try: # List deposit transactions api_response = transaction_api_instance.list_transactions( types="Deposit", statuses="Confirming, Completed", wallet_ids="<YOUR_WALLET_ID>" ) print("The response of TransactionsApi->list_transactions:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling TransactionsApi->list_transactions, %s\n", e)
To enhance the security of your transactions, it is highly recommended that you set up a callback endpoint to receive and approve withdrawal requests. Once you initiate a withdrawal using the WaaS 2.0 API, the callback endpoint will receive a callback message containing the transaction details. The transaction will proceed only if you approve the withdrawal request.To learn how to set up a callback endpoint and register it on Cobo Portal, refer to Introduction to webhooks and callbacks.
To withdraw tokens from your Safe{Wallet}, you should first get its wallet ID from Cobo Portal. Hover over the wallet in the wallet list, copy the wallet ID, and save it for future reference.
Call List Delegates to retrieve the available Delegates. Specify the parameters and properties as follows:
Path:
wallet_id: The wallet ID of your Safe{Wallet}.
Request body:
request_type: Transfer
Call Transfer token to initiate the withdrawal with the Delegate. Specify the properties in the request body as follows:
request_id: Use a unique ID to track the transaction request.
source:
source_type: Safe{Wallet}
wallet_id: The wallet ID of your Safe{Wallet}.
address: The address of your Safe{Wallet}. You can call the Get wallet information operation to retrieve the address.
delegate: The information of the Delegate. You can call the List Delegates operation to retrieve the applicable Delegates.
token_id: The token ID.
destination:
destination_type: Address
account_output
address: The receiving address.
memo: The memo, if applicable.
amount: The transfer amount.
category_names: The custom category for you to identify your transactions.
description: The description of the transfer.
Sample code in Python
import jsonimport uuidimport cobo_waas2configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret api_private_key="<YOUR_API_SECRET>", # Use the development environment host="https://api.dev.cobo.com/v2")def get_delegate(wallet_id, request: cobo_waas2.SafeWalletDelegates):# Enter a context with an instance of the API client with cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsSmartContractWalletsApi(api_client) try: # Call the List Delegates operation to retrieve available Delegates api_response = wallet_api_instance.list_safe_wallet_delegates( wallet_id=wallet_id, safe_wallet_delegates=request ) if not api_response: raise Exception("No delegate found") print("The response of WalletsApi->list_safe_wallet_delegates:") print(json.dumps(api_response[0].to_dict(), indent=2)) # Return the first Delegate return api_response[0] except Exception as e: print("Exception when calling WalletsApi: %s\n", e)def get_wallet(wallet_id) -> cobo_waas2.SafeWallet: with cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsApi(api_client) try: # Call the Get wallet information operation to retrieve the wallet information, including the wallet address api_response = wallet_api_instance.get_wallet_by_id( wallet_id=wallet_id ) print("The response of WalletsApi->get_wallet_by_id:") print(json.dumps(api_response.to_dict(), indent=2)) return api_response.actual_instance.actual_instance except Exception as e: print("Exception when calling WalletsApi: %s\n", e)token_id = "<TOKEN_ID>"# Enther the receiving addressreceiver_address = "<TARGET_ADDRESS>"# Enter the wallet ID found on Cobo Portal wallet_id = "<YOUR_WALLET_ID>"# Enter the amount of tokens you want to transferamount = "<AMOUNT>"transfer_request = cobo_waas2.SafeWalletDelegates( actual_instance=cobo_waas2.SafeWalletDelegatesTransfer( request_type=cobo_waas2.EstimateFeeRequestType.TRANSFER, token_id=token_id, address=receiver_address, ) )# Retrieve a list of available Delegatesdelegate = get_delegate(wallet_id, transfer_request)# Retrieve detailed information about the Safe{Wallet}wallet = get_wallet(wallet_id)with cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.TransactionsApi(api_client) try: # Initiate token transfer through a Delegate api_response = wallet_api_instance.create_transfer_transaction( cobo_waas2.TransferParams( request_id=str(uuid.uuid4()), # Set the sending address and the Delegate source=cobo_waas2.TransferSource( actual_instance=cobo_waas2.SafeTransferSource( source_type=cobo_waas2.WalletSubtype.SAFE_WALLET, wallet_id=wallet_id, address=wallet.safe_address, delegate=delegate, ) ), token_id=token_id, # Set the receiving address and withdrawal amount destination=cobo_waas2.TransferDestination( actual_instance=cobo_waas2.AddressTransferDestination( destination_type=cobo_waas2.TransferDestinationType.ADDRESS, account_output=cobo_waas2.AddressTransferDestinationAccountOutput( address=receiver_address, amount=amount, ), ), ), category_names=["<CATEGORY_NAME>"], description="<DESCRIPTION>", ) ) print("The response of TransactionsApi->create_transfer_transaction:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling WalletsApi: %s\n", e)
The response of the withdrawal request is as follows. Record the transaction ID as you will use it in the following steps.
If you have set up a callback endpoint, after you initiate the withdrawal transaction, your callback endpoint will receive a message containing the transaction details. Check if the transaction meets expectations, and respond with a success status code (200 or 201) and a response body of ok to approve the transaction. To learn more about handling a callback message, see Handle messages.
In addition to webhook events, you can also call the Get transaction information operation to query the status of the transaction. Set the path parameter transaction_id to the transaction ID returned in the response of the previous withdrawal request.
Sample code in Python
import jsonimport uuidimport cobo_waas2from cobo_waas2 import ( CreateAddressRequest, AddressEncoding, TransferParams, TransferSource, MpcTransferSource, WalletSubtype, TransferDestination, AddressTransferDestination, TransferDestinationType, AddressTransferDestinationAccountOutput,)configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret. api_private_key="<YOUR_API_SECRET>", # Use the development environment. host="https://api.dev.cobo.com/v2")# Enter a context with an instance of the API clientwith cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class transaction_api_instance = cobo_waas2.TransactionsApi(api_client) try: # Get transaction by ID api_response = transaction_api_instance.get_transaction_by_id( transaction_id="<YOUR_TRANSACTION_ID>" ) print("The response of TransactionsApi->get_transaction_by_id:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling TransactionsApi->get_transaction_by_id, %s\n", e)
This section introduces how to call a smart contract using your Safe{Wallet} through the Delegate.
Get the wallet ID of your Safe{Wallet} from Cobo Portal. Hover over the wallet in the wallet list, copy the wallet ID, and save it for future reference.
Call List Delegates to retrieve the available Delegates. Specify the parameters and properties as follows:
Path:
wallet_id: The wallet ID of your Safe{Wallet}.
Request body:
request_type: ContractCall
Use the Call smart contract operation to call the smart contract with the Delegate. Specify the properties in the request body as follows:
request_id: Use a unique ID to track the transaction request.
chain_id: The ID of the chain on which your Safe{Wallet} operates. You can call the Get wallet information operation to retrieve the information.
source:
source_type: Safe{Wallet}
wallet_id: The wallet ID of your Safe{Wallet}.
address: The address of your Safe{Wallet}. You can call the Get wallet information operation to retrieve the information.
delegate: The information of the Delegate. You can call the List Delegates operation to retrieve the applicable Delegates.
destination:
destination_type: EVM_Contract
address: The destination address.
value : The transfer amount.
calldata: The transaction calldata.
category_names: The custom category for you to identify your transactions.
description: The description of the transfer.
Sample code in Python
import jsonimport cobo_waas2configuration = cobo_waas2.Configuration( # Replace `<YOUR_API_SECRET>` with your API secret api_private_key="<YOUR_API_SECRET>", # Use the development environment host="https://api.dev.cobo.com/v2")def get_delegate(wallet_id, request: cobo_waas2.SafeWalletDelegates):# Enter a context with an instance of the API client with cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsSmartContractWalletsApi(api_client) try: # Call the List Delegates operation to retrieve available Delegates api_response = wallet_api_instance.list_safe_wallet_delegates( wallet_id=wallet_id, safe_wallet_delegates=request ) if not api_response: raise Exception("No delegate found") print("The response of WalletsApi->list_safe_wallet_delegates:") print(json.dumps(api_response[0].to_dict(), indent=2)) return api_response[0] except Exception as e: print("Exception when calling WalletsApi: %s\n", e)def get_wallet(wallet_id) -> cobo_waas2.SafeWallet: with cobo_waas2.ApiClient(configuration) as api_client: # Create an instance of the API class wallet_api_instance = cobo_waas2.WalletsApi(api_client) try: # Call the Get wallet information operation to retrieve the wallet information, including the wallet address api_response = wallet_api_instance.get_wallet_by_id( wallet_id=wallet_id ) print("The response of WalletsApi->get_wallet_by_id:") print(json.dumps(api_response.to_dict(), indent=2)) return api_response.actual_instance.actual_instance except Exception as e: print("Exception when calling WalletsApi: %s\n", e)# Set the destination address contract_address = "<CONTRACT_ADDRESS>"# Set the transaction calldatadata = "<DATA>"# Set the transfer amountvalue = "<VALUE>"contract_call_request = cobo_waas2.SafeWalletDelegates( actual_instance=cobo_waas2.SafeWalletDelegatesContractCall( request_type=cobo_waas2.EstimateFeeRequestType.CONTRACTCALL, address=contract_address, calldata=data, value=value, ) )# Retrieve a list of available Delegates.delegate = get_delegate(wallet_id, contract_call_request)# Retrieve detailed information about the Safe{Wallet}.wallet = get_wallet(wallet_id)with cobo_waas2.ApiClient(configuration) as api_client: wallet_api_instance = cobo_waas2.TransactionsApi(api_client) try: # Call the smart contract api_response = wallet_api_instance.create_contract_call_transaction( cobo_waas2.ContractCallParams( request_id=str(uuid.uuid4()), chain_id=wallet.chain_id, source=cobo_waas2.ContractCallSource( actual_instance=cobo_waas2.SafeContractCallSource( source_type=cobo_waas2.ContractCallSourceType.SAFE_WALLET, wallet_id=wallet_id, address=wallet.safe_address, delegate=delegate, ) ), destination=cobo_waas2.ContractCallDestination( actual_instance=cobo_waas2.EvmContractCallDestination( destination_type=cobo_waas2.ContractCallDestinationType.EVM_CONTRACT, address=contract_address, calldata=data, value=value, ), ), category_names=["<CATEGORY_NAME>"], description="<DESCRIPTION>", ) ) print("The response of TransactionsApi->create_contract_call_transaction:") print(json.dumps(api_response.to_dict(), indent=2)) except Exception as e: print("Exception when calling TransactionsApi: %s\n", e)
The response of the contract call request is as follows. You can use the transaction ID from the response to query the transaction status by calling the Get transaction information operation.