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:
Give transfer approval in the input and output contracts to the crafting rule address. this should be facilitated through the crafting web-app.
Have enough of the tokens to satisfy the needs of the crafting rule.
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
Already have crafted the output tokens they want to redeem
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
Performs the crafting of the input tokens to the output tokens. It performs the following operations in order:
Converts the list into a Bag struct and ItemAttributes list.
Generate the output templates and attributes according to the rule(...) implemented by the rule developer.
Transfers the input tokens from the user wallet to the rule wallet.
Mint and/or transfer the output tokens according to the disclosed mapping rule to the user wallet.
Stores the input tokens and tags them with the output bag of tokens. This will help reverse the operation in redeeming.
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.
Performs the redeeming the input tokens owned by the contract by returning the output tokens previously crafted. It performs the following operations in order:
Converts the list into a Bag struct.
Recover the input bag previously pointed to by the signature of the output bag.
Transfer the input tokens from the contract wallet to the user wallet.