| 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> |
A Branded Token allows a mainstream application to create a value-backed token designed specifically for its application's context.
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.
Tokenize mainstream applications with existing user bases.
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.
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
}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.
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.");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.