Portals are smart contracts that are registered in the "Portal Registry" and that you can consider as the entrypoint to the Verax Attestation Registry. This is where the payloads to be attested start their journey.
To create a Portal, you must first deploy a contract that inherits the AbstractPortal
abstract contract. This portal contract is where you create attestations in the registry. You have full control over the logic in this contract, so long as it inherits the base AbstractPortal
contract.
The function that you will call to issue an attestation is:
function attest(
AttestationPayload memory attestationPayload,
bytes[] memory validationPayload
) public payable;
{% hint style="info" %}
We are also introducing an attestV2
function with the same signature, to cover the new "Modules V2" feature.
{% endhint %}
The attest
function accepts 2 arguments:
attestationPayload
, the raw attestation data that will be stored in the registryvalidationPayload
, validation logic that the module needs to execute its verification logic
This function allows you to actually create attestations, you can call the various modules and/or apply any other logic you need to. The convention is to keep as much logic as possible in modules, but it is up to you how you implement your own domain logic. You can choose to override this function and add your own logic, or use the function as defined in AbstractPortal
.
{% hint style="warning" %} While you can put whatever logic you want to in your portal contracts, it is strongly advised that you keep your portal as modular as possible, which means keeping your logic in modules. In the future, we may pivot to no-code portals, which have no contract, and which simply execute a specific chain of modules! {% endhint %}
As well as implementing the AbstractPortal
interface, the Portal contract must also implement the IERC165Upgradeable interface, which involves including this function:
function supportsInterface(bytes4 interfaceID) public pure override returns (bool) {
return interfaceID == type(AbstractPortal).interfaceId || interfaceID == type(IERC165Upgradeable).interfaceId;
}
The AbstractPortal
contract defines the following life cycle hooks:
- onAttest
- onReplace
- onBulkAttest
- onBulkReplace
- onRevoke
- onBulkRevoke
These lifecycle hooks can be overridden in the concrete implementation of the Portal, and can be used to implement additional logic and specific points in the lifecycle of an attestation.
Portal registration takes 5 parameters, defined as follows:
Parameter | Datatype | Description |
---|---|---|
id | address | Address of the Portal |
name | string | A descriptive name for the Portal |
description | string | A description of the Portal's functionality |
isRevocable | bool | Whether attestations issued by the portal can be revoked |
ownerName | string | The portal owner's name |
Once you have deployed your Portal contract, you can then register it in the PortalRegistry
contract using the register
function:
function register(
address id,
string memory name,
string memory description,
bool isRevocable,
string memory ownerName
);
A few caveats: a Portal contract must be first deployed and cannot be registered twice under different names. Also, the name, description and owner name must not be empty.
Instead of crafting the smart contract call by hand, you can benefit from a chain explorer interface. Let's use the Linea Sepolia explorer, Lineascan.
The form generated by Lineascan to interact with the PortalRegistry
contract
- Retrieve the
PortalRegistry
contract address from the project README - Access the
PortalRegistry
contract on Lineascan - Go to the "Contract" tab
- Go to the "Write as Proxy" tab
- Connect your wallet and fill the
register
form with the parameters described above - Send the transaction
We have seen rather manual ways to register a Portal, now let's focus on the easiest way: via the Verax SDK.
{% hint style="info" %} Check this page to discover how to instantiate the Verax SDK. {% endhint %}
Once you have an SDK instance, you can register a Portal like this:
await veraxSdk.portal.register(
id: "0xD39c439cD3Ae5E1F3c7d13985aDAC90846284904",
name: "ExamplePortal",
description: "This Portal is used as an example",
isRevocable: true,
ownerName: "Verax",
);
If you opted for a default Portal as described here, good news: it was registered while being deployed!