Chromia
Start Building

21 / 27Module 1: A Rell backend with FT accountsBeginner

Test the registration

Follow these steps to test the new module:

  1. Add a test file at src/test/registration_test.rell.

  2. Register the test module in chromia.yml by listing it under the modules:

src/chromia.yml
blockchains:  newschain:    test:      modules:        - test
  1. Open registration_test.rell, add the required imports, and declare the EVM address and private key the tests will use:
src/test/registration_test.rell
@test module;import registration. { register_user };import news_feed. { make_post, user, post };import lib.ft4.accounts. { single_sig_auth_descriptor };import lib.ft4.auth. { evm_signatures };import lib.ft4.core.accounts.strategies.open. { ras_open };import lib.ft4.external.accounts.{ add_auth_descriptor };import lib.ft4.external.accounts.strategies. { get_register_account_message };import lib.ft4.test.core.{ ft_auth_operation_for, evm_auth_operation_for, evm_sign };val evm_address = x"1337c28e95ce85175af66353fecccd676e3d273a";val evm_privkey = x"18e2d37cd5b51555c52d454c22608dee5e7151384f2d7b7bc21616e2eadc3e6f";
  1. Add a test case to registration_test.rell that registers an account with EVM signatures:
src/test/registration_test.rell
function test_evm_registration() {    val alice_auth_desc = single_sig_auth_descriptor(evm_address, set(["A", "T"]));    val alice_session_1 = rell.test.keypairs.alice;    val session1_auth_desc = single_sig_auth_descriptor(alice_session_1.pub, set(["S"]));    val strategy_op = ras_open(alice_auth_desc, session1_auth_desc);    val register_op = register_user("Alice");    val message = get_register_account_message(        strategy_op.to_gtx_operation(),        register_op.to_gtx_operation()    );    val signature = evm_sign(message, evm_privkey);    // Register account using evm address     rell.test.tx()        .op(evm_signatures([evm_address], [signature]))        .op(strategy_op)        .op(register_op)        .sign(alice_session_1)        .run();    assert_equals(user @ { } ( @sum 1 ), 1);    // Make post using session key    rell.test.tx()        .op(ft_auth_operation_for(alice_session_1.pub))        .op(make_post("My first post"))        .sign(alice_session_1)        .run();    assert_equals(post @ { } ( @sum 1 ), 1);        // Start a new session    val alice_session_2 = rell.test.keypairs.bob;    val session_auth_desc = single_sig_auth_descriptor(alice_session_2.pub, set(["S"]));    val add_auth_descriptor_operation = add_auth_descriptor(session_auth_desc);    // Add session token    rell.test.tx()        .op(evm_auth_operation_for(evm_privkey, add_auth_descriptor_operation))        .op(add_auth_descriptor_operation)        .sign(alice_session_2)        .run();    // Make another post using session key    rell.test.tx()        .op(ft_auth_operation_for(alice_session_2.pub))        .op(make_post("My second post"))        .sign(alice_session_2)        .run();    assert_equals(post @ { } ( @sum 1 ), 2);}

The test mimics a user who signs up with an EVM address and a matching signature. It does the following:

  • Builds an authentication descriptor for the EVM key carrying the "A" and "T" flags, which grant administrative and transfer access in the ft framework.
  • Generates a session keypair and a matching authentication descriptor for Alice (alice_session_1).
  • Produces the EVM registration signature with evm_sign, covering the operations the transaction will call.
  • Assembles a transaction containing the register_account operations and signs it with Alice's session keypair.
  • Checks that the registration succeeded.

Posting with session keypair

As an extra check, the next test uses the session keypair to create a post:

rell
    // Make a post using the session keypair    rell.test.tx()        .op(ft_auth_operation_for(alice_session_1.pub))        .op(make_post("My first post"))        .sign(alice_session_1)        .run();    assert_equals(post @ { } ( @sum 1 ), 1);

Here the session keypair signs the transaction, and ft_auth_operation_for from the ft test module supplies the authentication properties. The test:

  • Builds a new transaction, using ft_auth_operation_for to add the authentication properties.
  • Signs it with Alice's session keypair.
  • Checks that the post was created.

Logging in with a new session keypair

To confirm the behavior holds across logins, the following test simulates a user signing in a second time. The user generates a fresh session keypair and registers it with the dapp through the ft4.add_auth_descriptor operation:

rell
    // Start a new session    val alice_session_2 = rell.test.keypairs.bob;    val session_auth_desc = single_sig_auth_descriptor(alice_session_2.pub, set(["MySession"]));    val add_auth_descriptor_operation = add_auth_descriptor(session_auth_desc);    // Add a session token    rell.test.tx()        .op(evm_auth_operation_for(evm_privkey, add_auth_descriptor_operation))        .op(add_auth_descriptor_operation)        .sign(alice_session_2)        .run();    // Make another post using the session key    rell.test.tx()        .op(ft_auth_operation_for(alice_session_2.pub))        .op(make_post("My second post"))        .sign(alice_session_2)        .run();    assert_equals(post @ { } ( @sum 1 ), 2);

The test:

  • Generates a new session keypair and defines a single-signature auth descriptor with the "MySession" flag.
  • Builds a transaction that adds the new session key.
  • Signs that transaction with the EVM private key.
  • Creates another post and checks that it was created.

To learn more about how FT4 works, including authentication descriptors and session handling, see the FT4 Accounts and Tokens documentation.

You now have a module that registers user accounts through an EVM wallet, along with tests that confirm it works.

Written for this site from Chromia’s public course. Code samples are the course’s own.