Basis of Trial Accounts
A Trial Account is simply an account on NEAR that has a set of pre-defined restrictions that limit the methods that it can call. This is achieved by deploying a very small no-std Rust smart contract on it (~25 kb or 0.25 $NEAR) that acts as a proxy, or middleman, for any outbound calls it makes.
The contract deployed to the account exposes a method
execute that takes a set of actions as arguments, checks whether the actions are allowed, and then executes them. To achieve this middleman behavior, the Trial Account cannot have any full access keys (otherwise it could bypass the
execute method, and in turn, the restrictions). The account should only have one limited access key that can call the
execute method on its own contract.
Whenever a Trial Account wants to call a method on an external contract, say
nft_mint on the
nft.examples.testnet account, it needs to call
execute and pass in the desired function call as arguments. The contract will then check whether those actions are allowed and if they are, it will execute the desired behavior.
To help illustrate this behavior, the follow diagram shows the above scenario.
From the above, a Trial Account can be created by deployed a valid contract to an account that only has a limited access key on it with the correct permissions. This can all be achieved with a Function Call drop.
In order to create accounts ending with
.testnet, you'll need the
testnet accounts to create sub-accounts. This is done by calling the
create_account function on their contracts (the code is found here). This is exactly how regular linkdrops work, including Keypom.
create_account, a new sub-account is created with a full access key. This is close to the behavior we want for Trial Accounts but not exactly. In order to create a new account that has a limited access key and a contract deployed, you can call the
create_account_advanced function instead of
create_account, code found here. This function can accept
wasm for a contract, and limited access key arguments.
A Keypom function call drop can then be programmed to:
- Call the
- Pass in user provided args for the new account ID.
- Pass in the
wasmfor the contract to be deployed.
- Pass in the limited access key arguments to create a key that can call
executeon the newly created account.
- Once the account is created, Keypom will automatically call a setup method on the new account that will set the restrictions.
Keypom has abstracted away all these complexities using a simple ready-made function createTrialAccountDrop.
Understanding Trial Restrictions
There are 3 different restrictions that can be applied to a Trial Account:
- Callable contracts
- Callable methods
- Attached Deposits
As a trial funder, you have complete control over exactly which contracts a trial account can call. This can be any number of contracts and should be passed in using an array. For example, if you wanted the trial to only call methods on the
nft.examples.testnet contracts, you would pass in the following:
const callableContracts = [
Not only do you have full control over the contracts that a trial account can call, but you can also specify individual methods on a per-contract basis. In the above example, if you wanted the account to be able to call any method on the
v2.keypom.testnet contract, but only the
nft_transfer methods on the
nft.examples.testnet contract, you would pass in the following:
const callableMethods = [
* symbol is used to represent no restrictions on methods for a given contract.
Max Attachable Deposit
The last restriction that you can set on a given trial account is the maximum amount of $NEAR that can be attached to function calls for a given contract. In the above scenario, say you wanted to limit an account to the following restrictions:
- Attaching up to 5 $NEAR to any method on the
- Only attaching 1 yoctoNEAR to methods on the
You would pass in the following:
const maxAttachableDeposit = [
The final thing to understand about trial accounts is how they can be exited. While the account is in the trial state, it has restrictions and isn't usable in the wider ecosystem. As a funder, you can specify conditions that need to be met in order for the account to exit the trial state.
Trial Over Floor
The main condition that dictates how long an account will be in the trial state before it must exit is the trial floor. This is an amount of $NEAR that must be spent before the account is eligible to exit. The amount consists of both gas burnt as well as deposits to successful function calls.
For example, if an account attached 1 $NEAR to a function call and also burnt 75 TGas, it would be
1.0075 $NEAR closer to the floor. Overtime, as an account executes more and more transactions, it will come closer to the floor. Once the floor has been reached, the account will be eligible to exit.
It's important to note that once the floor has been met, the account can continue to execute transactions. Reaching the floor simply means that the account can exit the trial state (assuming all other conditions have been met).
If the funder chooses to, they can also specify a repay condition. This is an amount of $NEAR that must be paid back to them in order for the account to exit the trial state.
This process happens automatically when the exit method is called but it will throw an error if the account doesn't possess enough funds to repay the funder. This amount can be 0 $NEAR meaning that once the account reaches the floor, it can immediately exit without needing to repay.
The $NEAR needed to repay the funder can be gained in one of three ways:
- Gained during the trial (e.g selling an NFT you minted, winning an on-chain lottery etc.).
- Sent by another account.
- Sent with an on-ramp (similar to how accounts are funded currently).
While there is still friction in the last case, the user has experienced your application first and the onboarding is pushed until after their trial is over. Currently, people need to go through the complicated onboarding process first and only experience the app afterwards.
As an example, let's say you're building a roulette app and you want to give users a trial account to experience what you're building in the hope that they will continue to use it afterwards. You give someone 10 $NEAR and set a repay condition of 5 $NEAR. During their trial, they could have won 20 $NEAR from the roulette app by putting all their money on red.
This would satisfy the repay condition and they would be able to keep the rest of the $NEAR that they won.
What Happens On Exit?
When regular accounts are created on NEAR, they start with a full access key and don't have any smart contract deployed to them. This behavior should be the same for trial accounts except they keep any assets they had during the trial state. When the account exits, the following will happen:
- The limited access key is removed from the account.
- The trial contract is removed from the account.
- Any state that was set on the trial contract is removed.
- The full access key is added to the account.
- Any repay conditions are paid out.
- Any $NEAR that was not gained during the trial is returned to the funder. This includes the bytes freed from deleting the contract and is meant to be a way to resist Sybil attacks.
This means that the account will act as a fresh NEAR account with a set of starting assets such as NFTs or FTs that it gained during the trial. If the account wanted to, it could deploy a contract such as multi-sig, nETH etc.
When a trial account exits, it will be given a full access key and the restrictions will be removed. This means that the account will be able to call any method on any contract and attach any amount of $NEAR to function calls.
In this tutorial, you learnt the basics of how trial accounts operate and what is needed to create them. You also learnt about the different restrictions that can be applied to trial accounts, how they can be exited and what happens when they exit.
In the next tutorial, you'll learn how to create a simple trial account drop that will be used to instantly sign a user into the guest-book application.