Skip to main content

Memo integration guide

The memo feature adds an optional memo requirement for FT4 transfers, ensuring that certain accounts mandate memos for all incoming transfers. This feature is useful for attaching textual annotations to blockchain transactions, making it especially beneficial for exchange integrations or wallets that manage shared accounts and require transaction context for identification.

Key components

Operations

  1. Enable memo requirement
    • Operation: enable_transfer_memo()
    • Description: Activates memo enforcement for an FT4 account, requiring that all incoming transfers include a memo.
  2. Disable memo requirement
    • Operation: disable_transfer_memo()
    • Description: Deactivates memo enforcement, allowing incoming transfers without a memo.
  3. Add a memo
    • Operation: memo(text)
    • Description: Attaches a textual memo to a transfer.
    • Constraints:
      • The memo text must be between 1 and 50 characters.
      • This operation is only valid when paired with an ft4.transfer operation targeting accounts that require memos.

Queries

Check memo requirement

  • Query: does_account_require_memo(account_id: byte_array): boolean
  • Description: Checks if an FT4 account enforces memo requirements for incoming transfers.
tip

For the full implementation of the memo feature, refer to the source code here.

Example workflows

FT4 client-side integration

Receiver account should allow to add memo to transactions:

//... code for initialization
await session.call(op("enable_transfer_memo"));

Sender account of transfer transactions can add memo if it was enabled by receiver:

// Initialization code
const tb = session.transactionBuilder();
tb.add({name: "memo", args: [memo]}, { authenticator: noopAuthenticator })
.add(transfer(<ACCOUNT_ID>, <assetId>, <amount>))
.buildAndSend();

Find complete instructions for FT4 client-side initialization and asset transfers here.

Rell test scripts

Enable memo requirement

rell.test.tx()
.op(enable_transfer_memo())
.op(test.ft_auth_operation_for(alice.keypair.pub))
.sign(alice.keypair)
.run();

Transfer with memo

rell.test.tx()
.op(memo("For invoice #1234"))
.op(test.ft_auth_operation_for(alice.keypair.pub))
.op(assets.external.transfer(bob.account_id, asset.id, 100))
.sign(alice.keypair)
.run();

Query memo requirement

val requires_memo = does_account_require_memo(bob.account_id);
print("Bob's account requires memo: %s".format(requires_memo));

Invalid transfer (no memo)

rell.test.tx()
.op(test.ft_auth_operation_for(alice.keypair.pub))
.op(assets.external.transfer(bob.account_id, asset.id, 100))
.sign(alice.keypair)
.run_must_fail("Transfers to account ... require a memo");
tip

For the complete set of Rell test examples, check here.