Skip to main content

Grant Permissions

caution

This article is a WIP

Requirements

You will need a Universal Profile that you can control via its KeyManager to follow this guide.
If you don't have a Universal Profile yet, follow our previous guide Create a Universal Profile or look at the lsp-factory.js docs.

In this guide, we will learn how to grant permissions to third-party addresses to enable them to interact with our Universal Profile.

By the end of this guide, you will know:

  • How permissions in the LSP6 Key Manager work + how to create them using erc725.js.
  • How to set permissions for a third party address on your Universal Profile.

Give permissions to 3rd parties overview

Introduction​

The Key Manager (KM) enables us to give permissions to other 3rd party addresses to perform certain actions on our Universal Profile (UP), such as editing our profile details, or any other profile metadata.

When granting permissions to a new address, we need to update three data keys in the ERC725Y storage of our Universal Profile:

🗄 ERC725Y data key📃 DescriptionðŸŽŊ Objective
AddressPermissions[]holds the number of addresses that have permissions on our UP.We need to increment it by +1.
AddressPermissions[index]holds a controller address at a specific index.We need to add the beneficiary address at the new index.
AddressPermissions:Permissions:<beneficiary-address>this data key holds the permissions of a controller address.We need to add the permissions of the beneficiary address under this data key.

Setup​

Install the dependencies
npm install web3 @erc725/erc725.js @lukso/lsp-smart-contracts

Step 1 - Initialize erc725.js​

The first step is to initialize the erc725.js library with a JSON schema specific to the LSP6 Key Manager. This will enable the library to know how to create and encode the permissions.

import { ERC725 } from '@erc725/erc725.js';
import LSP6Schema from '@erc725/erc725.js/schemas/LSP6KeyManager.json';

// step 1 -initialize erc725.js with the ERC725Y permissions data keys from LSP6 Key Manager
const erc725 = new ERC725(
LSP6Schema,
myUniversalProfileAddress,
web3.currentProvider,
);

Step 2 - Encode the permissions​

info

More permissions are available in erc725.js. See the API docs for encodePermissions(...) function for a complete list.

We can now use erc725.js to create the permissions for a specific 3rd party address. The library provide convenience functions for us, such as encodePermissions.

2.1 - Create the permission​

Let's consider in our example that we want to grant the permission SETDATA to a beneficiaryAddress, so that it can edit our Universal Profile details on our behalf.

We can do this very easily with erc725.js, using the encodePermissions(...) function.

// step 2.1 - create the permissions of the beneficiary address
const beneficiaryPermissions = erc725.encodePermissions({
SETDATA: true,
});

2.2 - Encode the permission for the 3rd party address​

Now that we have created the permission value SETDATA, we need to assign it to the beneficiaryAddress.

To do so, we need to assign the permission value created in step 2.1 to the beneficiaryAddress, using the AddressPermissions:Permissions:<address>, where <address> will be the address of the beneficiary.

We also need to add the beneficiaryAddress inside the AddressPermissions[] Array, and increment the AddressPermissions[] array length (+1).

// step 2.2 - encode the data key-value pairs of the permissions to be set for the beneficiary address
const beneficiaryAddress = '0xcafecafecafecafecafecafecafecafecafecafe'; // EOA address of an exemplary person

const addressPermissionsArray = await erc725.getData('AddressPermissions[]');
const controllers = addressPermissionsArray.value;

const permissionData = erc725.encodeData([
// the permission of the beneficiary address
{
keyName: 'AddressPermissions:Permissions:<address>',
dynamicKeyParts: beneficiaryAddress,
value: beneficiaryPermissions,
},
// the new list controllers addresses (= addresses with permissions set on the UP)
// + the incremented `AddressPermissions[]` array length
{
keyName: 'AddressPermissions[]',
value: [...controllers, beneficiaryAddress],
},
]);

Step 3 - Add the permissions on your UP​

We have now all the data needed to setup the permission for this 3rd party addres on our Universal Profile.

3.1 - Add imports & constants​

To get started you would need the following:

  • UniversalProfile from @lukso/lsp-smart-contracts in order to use its ABI.
  • The private key for your controller address with proper permissions, used for interacting with the Universal Profile.
  • The address of the Universal Profile that you want to interact with.
Load account from a private key
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import Web3 from 'web3';

const web3 = new Web3('https://rpc.testnet.lukso.network');
const myUniversalProfileAddress = '0x...';
const PRIVATE_KEY = '0x...'; // your EOA private key (previously created)

