diff --git a/text/0018-token-standard.md b/text/0018-token-standard.md
new file mode 100644
index 00000000..33dd39d9
--- /dev/null
+++ b/text/0018-token-standard.md
@@ -0,0 +1,272 @@
+# Casper Payments: Casper Token Standard
+
+## Summary
+A standard interface for the CSPR and the custom made tokens.
+
+## Motivation
+Having a token standard enables other projects to generalized on top it and makes
+integration easy, especially for wallets, DAOs and DeFi products like decentralized
+exchanges and liquidity pools. Defining a token standard before releasing
+the mainnet gives use the unique opportunity to implement this standard for our
+native platform token CSPR. It allows developers to reduce amount of code,
+because it is no longer required to handle 2 cases: one for native
+token and the other for a tokens implementing current token standard.
+
+In the design we decided to get away from the purse based model and use
+the account based model. As a main inspiration we point at ERC-20 standard
+known from Ethereum. It is the most widely adopted standard in the blockchain
+space, successfully ported outside of Ethereum. Thanks to the unique ability
+of Casper to execute code in the account's context, the main drawback of ERC-20,
+which is the "approve and call" pattern is no longer a problem.
+
+## Guide-level explanation
+### Interface
+The token contract should implement following endpoints.
+
+#### name
+Returns the token name.
+```rust
+fn name() -> String
+```
+
+#### symbol
+Returns the token symbol.
+```rust
+fn symbol() -> String
+```
+
+#### decimals
+Returns the number of token decimals.
+```rust
+fn decimals() -> u8
+```
+
+#### balance_of
+Returns the amount of tokens given address holds.
+```rust
+fn balanceOf(address: Address) -> U512
+```
+
+#### batch_balance_of
+Returns the amounts of tokens given a list of addresses.
+```rust
+fn batch_balance_of(addresses: Vec
) -> Vec
+```
+
+#### transfer
+Transfer tokens from the direct function caller to the `recipient`.
+```rust
+fn transfer(recipient: Address, amount: U512)
+```
+
+#### batch_transfer
+Transfer tokens to multiple recipients.
+```rust
+fn batch_transfer(recipient_and_amount_list: Vec<(Address, U512)>)
+```
+
+#### approve
+Allow other address to transfer caller's tokens.
+```rust
+fn approve(spender: Address, amount: U512)
+```
+
+#### batch_approve
+Allow other addresses to transfer caller's tokens.
+```rust
+fn batch_approve(spender_and_amount_list: Vec<(Address, U512)>)
+```
+
+#### allowance
+Returns the amount allowed to spend.
+```rust
+fn allowance(owner: Address, spender: Address) -> U512
+```
+
+#### batch_allowance
+Returns the amounts allowed to spend for given addresses.
+```rust
+fn allowance(owner_spender_list: Vec<(Address, Address)>) -> Vec
+```
+
+#### transfer_from
+Transfer tokens from `onwer` address to the `recipient` address if required
+amount was approved before to be spend by the direct caller.
+The operation should decrement approved amount.
+```rust
+fn transfer_from(owner: Address, recipient: Address, amount: U512)
+```
+
+#### batch_transfer_from
+Transfer tokens from `onwer` address to the multiple `recipients` addresses if required
+amount was approved before to be spend by the direct caller.
+The operation should decrement approved amount.
+```rust
+fn batch_transfer_from(owner: Address, recipient_amount_list: Vec<(Address, U512)>)
+```
+
+### Compare to ERC-20
+While very similar to ERC-20, this standard is a bit different:
+1. Methods: `name`, `symbol` and `decimals` are required.
+2. Names of arguments are part of the standard.
+3. Added batch versions of methods.
+
+## Reference-level explanation
+### Custom tokens
+We have successfully tested the implementation of ERC-20-based token.
+Code is available at https://github.com/CasperLabs/erc20.
+
+### Casper Token
+Currently Casper Token implements purse-based model. To support presented
+standard reimplementation of Casper Token (Mint) is required. In addition
+Casper Token should be deployed at a know Address.
+
+It should be possible to implement host-side interface, that manipulates
+the memory directly, so CSPR transfers are as fast as possible.
+
+## Rationale
+In this section we compare purse-based model and account-based model.
+
+Purse-based model allows accounts and contracts on creation of object
+called `purses`. Each purse can have it's own balance. Each purse have
+unique token access, that allows for tokens spending. This token access
+has to passed to contracts to send tokens.
+
+### Scenario
+Let's consider the most widely used scenario of interaction between two
+contracts: sending tokens from contract to contract. In this example we
+assume that:
+1. `Oracle` contract is already deployed and can provide a dollar price for tokens.
+2. `TokenEx` contract is deployed.
+3. `Vault` contract is deployed.
+4. `Source` contract is deployed.
+5. Goal is to transfer 10 dollars worth of Ex tokens into the `Vault` from the `Source`.
+6. Scenario starts by calling `action` on `Source`.
+
+Below code is pseudo-code.
+
+### Purse-based Model.
+In this example `TokenEx` implements purse-based model.
+```rust
+[#casper_contract]
+mod Source {
+
+ [#casper_method]
+ fn action(max_amount_of_tokens_allowed: U512) {
+ // Read purse from the local contract's memory.
+ let main_purse: URef = runtime::get_key("contracts_main_purse_for_ex_tokens");
+
+ // Call the Token contract to transfer tokens into the new purse.
+ // That's important, so the `Vault` contract is not exposed to the whole balance.
+ let intermediate_purse: URef =
+ runtime::call_contract("token_ex_address", "transfer_to_new_purse", runtime_args!{
+ from => main_purse,
+ amount => max_amount_of_tokens_allowed
+ });
+
+ // Deposit tokens.
+ runtime::call_contract("vault_address", "deposit_10_dollars", runtime_args!{
+ ex_purse => intermediate_purse
+ });
+
+ // Transfer back the remaining from intermediate_purse to have all
+ // the Ex tokens on one purse.
+ runtime::call_contract("token_ex_address", "transfer_all", runtime_args!{
+ from => intermediate_purse,
+ to => main_purse
+ });
+ }
+}
+
+[#casper_contract]
+mod Vault {
+
+ [#casper_method]
+ fn deposit_10_dollars(ex_purse: URef) {
+ let main_purse: URef = runtime::get_key("contracts_main_purse_for_ex_tokens");
+ let price = runtime::call_contract("oracle_address", "ex_price");
+ let expected_amount = 10.0 / price;
+ runtime::call_contact("token_ex_address", "transfer", runtime_args!{
+ from => ex_purse,
+ to => main_purse,
+ amount => expected_amount
+ });
+ }
+}
+```
+
+### Account-based Model.
+In this example `TokenEx` implements account-based model.
+```rust
+[#casper_contract]
+mod Source {
+
+ [#casper_method]
+ fn action(max_amount_of_tokens_allowed: U512) {
+ // Approve tokens.
+ runtime::call_contract("token_ex_address", "approve", runtime_args!{
+ spender => "vault_address",
+ amount => max_amount_of_tokens_allowed
+ });
+
+ // Deposit tokens.
+ runtime::call_contract("vault_address", "deposit_10_dollars", runtime_args!{});
+ }
+}
+
+[#casper_contract]
+mod Vault {
+
+ [#casper_method]
+ fn deposit_10_dollars() {
+ let price = runtime::call_contract("oracle_address", "ex_price");
+ let expected_amount = 10.0 / price;
+ runtime::call_contact("token_ex_address", "transferFrom", runtime_args!{
+ from => runtime::get_caller(),
+ to => "vault_address",
+ amount => expected_amount
+ });
+ }
+}
+```
+
+
+Account-based model is better because:
+1. It doesn't require contracts and accounts to maintain purses in their
+ named keys space.
+2. Transferring tokens in a purse-based model creates a lot of empty purses, that
+ probably will never be reused. The solution for that might some sort of
+ garbage collector, but that's just not a problem with the account-based model.
+3. In most cases accounts and contracts will want to have all the tokens of one
+ type in a single purse. That makes accounting much easier (also much cheaper).
+ Account-based model gives that by the design.
+4. Most of the platforms have token defined that way. Following that path,
+ makes it much easier for developers to implement smart contract, because that's
+ what they already know.
+5. It will allow for much better Solidity portability via the Caspiler transpiler.
+
+### Approve and Call Problem
+On Ethereum it is problematic for accounts to interact with contracts, that require
+tokens. The account has to first call the `approve` function, wait for it, to
+be executed and only then call desired contract's method.
+
+On Casper platform contracts can provide helper functions for accounts, that are executed
+in the account context. That helper function can easily aggregate multiple approves
+and contract calls into one call.
+
+## Drawbacks and alternatives
+The alternative is to:
+1. Keep current implementation of Mint and wait for more feedback on purse-based model.
+2. Do not define any standard and see what would the community do.
+
+## Prior art
+We point at ERC-20 a the main source of influence: https://eips.ethereum.org/EIPS/eip-20
+
+## Unresolved questions
+It is useful if the interaction with contracts generates events, that describe
+what happened. Currently the Casper platform doesn't have that features,
+so this standard will have to be updated in a future, when the shape of the event
+functionality is known.
+
+The standard doesn't cover the upgradeability story. Maybe it should?
+