Crafting Rule Contract

The center of our Crafting Engine

Requirements for Rule designer before releasing it

Before a rule can be useful, output tokens must allow the rule to mint their tokens. So, the rule designer must negotiate with the output games and gather their approvals for the rule. After minting rights have been given through the CraftableOut.canMint( ... ) function, the rule can be used to craft and redeem transactions.

Usage Requirements for User

To craft...

For the user to be able to use the crafting rule services, they must:

  1. Give transfer approval in the input and output contracts to the crafting rule address. this should be facilitated through the crafting web-app.

  2. Have enough of the tokens to satisfy the needs of the crafting rule.

  3. Call the craft( ... ) function with the order of tokens mentioned in the definition.

To redeem...

For the user to redeem, in addition to approvals, they must

  1. Already have crafted the output tokens they want to redeem

  2. Call the redeem( ... ) function with the order of tokens mentioned in the definition.

Understanding how the crafting rule contract works

To implement the crafting rule, you can opt to code it yourself for the full customization and flexibility. If you don't feel like coding, we offer you a no-code tool to generate the crafting rule for you.

In all cases, all you have to code - if you intend to use the coding approach - are four functions

The constructor

In your constructor, you must initialize the crafting rule with the lists of input and output tokens you intend to use in your rule.

constructor( ... ) {
    CraftingRule( [list of input contract addresss], [list of output contract addresses ] )
}

The item orders

There are two functions to implement to validate the order of user inputs for the craft( ... ) and redeem( ... )

  • _inputItemOrderValid(address[] addrs, uint256[] classes) it should return true only if the input order is the same as the definition file.

my-meal-rule.sol
...
function _inputItemOrderValid(
  address[] memory addrs,
  uint256[] memory classes
) internal view override returns (bool) {
  //MealRule: bag must have 2 items and 2 classes
  if (!(addrs.length == 2 && classes.length == 2)) return false;

  // MealRule: first item must be falafel
  if (!(addrs[0] == FALAFEL_INGREDIENT)) return false;

  if (!(classes[0] == 1)) return false;

  // MealRule: second item must be condiment
  if (!(addrs[1] == CONDIMENT_INGREDIENT)) return false;

  return true;
}
...
  • _outputItemOrderValid(address[] addrs, uint256[] classes) it should return true only if the output order is the same as the definition file.

my-meal-rule.sol
...
function _outputItemOrderValid(
  address[] memory addrs,
  uint256[] memory classes
) internal view override returns (bool) {
  //MealRule: bag must have 2 items and 2 classes
  if (!(addrs.length == 2 && classes.length == 2)) return false;

  // MealRule: first item must be sandwich
  if (!(addrs[0] == SANDWICH)) return false;

  if (!(classes[0] == 1)) return false;

  // MealRule: second item must be napkin
  if (!(addrs[1] == NAPKIN)) return false;

  return true;
}
...

The mapping rule

The mapping rule defines the buisness rules in place to transform the inputs provided to the outputs in questions. it could be simple if-else conditions for filters or complicated math operations to compute the output attribute value from input attribute values.

The mapping rule rule(Bag inBag, ItemAttributes[] inAttributes) takes the input in the form of structs. It should return:

  • list of output addresses outAddrs

  • list of output classes outClasses

  • list of output balances outBalances

  • list of output attributes in the form of ItemAttributes structs.

function rule ( ... ) ... {
    // [1] initialize output lists for addresses, classes, balances, balances
    // [2] logic to compute output balances and attributes from input values
}

[1] Initialization

function rule ( ... ) ... {
    ...
    // [1] initialize the output lists
    // OUTPUT ADDRESSES
    outAddrs = new address[](2);
    outAddrs[0] = SANDWICH;
    outAddrs[1] = NAPKIN;

    // OUTPUT CLASSES
    outClasses = new uint256[](2);
    outClasses[0] = 1; // the first token should be a Falafel token
    
    // example of making the output class choice based on an input
    // if the falafel is big, we need a textile napkin
    if (falafelAttributes.attributes[1] > 16) {
      outClasses[1] = 2;
    } else {
      outClasses[1] = 1;
    }

    // OUTPUT BALANCES
    outBalances = new uint256[](2);
    // one sandwich
    outBalances[0] = 1;
    // if we have taratour, we need two napkins
    if (condiment.class == 1) {
      outBalances[1] = 2;
    } else {
      outBalances[1] = 1;
    }
    ...
}

[2] Computing output balances and attributes

The jth attribute of the ith input token can be accessed via inAttributes[i].attributes[j]

The balance of the jth input token can be accessed by

Item memory myJthToken = _getItem(inBag, 1);
// => access through myJthToken.balance

an example of some output logic code for attributes

function rule ( ... ) ... {
    ...
    // [2] logic to compute output
    
    // if we used tahini it expires
    if (condiment.class == 3) {
      outAttributes[0].attributes[3] = 1;
    } else {
      outAttributes[0].attributes[3] = 0;
    }
    ...
}

Docs

Structs
Bag
struct Bag {
  address[] itemAddrs;
  uint256[] itemIds;
  uint256[] itemClasses;
  uint256[] itemBalances;
  bytes32 digest;
  bool computed;
}
Item
struct Item {
  address addr;
  uint256 id;
  uint256 class;
  uint256 balance;
}
ItemAttributes
struct ItemAttributes {
  uint256[] attributes;
}

Functions
inContractsCount()

The number of distinct input contracts involved in this crafting rule.

outContractsCount()

The number of distinct output contracts involved in this crafting rule.

inContractsAddresses(uint256 index)

Returns the address of the input contract at the index in the order of the definition.

outContractsAddresses(uint256 index)

Returns the address of the output contract at the index in the order of the definition.

canCraft(address[] addrs, uint256[] ids, uint256[] balances)

Checks whether the user would be able to perform the crafting according to the contract rule if they provide the tokens in the following order:

[ (addrs[0], ids[0], balances[0]), (addrs[1], ids[1], balances[1]), ... ]

It returns true if the order is allowed.

craft(address[] addrs, uint256[] ids, uint256[] balances)

Performs the crafting of the input tokens to the output tokens. It performs the following operations in order:

  1. Converts the list into a Bag struct and ItemAttributes list.

  2. Generate the output templates and attributes according to the rule(...) implemented by the rule developer.

  3. Transfers the input tokens from the user wallet to the rule wallet.

  4. Mint and/or transfer the output tokens according to the disclosed mapping rule to the user wallet.

  5. Stores the input tokens and tags them with the output bag of tokens. This will help reverse the operation in redeeming.

  6. Generates Crafted events, which has the CraftingHash. the crafting hash acts as the invoice ID for the crafting operation. The hash is a function of the input bag presented.

canRedeem(address[] addrs, uint256[] ids, uint256[] balances)

Checks whether the user would be able to perform the redeeming according to the contract rule if they provide the tokens in the following order:

[ (addrs[0], ids[0], balances[0]), (addrs[1], ids[1], balances[1]), ... ]

It returns true if the order is allowed and the tokens presented have been previously crafted together.

redeem(address[] addrs, uint256[] ids, uint256[] balances)

Performs the redeeming the input tokens owned by the contract by returning the output tokens previously crafted. It performs the following operations in order:

  1. Converts the list into a Bag struct.

  2. Recover the input bag previously pointed to by the signature of the output bag.

  3. Transfer the input tokens from the contract wallet to the user wallet.

  4. Burns the output tokens previously minted.

  5. Generates a Redeemed event.

Last updated