Skip to content

Latest commit

 

History

History
182 lines (148 loc) · 6.74 KB

File metadata and controls

182 lines (148 loc) · 6.74 KB
oip <0001>
title <Branded Token>
author <@jasonklein, Benjamin Bollen (@benjaminbollen)>
discussions-to <https://discuss.openst.org/t/branded-token-oip-0001/49>
status Draft
type <Standards Track>
category <OpenST>
created <2018-11-20>

Branded Token

Simple Summary

A Branded Token allows a mainstream application to create a value-backed token designed specifically for its application's context.

Abstract

Owners of a balance of a Branded Token (BT) must be able to redeem the underlying value that is associated with the Branded Token. A Branded Token is only usable within the application context. The application can maintain a policy on accepting new BT holders.

Motivation

Tokenize mainstream applications with existing user bases.

Specification

A Branded Token implements the required and optional EIP-20 Standard Token interface.

A Branded Token (BT) can be organised[OIP-] such that accepting a stake request to mint more Branded Tokens backed by OST can be controlled by the Organisation such that the total supply is determinable.

Stake Request

A staker can call requestStake to mint more branded tokens by staking a value token (OST) to fully back the BT. The BT can be staked at constant conversion rate BT:OST, or can be staked against a basket of value tokens.

On calling requestStake the value token amount _stake must be transferred from the staker to the Branded Token contract. Up until the stake request is accepted, the staker can call revokeStakeRequest and the stake amount is transferred back to the staker.

A call to acceptStakeRequest must present a valid signature of the _stakeRequestHash. We can't rely on msg.sender directly for access control to acceptStakeRequest because the caller might be a UX-composer contract owned by the staker.

interface ValueBacked {
    function requestStake(
        uint256 _stake,
        uint256 _mint
    )
        returns (bytes32 stakeRequestHash_);

    function acceptStakeRequest(
        bytes32 _stakeRequestHash,
        bytes32 _r,
        bytes32 _s,
        uint8 _v
    )
        returns (bool success_);

    function revokeStakeRequest()
        returns (bool success_);

    function redeem(
        uint256 _redeem
    )
        returns (bool success_);
}

where the stakeRequestHash is calculated according to EIP-712 only if the amount specified in _mint is correct given the amount specified in _stake following the backing rules of the Branded Token contract, or reverted otherwise.

//keccak256(
//    "EIP712Domain(address brandedTokenContract)"
//);
bytes32 public constant DOMAIN_SEPARATOR_TYPEHASH = 0x

//keccak256(
//    "StakeRequest(address staker,uint256 amount,uint256 nonce)"
//);
bytes32 public constant BT_STAKE_REQUEST_TYPEHASH = 0x

struct StakeRequest {
    address staker,
    uint256 amount, // value backed in OST
    uint256 nonce
}

Restricting use on Ethereum mainnet

Because Ethereum mainnet cannot support the transaction volume of any mainstream application, we want the value definition of the Branded Token to be declared on Ethereum mainnet, but restrict its direct use.

We therefore introduce the Restricted interface such that users can own a balance of the Branded Token on Ethereum mainnet, however, by default they cannot call transfer or transferFrom if the restriction is not lifted. Users can always redeem their balance for the underlying value token.

Users can call approve to set an allowence for a spender.

The restriction SHOULD be lifted for contracts that facilitate layer-2 scaling of the application (i.e. Mosaic gateway contracts, payment channels, zkSTARK contracts). These contracts can move a user's token balance into the scaling solution and give the user access to her token balance within the application (supported by the layer-2 scaling solution).

When the user exits the scaling solution contract, the user has a balance which she can redeem or re-enter into a (different) scaling contract.

interface Restricted {
    function liftRestriction(
        address[] _restrictionLifted) external returns (bool success);
    function isUnrestricted(
        address _actor) external view returns (bool isUnrestricted);
}
modifier onlyUnrestricted {
    require(
        unrestricted[msg.sender],
        "'msg.sender' is restricted."
    );
    _;
}

It is recommended to implement a one-time callable function liftAllRestrictions which renders the contract into a value-backed EIP-20 contract without restrictions.

An Internal Economy

The internal interface is to be applied to the utility token representation of the branded token on a side chain.

It should be possible to restrict the use of an application's utility token to the application context. To this end we require the recipient _to in calls to transfer and transferFrom is registered as an internal actor.

Addresses can be registered as internal actors, and once an actor has been registered as internal it cannot be deregistered.

interface Internal {
    function registerInternalActors(
        address[] _internalActors) external returns (bool success);
    function isInternalActor(
        address _actor) external view returns (bool isInternal);
}
require(
    isInternalActor(_to),
    "Tokens can only be transfered to internal actors.");

Rationale

The property internal for a token restricts the creation of a secondary market of the token while allowing open transactions within the context of the intended application. Any user can always redeem a token balance to exit the internal economy and recover value token that backed the branded token, which can be freely transfered.