16 June 2024
—
The Zucoin wallet app supports transfer codes from third parties, which can automatically prepare a transfer.
A transfer code that pre-fills sender-side transfer details is known as a pre-formed transfer code.
It gives the sender automatic instructions to help them start a transfer.
For safety, the sender must confirm any pending transaction initiated by a transfer code.
The sender receives a confirmation screen before the resulting transfer begins.
A pre-formed sender transfer code can specify the following values:
incoming_data.inner_state_amountmessage) that can be copied into the transaction itselfuser_share_message) that stays in the transfer code onlyExplicit sender selection is optional. By default, a pre-formed sender transfer code uses type set to sender_create_transaction. In this mode, the sender wallet is set by the wallet or app flow that first gets the transfer code and is treated as the sender.
If your service already knows which wallet must send the transfer, set type to sender_create_transaction_explicit and add incoming_data.sender_key_public__base64urlsafe with that wallet's public key. When this explicit type is used, the sender key is required and is validated like the receiver key.
This is useful for account-based, membership, marketplace, and bulk-transfer flows where a transfer code needs to be tied to a specific member, seller, sale wallet, or locally stored sender wallet. It removes ambiguity when more than one wallet might exist, helps the app load the correct wallet state and history, and avoids a generic request being prepared against the wrong sender wallet.
Use the default sender_create_transaction type and omit sender_key_public__base64urlsafe when any sender wallet should be able to act on the request. The sender still has to confirm the prepared transfer in the Zucoin wallet app either way.
Pre-formed sender transfer codes can include the optional expiry__unix_time_secs property inside incoming_data. Use a string containing a whole-number Unix timestamp in seconds.
In Splitchain, Transfer Code v1 validates this field before the wallet accepts the transfer code. The timestamp must be after the current Splitchain time block and no more than 59,999,880 seconds (999,998 minutes) ahead.
For sender-create transfer codes, the wallet transfer preparation keeps this expiry and writes it to the partial transaction when preparing a Transaction v2. In Transaction v2, the field belongs at inner.expiry__unix_time_secs and is validated as an optional whole-number string no more than 59,999,880 seconds after inner.unix_time_secs.
For receiver_confirm_partial_transaction transfer codes, the actual transaction expiry must already be inside incoming_data.partial_transaction.inner.expiry__unix_time_secs. Do not rely on a wrapper-level incoming_data.expiry__unix_time_secs as the transaction expiry, because that wrapper field is not kept after filtering.
Omit the field when the transaction should not expire; do not send an empty expiry field. Transfer Code v1 uses the same incoming_data.expiry__unix_time_secs field name for sender-create requests, while older amount conversion and origin details use the v1 inner_state_metadata structure.
Transfer-code message fields are plain-text context for a transfer request. They are not smart assets or smart contracts.
There are two optional message fields: message and user_share_message. They behave differently.
message is optional transaction message text. In Splitchain, if a sender-create Transfer Code v1 includes incoming_data.message, it is validated as a non-empty string up to 256 characters. When a sender-create Transfer Code v1 is used to prepare a Transaction v2 partial transaction, the wallet transfer preparation copies that value into inner.message. Once it is in inner.message, it is part of the Transaction v2 data that is validated, filtered, signed, and may be stored or cached with the transaction.
user_share_message is optional transfer-code-only text that wallet or app flows can use for sender-facing instructions. In Splitchain, if a sender-create transfer code includes it, it is validated as a non-empty string up to 300 characters with a restricted plaintext character set, and the filtered transfer code keeps the trimmed value. It is not copied into inner.message and is not part of the signed transaction data.
For receiver_confirm_partial_transaction transfer codes, wrapper-level fields such as incoming_data.message and incoming_data.user_share_message are not kept after filtering. If a receiver-confirm transfer code needs a transaction message, that message must already be inside incoming_data.partial_transaction.inner.message.
Using transfer codes helps keep the network leaner and simpler by keeping less information on it.
Transfer codes also paved the way for two-factor transactions to be the default behavior on the Splitchain network, improving safety by requiring both a sender and a receiver to accept a transaction.
A website can generate a transfer code for a sender, with pre-filled details to start the transaction process.
The following code example creates a simple request to pay a bill:
$test_transfer_code_for_sender = [
'version' => '1',
// Optional explicit sender, when transfer is for an exact sender wallet address
// 'type' => 'sender_create_transaction_explicit'
'type' => 'sender_create_transaction',
'incoming_data' => [
// Optional, required if type is "sender_create_transaction_explicit"
// 'sender_key_public__base64urlsafe' => 'BBBBB...',
// Receiver's wallet address, base64_urlsafe encoded
'receiver_key_public__base64urlsafe' => 'AAAAA...',
// Zucoin quantity to ask sender to transfer, as a string text number
'inner_state_amount' => '0.005',
// Optional, whole-number Unix timestamp in seconds
'expiry__unix_time_secs' => (string)(time() + 3600),
// Optional, copied into transaction inner->message when prepared
// 'message' => 'Invoice #1042',
// Optional, transfer-code-only sender instructions, not copied into the transaction
// 'user_share_message' => 'Custom message for sender to confirm here'
]
];
Now let's build a quick function that can automatically generate these pre-formed transfer codes:
<?php
/**
* Generate a pre-formed transfer code for a sender to use in
* initiating a transaction with a receiver
*
* @tip Use a sodium encryption library, e.g.
* https://www.php.net/manual/en/book.sodium.php is built into PHP
* 7.2 and above
*
* @returns A string encoded pre-formed transfer code on success
* and false on fail
*/
function generate_pre_formed_sender_transfer_code(
string $receiver_key_public__base64urlsafe,
string $inner_state_amount,
string $expiry__unix_time_secs = '',
string $sender_key_public__base64urlsafe = '',
string $message = '',
string $user_share_message = ''
) {
// $sender_key_public__base64urlsafe is optional. Leave it empty for a generic sender request.
// $message is optional transaction message text. Leave it empty if not needed.
// $user_share_message is optional transfer-code-only sender instruction text.
// @tip Example only, validate incoming values here
//...
$transfer_code_type = 'sender_create_transaction';
if ('' !== $sender_key_public__base64urlsafe)
{
$transfer_code_type = 'sender_create_transaction_explicit';
}
$pre_formed_transfer_code = [
'version' => '1',
'type' => $transfer_code_type,
'incoming_data' => [
// Receiver's wallet address, base64_urlsafe encoded
'receiver_key_public__base64urlsafe' => $receiver_key_public__base64urlsafe,
// Zucoin quantity to ask sender to transfer, as a string text number
'inner_state_amount' => $inner_state_amount
]
];
// Optional explicit sender mode, include only when the sender wallet is already known
if ('' !== $sender_key_public__base64urlsafe)
{
$pre_formed_transfer_code['incoming_data']['sender_key_public__base64urlsafe'] = $sender_key_public__base64urlsafe;
}
// Optional transaction message, copied into inner->message when prepared
if ('' !== $message)
{
$pre_formed_transfer_code['incoming_data']['message'] = $message;
}
// Optional transfer-code-only sender instructions, not copied into the transaction
if ('' !== $user_share_message)
{
$pre_formed_transfer_code['incoming_data']['user_share_message'] = $user_share_message;
}
// Optional, omit when the transaction should not expire
if ('' !== $expiry__unix_time_secs)
{
$pre_formed_transfer_code['incoming_data']['expiry__unix_time_secs'] = $expiry__unix_time_secs;
}
// Zucoin wallet app expects transfers to be encoded this way for reliable data transmission
$pre_formed_transfer_code_encoded =
sodium_bin2base64(
rawurlencode(
json_encode($pre_formed_transfer_code, JSON_THROW_ON_ERROR)
),
SODIUM_BASE64_VARIANT_URLSAFE
);
// Not needed, gets handled in Zucoin wallet app
$pre_formed_transfer_code_encoded = rtrim($pre_formed_transfer_code_encoded, '=');
// Done! Now give this to the sender. E.g. display it via a webpage
return $pre_formed_transfer_code_encoded;
}
Once the above logic completes successfully, you can pass this data to the sender using your preferred method (email, on-screen copy-paste code, on-screen QR code, SMS, push notification, etc).
When the sender pastes the pre-formed transfer code into their Zucoin wallet app, the sender will be asked to confirm the transaction.
Third-party systems usually have their own user flows. When needed, use the optional user_share_message property for sender-facing instructions about the next step. Use message only when the text should be copied into the transaction itself.
That's it—let us know what you build with it!
Disclaimer: Of course, this is not advice, financial or otherwise. It’s also important to consider the risks and challenges associated with any potential benefits.
Get periodic insights, news, offers + more, trusted by 1,000+ readers.
(By subscribing you agree to receive news + marketing emails, but we won't spam or sell your data!)