Query Contract UI | Developers

Query Contract UI

Estimated reading time: 5 minutes

The previous section showed how to display a single screen. This section shows how to display the rest of the screens. Similarly to the section before, the display itself is handled by the Ethereum App. The only thing the plugin needs to do is determine what strings need to be displayed.

Each screen has a screen number (also called screenIndex). When the Ethereum App needs to display a screen, it just calls the plugin and gives it the screenIndex. The plugin fills msg->title and msg->msg accordingly. The Ethereum App then displays the strings. If the user presses the right button or the left button, the Ethereum App increments or decrements screenIndex and calls the plugin with the updated screenIndex. Here is the flow:

sequenceDiagram Eth App -> Plugin: We're on screen 1 Note right of Plugin: Determine what
needs to be displayed Plugin --> Eth App: Note left of Eth App: User sees screen Note left of Eth App: User presses
right button Eth App -> Plugin: We're on screen 2 Note right of Plugin: Determine what
needs to be displayed Plugin --> Eth App: Note left of Eth App: User sees screen Note left of Eth App: User presses
*left* screen Eth App -> Plugin: We're on-screen *1* Note right of Plugin: Determine what
needs to be displayed Plugin --> Eth App: Note left of Eth App: etc

We will use msg->title to fill the upper line and msg->msg to fill the bottom one.

|  Ledger  |  <- msg->title
|   Rocks   |  <- msg->msg

In our boilerplate example, this is what we want to display for a swap:

         0                    1                         2                <- screenIndex
|   Send     | Receive Min.|  Beneficiary |
| ETH 0.1  | USDT 300.12  | 0x37abc...  |

Let’s dive right into handle_query_contract_ui.c:

// Switch on `screenIndex`, and call some (yet-to-be-written) function
// to set the UI accordingly.
switch (msg->screenIndex) {
    case 0:
        set_send_ui(msg, context);
        break;
    case 1:
        set_receive_ui(msg, context);
        break;
    case 2:
        set_beneficiary_ui(msg, context);
        break;
    default:
        PRINTF("Received an invalid screenIndex\n");
        msg->result = ETH_PLUGIN_RESULT_ERROR;
        return;
}

Let’s start by writing set_send_ui.

static void set_send_ui(ethQueryContractUI_t *msg, context_t *context) {
    // Copy the "Send" in the upper line.
    strlcpy(msg->title, "Send", msg->titleLength);
    
    // The amount of ETH associated with this transaction is
    // located in `msg->pluginSharedRO->txContent->value.
    uint8_t *eth_amount = msg->pluginSharedRO->txContent->value.value;
    uint8_t eth_amount_size = msg->pluginSharedRO->txContent->value.length;

    // `amountToString` is a utility function that converts 
    //  a `uin256_t` to a string. Also, `18` and `ETH` refer
    //  to the number of decimals and to the ticker respectively.
    amountToString(eth_amount,
                eth_amount_size,
                18,
                "ETH",
                msg->msg,
                msg->msgLength);
}

We can write a similar function for set_receive_ui:

static void set_receive_ui(ethQueryContractUI_t *msg, context_t *context) {
    // Set the title
    strlcpy(msg->title, "Receive Min.", msg->titleLength);

    // This time use amountToString with the data stored in our context!
    amountToString(context->amount_received,
                   sizeof(context->amount_received),
                   context->decimals,
                   context->ticker,
                   msg->msg,
                   msg->msgLength);
}

And finally, we need to write set_beneficiary_ui. Remember, this screen is only shown if the recipient’s address doesn’t match the user’s address. This was done in handle_plugin_finalize, where we incremented numScreens if the addresses were different.

static void set_beneficiary_ui(ethQueryContractUI_t *msg, context_t *context) {
    // Set the upper line
    strlcpy(msg->title, "Beneficiary", msg->titleLength);

    // Prefix the address with `0x`.
    msg->msg[0] = '0';
    msg->msg[1] = 'x';

    // We need a random chainID for legacy reasons with `getEthAddressStringFromBinary`.
    // Setting it to `0` means it works with any chainID :)
    uint64_t chainid = 0;

    // Get the string format of the address stored in `context->beneficiary`. Store it in
    // `msg->msg`.
    getEthAddressStringFromBinary(
        context->beneficiary,
        (uint8_t *) msg->msg + 2,  // +2 because we've already prefixed with '0x'.
        msg->pluginSharedRW->sha3, // Used by the function to calculate the hash
        chainid);
}

And that’s it for your plugin. Now you have coded everything, it is time to test!


Did you find this page helpful?


How would you improve this page for developers?



Query Contract ID
Testing
Getting Started
Theme Features
Customization