Withdraw Assets
To withdraw assets from an withdrawal wallet, the caller must to provide an unique order_id for each request, the CYBAVO SOFA system will send the callback with the unique order_id when the withdrawal is success (from in pool
state to in chain
state).
By default, the withdraw API will perform the address check to verify that the outgoing address is good or not. If the address in the request is marked as a problematic address, the request will be aborted. The error message will identify the problematic addresses. Set the ignore_black_list
to true to skip the address check.
The withdrawal API can also interact with the contracts (ERC/BEP 721/1155) deployed in the SOFA system.
Request
POST /v1/sofa/wallets/{WALLET_ID}/sender/transactions
Withdrawal Wallet
Deposit-withdrawal Wallet
Delegated Wallet
The order_id must be prefixed. Find prefix from corresponding wallet detail on web control panel.
If withdraw BNB or XRP, this API will check whether the destination addresse needs memo / destination tag or not. If the address does need memo / destination tag, the API will fail without memo / destination tag specified.
Post Body
Field | Type | Note | Description |
---|---|---|---|
order_id | string | required, max 255 chars |
Specify an unique ID, order ID must be prefixed |
address | string | required | Outgoing address (address must be a contract address, if the contract_abi is not empty) |
amount | string | required | Withdrawal amount |
contract_abi | string | required, if calls contract ABI | Specify the ABI method and the parameters, in the format ABI_method:parameters |
memo | string | optional | Memo on blockchain (This memo will be sent to blockchain). Refer to Memo Requirement |
user_id | string | optional | Specify certain user |
message | string | optional | Message (This message only savced on CYBAVO, not sent to blockchain) |
block_average_fee | int | optional, range 1~100 |
Use average blockchain fee within latest N blocks. This option does not work for XRP, XLM, BNB, DOGE, EOS, TRX, ADA, DOT and SOL cryptocurrencies. |
manual_fee | int | optional, range 1~2000 |
Specify blockchain fee in smallest unit of wallet currency (For ETH/BSC/HECO/OKT/OP/ARB/CELO/FTM/PALM, the unit is gwei. The unit returned by the Query Average Fee API is wei, divided by 1000000000 to get the correct unit. . This option does not work for XRP, XLM, BNB, DOGE, EOS, TRX, ADA, DOT and SOL cryptocurrencies. |
token_id | string | optional | Specify the token ID to be transferred |
from_address | string | required, for delegated wallet | Specify the delegated address for the request |
from_address_index | int64 | required, for delegated wallet | Specify the corresponding index of the from_address |
ignore_gas_estimate_fail | boolean | optional, default false |
FOR DEBUG PURPOSE ONLY. After setting, the ABI EVM gas estimation will not be performed(Apply to individual order). |
ignore_black_list | boolean | optional, default false |
After setting, the address check will not be performed. Apply to all orders. |
The order_id must be prefixed. Find prefix from corresponding wallet detail on web control panel
block_average_fee and manual_fee are mutually exclusive configurations. If neither of these fields is set, the fee will refer to corresponding withdrawal policy of the withdrawal wallet.
The format of the contract_abi
is ABI_method:hex_parameters
, for example: create:0x00000000000000000000000000000000000000000000000000000000000013880000
000000000000000000000000000000000000000000000000000000000400000000000000000
0000000000000000000000000000000000000000000000000. The parameters must be encoded by
web3.eth.abi.encodeParameters() of web3.js.
Only mapped wallets can use contract_abi
to call ABI on smart contracts.
Only ERC721/1155 token wallet can use token_id
to transfer token. For ERC721 wallets, if token_id
is specified, the amount will be treated as 1.
The block_average_fee
and manual_fee
do not work for XRP, XLM, BNB, DOGE, EOS, TRX, ADA, DOT and SOL cryptocurrencies.
Response Body
Field | Type | Description |
---|---|---|
results | array | Array of withdraw result (order ID/withdraw transaction ID pair), if succeeds |
An example response of the request contains problematic addresses:
{
"error_code": 827,
"error": "Outgoing address in black list, abort transaction",
"blacklist": {
"0x83eE561B2aBD000FF00d6ca22f38b29d4a760d4D": [
"Involve phishing activity",
"Involve cybercrime related"
]
}
}
The response includes the following parameters:
Field | Type | Description |
---|---|---|
error_code | int | The error code |
error | string | The error message |
blacklist | object | The object describes all problematic addresses and their causes. |
Error Code
HTTP Code | Error Code | Error | Message | Description |
---|---|---|---|---|
403 | - | Forbidden. Invalid wallet ID | - | No wallet ID found |
403 | - | Forbidden. Header not found | - | Missing X-API-CODE , X-CHECKSUM header or query param t |
403 | - | Forbidden. Invalid timestamp | - | The timestamp t is not in the valid time range |
403 | - | Forbidden. Invalid checksum | - | The request is considered a replay request |
403 | - | Forbidden. Invalid API code | - | X-API-CODE header contains invalid API code |
403 | - | Invalid API code for wallet {WALLET_ID} | - | The API code mismatched |
403 | - | Forbidden. Checksum unmatch | - | X-CHECKSUM header contains wrong checksum |
403 | - | Forbidden. Call too frequently ({THROTTLING_COUNT} calls/minute) | - | Send requests too frequently |
403 | 385 | API Secret not valid | - | Invalid API code permission |
403 | 827 | Outgoing address in black list, abort transaction | - | Some outgoing addresses are blacklisted, examine the response ‘blacklist’ field for detailed information |
400 | 112 | Invalid parameter | - | Malformatted post body |
400 | 112 | Invalid parameter | the maximum request limit is exceeded | - |
400 | 955 | There is no content in your withdrawal request, please check your input | - | The post body of request doesn’t conform the API request specification |
400 | 703 | Operation failed | order_id must start with {ORDERID_PREFIX} | The prefix of order_id is incorrect |
400 | 703 | Operation failed | order_id: {ORDER_ID} - the character \ or / is prohibited | {ORDER_ID} is invalid |
400 | 703 | Operation failed | order_id: {ORDER_ID} is invalid | {ORDER_ID} is invalid |
400 | 703 | Operation failed | order_id: {ORDER_ID} - memo is required | The outgoing address of {ORDER_ID} needs memo specified |
400 | 703 | Operation failed | order_id: {ORDER_ID} - destination tag is required | The outgoing address of {ORDER_ID} needs destination tag specified |
400 | 703 | Operation failed | order_id: {ORDER_ID} - invalid block_average_fee | The block_average_fee is out of range |
400 | 703 | Operation failed | order_id: {ORDER_ID} - invalid manual_fee | The manual_fee is out of range |
400 | 703 | Operation failed | order_id: {ORDER_ID} - from_address is required | from_address is a required parameter |
400 | 703 | Operation failed | order_id: {ORDER_ID} - from_address_index is required | from_address_index is a required parameter |
400 | 703 | Operation failed | order_id: {ORDER_ID} - from_address_index not match | from_address_index is not consistent with the index of the from_address |
400 | 703 | Operation failed | order_id: {ORDER_ID} - invalid from_address | from_address does not exist |
400 | 703 | Operation failed | order_id: {ORDER_ID} - from_address not support | from_address cannot be used in non-delegated wallets |
400 | 399 | Duplicated entry: {ORDER_ID} | - | The {ORDER_ID} is duplicated |
400 | 945 | The max length of BNB memo is 256 chars | - | Reached the limit of the length of BNB memo |
400 | 946 | The max length of EOS memo is 128 chars | - | Reached the limit of the length of EOS memo |
400 | 947 | The max length of XRP destination tag is 20 chars | - | Reached the limit of the length of XRP destination tag |
400 | 948 | The max length of XLM memo is 20 chars | - | Reached the limit of the length of XLM memo |
400 | 818 | Destination Tag must be integer | - | Wrong XRP destination tag format |
400 | 944 | The max length of order id is 255 chars | - | Reached the limit of the length of order_id |
400 | 703 | Operation failed | Detailed error message | Failed to connect to authentication callback URL |
400 | 703 | Operation failed | HTTP resp failed {HTTP_CODE}, body: {RESPONSE_BODY} | The authentication callback URL returned status code other than 200 or 400 |
400 | 703 | Operation failed | Unrecognized response: {RESPONSE_BODY}, ‘OK’ expected | The returned status code is 200 but the body is not OK |
400 | 703 | Operation failed | request IP ({IPv4}) not in ACL | The request IP not in the withdrawal ACL |
400 | 703 | Operation failed | invalid amount {AMOUNT} | The requested amount is not a valid number |
400 | 703 | Operation failed | invalid amount decimals {AMOUNT} | The decimals of the requested amount exceeds the valid range |
400 | 955 | There is no content in your withdrawal request, please check your input | - | No orders found in the request that may be caused by an incorrectly formatted post body |
404 | 304 | Wallet ID invalid | - | The wallet is not allowed to perform this request |
404 | 312 | Policy not found | no active withdrawal policy found | No active withdrawal policy found |
Sample Request
API
/v1/sofa/wallets/68451/sender/transactions
Post Body
{
"requests": [
{
"order_id": "888888_1",
"address": "0x83eE561B2aBD000FF00d6ca22f38b29d4a760d4D",
"amount": "0.0001",
"memo": "memo-001",
"user_id": "USER01",
"message": "message-001",
"block_average_fee": 5
},
{
"order_id": "888888_2",
"address": "0xf16B7B8900F0d2f682e0FFe207a553F52B6C7015",
"amount": "0.0002",
"manual_fee": 50
},
{
"order_id": "888888_3",
"address": "0x9638fa816ccd35389a9a98a997ee08b5321f3eb9",
"amount": "0.0002",
"message": "message-003"
},
{
"order_id": "888888_4",
"address": "0x2386b18e76184367b844a402332703dd2eec2a90",
"amount": "0",
"contract_abi":"create:0x000000000000000000000000000000000000000000000000000000000000138800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000",
"user_id": "USER04",
"ignore_gas_estimate_fail": true
},
{
"order_id": "888888_5",
"address": "0x6A2969E4496d5b27967a68b411D7e0218943c1B6",
"amount": "1",
"token_id": "985552421"
}
],
"ignore_black_list": false
}
For delegated wallet
{
"requests": [
{
"order_id": "132342_1001",
"address": "0x480A8507C63A27f05cd29BfB3Bb4F7bA1B6ba102",
"from_address": "0xEb0e93980Cd0C5D3868B7da32A5604085f9F813C",
"from_address_index": 7,
"amount": "0.1"
},
{
"order_id": "132342_1002",
"address": "0xfe67e5b57ecccaa3f95bb90466651391024f25fc",
"amount": "0",
"contract_abi": "transferFrom:0x0000000000000000000000006a2969e4496d5b27967a68b411d7e0218943c1b60000000000000000000000001ea22ed0347e6c9f852cfcbefe752a026450164b00000000000000000000000000000000000000000000000000000000000026ac",
"from_address": "0x1EA22Ed0347E6C9f852cfcBEFE752A026450164b",
"from_address_index": 20
}
]
}
Response Body
{
"results": {
"1": 20000000001,
"2": 20000000002
}
}
Sample cURL Command
curl -X POST -H "Content-Type: application/json" -d '{"requests":[{"order_id":"888888_1","address":"0x60589A749AAC632e9A830c8aBE042D1899d8Dd15","amount":"0.0001","memo":"memo-001","user_id":"USER01","message":"message-001"},{"order_id":"888888_2","address":"0xf16B7B8900F0d2f682e0FFe207a553F52B6C7015","amount":"0.0002","memo":"memo-002","user_id":"USER01","message":"message-002"}]}' \
http://localhost:8889/v1/mock/wallets/{WALLET_ID}/sender/transactions