Address Lock Metadata File

Mechanics

The Address Lock Metadata File is a JSON file that describes which inputs should be gathered by the Revest frontend during the minting of an address lock, how to decode data received from the address lock itself to display to the user, and how to encode data that will trigger additional functionality within the address lock during the locked period.

All data passing to the Address Lock implementation or from it will be ABI (Application Binary Interface) encoded into a bytes array. This allows the Revest Protocol to collect an arbitrary amount of parameters from the user, encode them into a single argument, and then have the Address Lock implementation (which told the frontend which parameters to collect and in what order to encode them) decode the bytes into usable variables, which may then be stored or operated on. The same is true for data passed from the Address Lock implementation to the frontend; since the developer prescribes the parameters and their ordering in both the JSON config file read by the frontend and the Solidity used in the Address Lock, meaningful communication between the two is always possible.

Example: Encoding of Data to ABI and back within Solidity

From the Frontend (all under-the-hood, this is not something you will ever need to write for developing with Revest's API):

export function encodeArguments(abi, args) {
  let abiCoder = ethers.utils.defaultAbiCoder;
  return abiCoder.encode(abi, args);
}

let bytesArg = encodeArguments(['uint256','address','bool'],[16, '0x0621f8051991080aafA60F5A3F8855F68210E640',true]);
//bytesArg = 00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000621f8051991080aafa60f5a3f8855f68210e6400000000000000000000000000000000000000000000000000000000000000001

Once this bytes array has been transmitted to the mintAddressLock function, it is then relayed to the Address Lock implementation located at the "trigger" address parameter. There, it may be decoded and utilized.

//Input parameter bytesArg
(uint numberArg, address addArg, bool boolArg) = abi.decode(bytesArg, (uint, address, bool));
//numberArg = 16, addArg = 0x0621f8051991080aafA60F5A3F8855F68210E640, boolArg = true

Structuring a Metadata File

The Revest Protocol Address Metadata File describes what parameters should be collected or displayed and in what order to encode/decode them from ABI data. It does through a domain-specific language written in JSON. A description of common sections follows. A live example may be found at this link and is suggested as a learning tool.

Name, Description, and Author

Self-explanatory fields, these do not meaningfully impact user-experience, but will be utilized by future versions of the frontend to display data to users selecting from Address Lock presets.

Inputs

The "inputs" field is an array of objects which describe each individual input to be displayed on the minting screen to the user. The order of these objects in the array determines the order in which they will be displayed to the user. Each object in an input list must include the following:

Label

The 'label' field describes the label which should be displayed to the user during the minting process. This field should describe what the input desired from the user is.

Primitive

The 'primitive' field describes the variable "type" for the desired input. Depending on what this value is, the input form will present differently to the user. Possible options include:

  • date: Renders as a calendar inputs and requests that the user provide a date

  • token: Presents the user with a list of commonly-utilized tokens that also allows for the importing of ERC20s from a pasted-in address.

  • oracle: Presents the user with a list of curated oracles recommended by the Revest Protocol. This primitive will require additional input, described in the "extra_data" section, to determine if a path between asset1 and asset2 exists

  • address: Offers an auto-checking address field, that will present the user with a visual error code if the address entered is not a valid Ethereum address

  • integer: Presents a numerical input field to the user that will not allow for decimal inputs. No decimal conversion will be performed on this field, making it ideal for truly integer values, such as quantities of NFTs

  • number: Presents the user with a numerical input field that will allow for decimals up to the prescribed precision. Allowable decimal precision should be specified in the "extra_data" section. This primitive will automatically be converted into a proper integer format through the ethers.js method parseUnits(number, decimalPrecision).

  • string: Displays a textual input field with no additional checks.

  • binary_radio: Displays a binary radio field, where one of two options may be chosen. Options must be specified in the "extra_data" section.

  • multi_radio: This field is identical to the binaryradio option, except that it allows for more than two options to be present. Similar encoding of options within the extra_data section is necessary.

Encode

The "encode" field describes what Solidity type the passed in values should be encoded as. Possible options are described by the linked Solidity docs. Certain primitives will always obviously map to certain types, and care must be taken by the developer to avoid non-sensical encoding assignments (such as number to bool).

Index

The "index" field describes in what order the current parameter should be encoded by the ABI encoder. While mixing different fields with each other makes sense from the perspective of a user-experience, minor gas savings may be realized by packing fields together properly prior to encoding. The values of index are left up to the developer, though it is mandatory that they begin at 0 and increase integer-wise from there.

Extra_data

The "extra_data" field is one which will have varying contents based on the primitive selected. Acceptable (and in many cases, mandatory) extra_data fields correlate as follows:

  • oracle

    • asset1: An address representing the asset of which to measure the price. If "asset1" is not present, then "asset1_index" must be present.

    • asset2: An address representing the asset with which the price of asset1 is to be measured. If "asset2" is not present, then "asset2_index" must be present.

    • asset1_index: Specifies an address or token selector to serve as the source of asset1. This index correlates to the index specified by the object within the config, not the order in which that object appears in the inputs list. If "asset1_index" is not present, then "asset1" must be present.

    • asset2_index: Specifies an address or token selector to serve as the source of asset2. This index correlates to the index specified by the object within the config, not the order in which that object appears in the inputs list. If "asset2_index" is not present, then "asset2" must be present.

  • number

    • decimal_precision: Specifies the decimal precision to round the number to and to encode it in. If set to -1, "source_precision_from_index" must be present in the same extra_data section.

    • source_precision_from_index: Specifies the index of a "token" primitive to use for sourcing data on decimal precision. Will set the decimal precision of the associated number input field equal to that token's decimal precision. This index correlates to the index specified by the object within the config, not the order in which that object appears in the inputs list.

  • binary_radio and multi_radio

    • options: A mandatory array that specifies two or more objects. Value should be set to either "true"/"false" strings for binary_radio or numerical indices for multi_radio.

      • text: The text to display the option as

      • value: The value to assign when the given option is selected

Updates

The "updates" field is an array of objects that describe how to collect and format data to be sent off for updating a given address lock implementation at any point in time. Field formatting is identical to that given for "inputs", save for the presence of an additional primitive:

  • button: The "button" primitive specifies the presence of a button containing a custom label, which when clicked will call the "updateLock" method of the associated Address Lock implementation.

This button may be displayed conditionally based on the presence of an additional boolean value in the displays section. The index with which to make this determination (whether to hide the button or not) is specified in the "extra_data" section of the button primitive, with the following format:

  • display_boolean_linkage_index: Specifies an integer index linked in "displays" that will always have the primitive type of "boolean" and will determine if the update button renders or not.

Displays

The "displays" field is an array representing the values to display to the user within the Revest Info Panel. It is similar to the "updates" and "inputs" fields, but in this case, the frontend is decoding ABI data rather than encoding it. Several differences exist between this and the "inputs" field: almost all are purely visual.

Label

The "label" field will often be utilized as a prefix for a display element, and in these cases should be given an additional whitespace character at the end of the label.

Empty labels will not render their values. This allows for the use of the "display_boolean_linkage_index" system, as this field has an empty label and will not render on-screen.

Units

The units suffix is appended to a given display value after the "label" value has prefixed it. This allows for inlined statements concerning unlocking conditions and similar information delivery in plain English. It is also useful for describing units of numerical quantity

Primitives

A variety of primitives are slightly altered for displays.

  • "oracle" and "token" primitives will display their respective names and do not require any additional extra_data linkages.

  • "number" fields are decoded from BigNumber representations to decimal values through the use of an associated decimal precisions.

  • "binary_radio" fields will be displayed inline as the text correlating to the value read from on-chain

Ongoing Development

The Revest Team is always interested in adding support for new suggested primitives. If you have any ideas you'd like to share, feel free to drop into the Telegram or Discord and share them with us! Adding new primitives to our frontend is backwards compatible and requires no Solidity modifications or redeployments.

Last updated