Comment on page


Learn how to transfer assets in your Arc application.
The transfer operation allows for the transfer of any asset between two users. The action can be executed via a single API call. To facilitate the process Arc offers an auxiliary endpoint for fetching transfer data. The details fetched from the transfer data endpoint must be user signed and subsequently submitted by the application to Arc.
Only assets enabled in your application can be used for transfer operations.
The following steps illustrate the typical flow of a transfer operation in Arc:
  1. 1.
    The user initiates the transfer process by sending a GET request to the Application's server for transfer details. This is necessary due to the fact that the user cannot access the Arc API directly and should therefore proxy the request through the application's back-end.
  2. 2.
    The Application receives the user's request and forwards the GET request to the Arc server endpoint /api/transfers/details to retrieve the transfer details.
  3. 3.
    Arc receives the Application's request, computes the transfer details, and sends the details back to the Application.
  4. 4.
    Application receives the transfer details from Arc and sends them back to User.
  5. 5.
    The user generates and signs a transfer based on the received transfer details and sends a POST request to Application to execute the transfer.
  6. 6.
    Application receives the transfer request from the user and forwards it to the /api/transfers endpoint of the Arc API.
  7. 7.
    Arc receives the transfer request from the application, performs validation actions and updates the balances for the users involved in the transfer.
  8. 8.
    The application sends a response back to the user indicating that the transfer was successful.
Transfer flow

Get transfer details

In order to facilitate fetching the necessary details to fill the transfer form, Arc exposes an HTTP Post endpoint under /api/transfers/details with the following spec:
Get Transfer Details
The details contain all the information required to compute the transaction hash to be signed using the user STARK key. These include internal asset information used by the StarkEx engine as well as auxiliary cryptographic variables and transfer-specific data to ensure the user signs the critical fields for this operation.
For convenience, Arc already provides a pre-computed hash in the singablePayload field of the response. Nonetheless, if the user wants to recompute the hash itself our SDKs provide this functionality:
// init stark express client
const arcClient: Client = await ClientFactory.createCustomClient(
{ url: DefaultProviderUrls.TESTNET } as IProvider,
// transfer asset
const transferData: TransferDetailsModel = {
senderUserId: '5a35dbab-02ba-4ed4-b799-59daa263488b',
receiverUserId: '5a35dbab-02ba-4ed4-b799-59daa263488c',
assetId: 'ba072cae-a82d-4c9b-b663-1f98cc8c38d1',
senderDataAvailabilityMode: DataAvailabilityModes.Validium,
receiverDataAvailabilityMode: DataAvailabilityModes.Validium,
amount: '214159265350000',
const transferDetailsDtoResponseData: ResponseData<TransferDetailsDto> =
await arcClient.transfers().getTransferDetails(transferData);
const transferDetailsDto = transferDetailsDtoResponseData.result;
Using the StarkEx.Crypto.SDK package:
var transfer = new EncodeTransferWithFeesModel(
new BigInteger("34"),
new BigInteger("21"),
new BigInteger("593128169"),
new BigInteger("2154549703648910716"),
new BigInteger("7"),
// "5359c71cf08f394b7eb713532f1a0fcf1dccdf1836b10db2813e6ff6b6548db"
var messageHash = target.EncodeTransferWithFees(transfer);
// Transfer payload hash with StarkWare's Python resources
from .starkex_messages import get_transfer_msg
def read_transfer_data(transfer_dict: dict) -> Dict[str, int]:
Transfers a dict of raw data representing a transfer, to an input dict for the
`get_transfer_msg` function.
return {
'amount': int(transfer_dict['amount']),
'nonce': int(transfer_dict['nonce']),
'sender_vault_id': int(transfer_dict['sender_vault_id']),
'token': int(transfer_dict['token'], 16),
'receiver_vault_id': int(transfer_dict['target_vault_id']),
'receiver_public_key': int(transfer_dict['target_public_key'], 16),
'expiration_timestamp': transfer_dict['expiration_timestamp']
key = 'transfer_order'
data = read_transfer_data(data_file[key])
singablePayload = get_transfer_msg(**data)
Arc already returns the singablePayload in the /api/transfers/details endpoint but we recommend our users to recompute the singablePayload to minimize trust assumptions.

Sign transfer details

To generate the required transfer signature, asked in the first form under /api/v1/transfers, users should sign the signablePayload with their private STARK key. In order to do this, you can use StarkEx JS crypto SDK, our own SDK in C#.
// init cryptoUtils
const cryptoUtils: ICryptoUtils = new CryptoUtils();
await cryptoUtils.init(message);
const signature = cryptoUtils.transfers().signTransfer(transferDetailsDto);
Using the StarkEx.Crypto.SDK package:
var messageHash = "5359c71cf08f394b7eb713532f1a0fcf1dccdf1836b10db2813e6ff6b6548db"
var privateKey = "2dccce1da22003777062ee0870e9881b460a8b7eca276870f57c601f182136c";
var signer = CreateStarkExSigner();
// R: "5f496f6f210b5810b2711c74c15c05244dad43d18ecbbdbe6ed55584bc3b0a2",
// S: "4e8657b153787f741a67c0666bad6426c3741b478c8eaa3155196fc571416f3"
var signature = signer.SignMessage(messageHash, privateKey);
# Signing payload hash with StarkWare's Python resources
from .signature import sign
r, s = sign(transfer_msg, private_key)

Submit transfer request

To transfer assets between two users, applications can issue an HTTP POST request /api/v1/transfers with the following body:
Transfer Asset
If successful, this endpoint will return the vaults updated by the transfer operation.