0

I have a physical product to sell. I want to have a digital asset representing each unit of my physical asset. I have created an ERC20 token contract and each token represents a unique instance of the product that I manufacture and want to sell. A new token is minted when a new product comes out of assembly line.

Note: I have selected a fungible token because the lifetime value of each unit of the product remains equal. This also enables trading of my ERC20 token, and by extension, my product, on the open market, as the value of each will be the same forever.

The problem is most of my business logic ended up in the main ERC20 contract. I want to keep the ERC20 token contract as lean as possible. If my business logic changes, I don't want to pause the token and create a new contract. The token should remain the same. To achieve this I want a way that an authorized contract (s) or me as the owner, should be able to call, for e.g. an issueToken function from my main ERC20. Think of having multiple storefronts and sales channels taking orders and on determining a valid order, fulfill it and issue the token to the buyer. This will also help me keep orders, the physical product data and associated metadata, separate from my main ERC20. However, I do want a one-to-one mapping of a unique product with a unique ERC20 token.

How can I best structure this behavior?

1

First, it can be difficult to achieve one-to-one product-token mapping as ERC20 is standard for non-unique tokens. Have you tried ERC-721 standard? http://erc721.org/

But if you want to stick to ERC20, I guess you want something like this (sorry if there are some minor typos, I typed it in the website's text box)

Token.sol

...

//place to store privileged users and contracts, simple manager pattern
mapping(address=>bool) public managers;

//user that deployed contract, simple owner pattern
address public owner;

constructor() public {
    owner = msg.sender;
    managers[owner] = true;
    //the rest of your constructor goes here
}

function issueToken(uint256 number) public {
    //only privileged user/contract can call it
    require(managers[msg.sender]);

    totalTokens += number; //increasing token suppply
    balances[msg.sender] += number; //balances is mapping where you store balances of each holder
}

//simple function to toggle managers on/off
function setManager(address manager, bool state)  {
    require(owner == msg.sender);
    managers[manager] = state;
}

...

Issuer.sol

...
Token public token; //of course better to use interface here, like IToken.sol
constructor(Token _token) public {
    token = _token;
}
function issueTo(uint256 number, address destination) {
    token.issueToken(number);
    //now balance of contract has +number tokens, transfer it to destination
    token.transfer(destination, number);
}
...

After you deploy Token and Issuer contract you must 'connect' them, call

token.setManager(issuer, true)

After that, you can call issuer.issueTo, you also can create multiple issuers that use the very same token contract.

  • Could you clarify why better to use interface like IToken in Issuer.sol? What benefit would I get from using interface? – Vishal Aug 5 at 20:03
  • That way your issuer won't depend on particular Token contract. It will be able to issue any token that has mint function for example. – Oleg Kondrakhanov Aug 6 at 3:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.