Upgrade Key Manager
This guide is an advanced guide. It is intended for developers who are looking to upgrade the Key Manager of their Universal Profile to a new one. For instance, if a new Key Manager with enhanced features.
For normal user using the UP Browser Extension, their UP is currently setup with a basic Key Manager already deployed for them on profile creation. It is therefore not recommended to follow this guide as this could affect the functionality of their UP, making it not possible to interact with it via the Browser Extension.
This advanced guide shows how to upgrade the LSP6KeyManager
of your UP, which is the owner()
of the UniversalProfile
. We will:
- Deploy a new
LSP6KeyManager
contract on LUKSO Testnet. - Upgrade by transferring ownership of the UniversalProfile to the newly deployed
LSP6KeyManager
. - Confirm the upgrade by accepting ownership via the 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
- ethers
- web3
npm install ethers @lukso/lsp-smart-contracts
npm install web3 @lukso/lsp-smart-contracts
Step 1 - Set up 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.universalProfileAddress
: address of your Universal Profile.
- ethers
- web3
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.testnet.lukso.network',
);
const privateKey = '0x...';
const universalProfileAddress = '0x...';
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.testnet.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
Step 2 - Initialize the controllerβ
Requirement: the EOA controller that we will use MUST have the
CHANGEOWNER
permission on the UP
- ethers
- web3
const account = new ethers.Wallet(privateKey).connect(provider);
const account = web3.eth.accounts.wallet.add(privateKey);
Step 3 - Initialize UP contractβ
In order to transfer ownership of your Universal Profile, you need to initialize the UP's contract.
- ethers
- web3
const universalProfile = new ethers.Contract(
universalProfileAddress,
UniversalProfile.abi,
);
const universalProfile = new web3.eth.Contract(
UniversalProfile.abi,
universalProfileAddress,
);
Step 4 - Deploy the new Key Managerβ
Deploy a new LSP6 Key Manager with the latest updates.
- ethers
- web3
const newKeyManager = await new ethers.ContractFactory(
LSP6KeyManager.abi,
LSP6KeyManager.bytecode,
)
.connect(account)
.deploy(universalProfileAddress);
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',
});
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.
- ethers
- web3
await universalProfile
.connect(account)
.transferOwnership(newKeyManager.address);
await universalProfile.methods.transferOwnership(newKeyManager.address).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
Step 5.2 - Accept Ownership from your new Key Managerβ
Create a calldata for the acceptOwnership()
function and take the ownership of your Universal Profile from your new LSP6 Key Manager.
- ethers
- web3
const acceptOwnershipCalldata = new ethers.Interface(
UniversalProfile.abi,
).encodeFunctionData('acceptOwnership()');
await newKeyManager.connect(account).execute(acceptOwnershipCalldata);
const acceptOwnershipCalldata = new web3.eth.Contract(
UniversalProfile.abi,
).methods
.acceptOwnership()
.encodeABI();
await newKeyManager.methods.execute(acceptOwnershipCalldata).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
The upgrade has been completed successfully.
Final codeβ
- ethers
- web3
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.testnet.lukso.network',
);
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const upgradeLSP6 = async () => {
// Initialize the controller account
const account = new ethers.Wallet(privateKey).connect(provider);
// Initialize your current UP
const universalProfile = new ethers.Contract(
universalProfileAddress,
UniversalProfile.abi,
);
// Deploy a new LSP6 Key Manager
const newKeyManager = await new ethers.ContractFactory(
LSP6KeyManager.abi,
LSP6KeyManager.bytecode,
)
.connect(account)
.deploy(universalProfileAddress);
// Transfer the ownership of your Universal Profile from the current LSP6 Key Manager to a new LSP6 Key Manager
await universalProfile
.connect(account)
.transferOwnership(newKeyManager.address);
// 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(acceptOwnershipCalldata);
};
await upgradeLSP6();
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.testnet.lukso.network');
const privateKey = '0x...';
const universalProfileAddress = '0x...';
const upgradeLSP6 = async () => {
// Initialize the controller account
const account = web3.eth.accounts.wallet.add(privateKey);
// Initialize your current UP
const universalProfile = new web3.eth.Contract(
UniversalProfile.abi,
universalProfileAddress,
);
// 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
await universalProfile.methods.transferOwnership(newKeyManager.address).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(acceptOwnershipCalldata).send({
from: account.address,
gas: 1_000_000,
gasPrice: '1000000000',
});
};
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.testnet.lukso.network');
const universalProfileAddress = '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();