Upgrade the LSP6 Key Manager
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 upgrade the LSP6 Key Manager of your Universal Profile to the latest version available.
By the end of this guide, you will know how to:
- Deploy a new LSP6 Key Manager with the last updates.
- Upgrade your Key Manager by changing the owner of your UP from your old to your new Key Manager.
Setup
Make sure you have the following dependencies installed before beginning this tutorial:
- Either
web3.js
orethers.js
@lukso/lsp-smart-contracts
- web3.js
- ethers.js
npm install web3 @lukso/lsp-smart-contracts
npm install ethers @lukso/lsp-smart-contracts
Step 1 - Set up the constants and imports
Create a JavaScript file and add the following imports on the top of the file:
privateKey
: private key of a controller address, MUST have CHANGEOWNER permission.keyManagerAddress
: address of the current LSP6 Key Manager.universalProfileAddress
: address of your Universal Profile.
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
- web3.js
- ethers.js
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://rpc.l16.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
Step 2 - Initialize the controller account
In order to send any transaction on the blockchain you need an EOA. In our case that account MUST have CHANGEOWNER
permission on the Universal Profile that will have its LSP6 Key Manager upgraded.
- web3.js
- ethers.js
const account = web3.eth.accounts.wallet.add(privateKey);
const account = new ethers.Wallet(privateKey).connect(provider);
Step 3 - Initialize the old LSP6 Key Manager
In order to transfer ownership of your Universal Profile, you need to initialize your current LSP6 Key Manager.
- web3.js
- ethers.js
const oldKeyManager = new web3.eth.Contract(LSP6KeyManager.abi, keyManagerAddress);
const oldKeyManager = new ethers.Contract(keyManagerAddress, LSP6KeyManager.abi);
Step 4 - Deploy the new LSP6 Key Manager
Deploy a new LSP6 Key Manager with the latest updates.
- web3.js
- ethers.js
const newKeyManager = new web3.eth.Contract(LSP6KeyManager.abi);
await newKeyManager
.deploy({
data: LSP6KeyManager.bytecode,
arguments: [universalProfileAddress],
})
.send({
from: account.address,
gas: 3_000_000,
gasPrice: '1000000000',
});
const keyManagerFactory = new ethers.ContractFactory(
LSP6KeyManager.abi,
LSP6KeyManager.bytecode,
);
const newKeyManager = await keyManagerFactory.deploy(universalProfileAddress);
Step 5 - Upgrade your Key Manager
Step 5.1 - Transfer Ownership to your new Key Manager
Create a calldata for the transferOwnership(address)
function and shift the ownership of your Universal Profile from your current LSP6 Key Manager.
- web3.js
- ethers.js
const transferOwnershipPayload = new web3.eth.Contract(
UniversalProfile.abi,
).methods
.transferOwnership('0xcafecafecafecafecafecafecafecafecafecafe')
.encodeABI();
await oldKeyManager.methods['execute(bytes)'](transferOwnershipPayload).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
const transferOwnershipPayload = new ethers.Interface(
UniversalProfile.abi,
).encodeFunctionData('transferOwnership(address)', [newKeyManager._address]);
await oldKeyManager
.connect(account)
['execute(bytes)'](transferOwnershipPayload);
Step 5.2 - Accept Ownership from your new Key Manager
Create a calldata for the claimOwnership()
function and take the ownership of your Universal Profile from your new LSP6 Key Manager.
- web3.js
- ethers.js
const acceptOwnershipCalldata = new web3.eth.Contract(UniversalProfile.abi).methods.acceptOwnership().encodeABI();
await newKeyManager.methods['execute(bytes)'](acceptOwnershipCalldata).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
const acceptOwnershipCalldata = new ethers.Interface(UniversalProfile.abi).encodeFunctionData("acceptOwnership()");
await newKeyManager.connect(account)['execute(bytes)'](acceptOwnershipCalldata);
The upgrade has been completed successfully.
Final code
- web3.js
- ethers.js
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
const upgradeLSP6 = async () => {
// Initialize the controller account
const account = web3.eth.accounts.wallet.add(privateKey);
// Initialize your current LSP6 Key Manager
const oldKeyManager = new web3.eth.Contract(LSP6KeyManager.abi, keyManagerAddress);
// Deploy a new LSP6 Key Manager
const newKeyManager = new web3.eth.Contract(LSP6KeyManager.abi);
await newKeyManager.deploy({
data: LSP6KeyManager.bytecode,
arguments: [universalProfileAddress],
}).send({
from: account.address,
gas: 3_000_000,
gasPrice: '1000000000',
});
// Transfer the ownership of your Universal Profile from the current LSP6 Key Manager to a new LSP6 Key Manager
const transferOwnershipPayload = new web3.eth.Contract(
UniversalProfile.abi,
).methods
.transferOwnership(newKeyManager._address)
.encodeABI();
await oldKeyManager.methods['execute(bytes)'](transferOwnershipPayload).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
// Accept the ownership of your Universal Profile from the new LSP6 Key Manager
const acceptOwnershipCalldata = new web3.eth.Contract(UniversalProfile.abi).methods.acceptOwnership().encodeABI();
await newKeyManager.methods['execute(bytes)'](acceptOwnershipCalldata).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
};
await upgradeLSP6();
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import { ethers } from 'ethers';
const provider = new ethers.JsonRpcProvider('https://rpc.l16.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
const upgradeLSP6 = async () => {
// Initialize the controller account
const account = new ethers.Wallet(privateKey).connect(provider);
// Initialize your current LSP6 Key Manager
const oldKeyManager = new ethers.Contract(keyManagerAddress, LSP6KeyManager.abi);
// Deploy a new LSP6 Key Manager
const keyManagerFactory = new ethers.ContractFactory(
LSP6KeyManager.abi,
LSP6KeyManager.bytecode,
);
const newKeyManager = await keyManagerFactory.deploy(universalProfileAddress);
// Transfer the ownership of your Universal Profile from the current LSP6 Key Manager to a new LSP6 Key Manager
const transferOwnershipPayload = new ethers.Interface(
UniversalProfile.abi,
).encodeFunctionData('transferOwnership(address)', [newKeyManager._address]);
await oldKeyManager
.connect(account)
['execute(bytes)'](transferOwnershipPayload);
// Accept the ownership of your Universal Profile from the new LSP6 Key Manager
const acceptOwnershipCalldata = new ethers.Interface(UniversalProfile.abi).encodeFunctionData("acceptOwnership()");
await newKeyManager.connect(account)['execute(bytes)'](acceptOwnershipCalldata);
};
await upgradeLSP6();
Test the new LSP6 Key Manager
We can now check the owner of the Universal Profile. If everything went through, the owner should be the address of the new LSP6 Key Manager.
Create the following file with the name test-new-lsp6.js
and run:
node test-new-lsp6.js
import LSP0ERC725YAccount from '@lukso/lsp-smart-contracts/artifacts/LSP0ERC725YAccount.json';
import LSP6KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');
const universalProfileAddress = '0x...';
const keyManagerAddress = '0x...';
const testLSP6 = async () => {
const universalProfile = new web3.eth.Contract(LSP0ERC725YAccount.abi, universalProfileAddress);
const universalProfileOwner = await universalProfile.methods.owner().call();
console.log(`The new owner of the Universal Profile is: ${universalProfileOwner}`);
console.log(`The old LSP6 Key Manager is at address: ${keyManagerAdderss}`);
const keyManager = new web3.eth.Contract(LSP6KeyManager.abi, universalProfileOwner);
const keyManagerTarget = await keyManager.methods.target().call();
console.log(`The address of the Universal Profile is: ${universalProfile._address}`);
console.log(`The target of the new LSP6 Key Manager: ${keyManagerTarget}`);
};
await testLSP6();