3.2 - Load your controller address​

We will need to interact with the Key Manager from the main controller address (the externally owned account (EOA) that has all the permissions on the UP).

The first step is to load this main controller address as an EOA using its private key.

The private key can be obtained depending on how you created your Universal Profile:

  • UP created with our Create a Universal Profile guide: you should have provided the private key and known it.
  • UP created with the lsp-factory.js: this is the private key given in the controllerAddresses field in the method lspFactory.UniversalProfile.deploy(...)
  • UP created via the Browser extension: click on the Settings icon (top right) > and Export Private Key
Load account from a private key
const myEOA = web3.eth.accounts.wallet.add(PRIVATE_KEY);

3.3 - Create contract instance​

The next steps is to create an instance of our UP smart contract to interact with. The contract ABIs are available in the @lukso/lsp-smart-contracts npm package.

You will need the address of your Universal Profile.

// step 1 - create instance of UniversalProfile contract
const myUniversalProfile = new web3.eth.Contract(
UniversalProfile.abi,
myUniversalProfileAddress,
);

3.4 - Set the permission on the Universal Profile​

The last and final step is to setup the permissions the beneficiaryAddress on our Universal Profile.

We can easily access the data key-value pair from the encoded data obtained by erc725.js in step 2.2.

We will then encode this permission data keys in a setData(...) payload and interact via the Key Manager.

// step 3.3 - send the transaction
await myUniversalProfile.methods.setData(
data.keys,
data.values,
).send({
from: myEOA.address,
gasLimit: 300_000,
});

Testing the permissions​

We can now check that the permissions have been correctly set by querying the AddressPermissions:Permissions:<beneficiaryAddress> data key on the ERC725Y storage of the Universal Profile.

If everything went well, the code snippet below should return you back an object with the permission SETDATA set to true.

const result = await myUniversalProfile.methods['getData(bytes32)'](
data.keys[0],
).call();
console.log(
`The beneficiary address ${beneficiaryAddress} has now the following permissions:`,
erc725.decodePermissions(result),
);

Finally, to test the actual permissions, you can do this guide using a beneficiaryAddress that you have control over (created manually via web3.js).

You can then try to do again the Edit our Universal Profile guide, using this new 3rd party address that you have control over to test if it can successfull edit the profile details. This will give you guarantee that this beneficiaryAddress has the SETDATA permission working.

Final code​

import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import { ERC725 } from '@erc725/erc725.js';
import LSP6Schema from '@erc725/erc725.js/schemas/LSP6KeyManager.json';
import Web3 from 'web3';

const web3 = new Web3('https://rpc.testnet.lukso.network');
const myUniversalProfileAddress = '0x...';

const PRIVATE_KEY = '0x...'; // your EOA private key (previously created)
const myEOA = web3.eth.accounts.wallet.add(PRIVATE_KEY);

const erc725 = new ERC725(
LSP6Schema,
myUniversalProfileAddress,
web3.currentProvider,
);

async function grantPermissions() {
// step 1 - create instance of UP contract
const myUniversalProfile = new web3.eth.Contract(
UniversalProfile.abi,
myUniversalProfileAddress,
);

// step 2 - setup the permissions of the beneficiary address
const beneficiaryAddress = '0xcafecafecafecafecafecafecafecafecafecafe'; // EOA address of an exemplary person
const beneficiaryPermissions = erc725.encodePermissions({
SETDATA: true,
});

// step 3.1 - encode the data key-value pairs of the permissions to be set
const addressPermissionsArray = await erc725.getData('AddressPermissions[]');
const controllers = addressPermissionsArray.value;

const data = erc725.encodeData([
// the permission of the beneficiary address
{
keyName: 'AddressPermissions:Permissions:<address>',
dynamicKeyParts: beneficiaryAddress,
value: beneficiaryPermissions,
},
// the new list controllers addresses (= addresses with permissions set on the UP)
// + the incremented `AddressPermissions[]` array length
{
keyName: 'AddressPermissions[]',
value: [...controllers, beneficiaryAddress],
},
]);

// step 3.3 - send the transaction
await myUniversalProfile.methods.setDataBatch(
data.keys,
data.values,
).send({
from: myEOA.address,
gasLimit: 300_000,
});

const result = await myUniversalProfile.methods['getData(bytes32)'](
data.keys[0],
).call();
console.log(
`The beneficiary address ${beneficiaryAddress} has now the following permissions:`,
erc725.decodePermissions(result),
);
}

grantPermissions();