Interact with other contracts
This guide might contain outdated information and will be updated soon.
In this guide, we will learn how to use our Universal Profile to interact with any other smart contract (like if we were using a regular Externally Owned Account).
Interaction flow:
Introductionâ
We have seen in the previous example how to send LYX from our UP via the execute(...)
function.
This function offers a fourth parameter: _data
, that provides a lot of flexibility when interacting from our UP. The _data
parameter is handy when the _to
recipient is a smart contract.
If you want to call a specific smart contract that was deployed on the network by the Universal Profile, the parameters of the execute(...)
function will be as follow:
_operation
:0
(forCALL
)._to
: theaddress
of the smart contract we want to interact with._value_
: empty (0)._data
: the ABI-encoded function name and arguments, to be run at the_to
contract address.
Suppose a smart contract targetContract
was deployed on the network and we want our UP to call the function myCoolFunction
on this contract. We will have to:
- ABI-encode the function call with the parameters we want to pass.
- Pass the encoded calldata as argument
_data
of theexecute(...)
function.
Setupâ
To complete this guide, we will need:
- an EOA with some LYX for gas fees and the required permissions for the interaction.
- the
UniversalProfile
andKeyManager
contracts ABIs from the@lukso/lsp-smart-contracts
npm package. - the address of our Universal Profile.
- the
targetContract
ABI. - the address of the Target Contract.
The chosen EOA needs to have CALL Permission together with Allowed Calls or SUPER_CALL Permission
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 - Create the contracts instancesâ
The first step is to create instances of our Universal Profile, Key Manager contracts and the Target Contract.
- Create an Universal Profile contract instance from
universalProfileAddress
. - Create a Target Contract instance from the
targetContractAddress
.
Save the Target Contract ABI in a separate JSON and import it in the main file.
You can quickly compile and get a contract's ABI in Remix IDE.
- web3.js
- ethers.js
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import TargetContractABI from './TargetContractABI.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.testnet.lukso.network');
const universalProfileAddress = '0x...';
const universalProfile = new web3.eth.Contract(
UniversalProfile.abi,
universalProfileAddress,
);
const targetContractAddress = '0x...';
const targetContract = new web3.eth.Contract(
TargetContractABI,
targetContractAddress,
);
import { ethers } from 'ethers';
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import TargetContractABI from './TargetContractABI.json';
const provider = new ethers.JsonRpcProvider(
'https://rpc.testnet.lukso.network',
);
const universalProfileAddress = '0x...';
const universalProfile = new ethers.Contract(
universalProfileAddress,
UniversalProfile.abi,
provider,
);
const targetContractAddress = '0x...';
const targetContract = new ethers.Contract(
targetContractAddress,
TargetContractABI,
provider,
);
Step 2 - Encode the calldatasâ
We need to create a calldata that will be executed on the Target Contract.
- web3.js
- ethers.js
// 1. encode the calldata to be run at the targetContract
// assuming targetContract is a Contract instance
const targetCalldata = targetContract.methods
.myCoolfunction('dummyParameter')
.encodeABI();
// 1. encode the calldata to be run at the targetContract
// assuming targetContract is a Contract instance
const targetCalldata = targetContract.interface.encodeFunctionData(
'myCoolfunction',
['dummyParameter'],
);
Step 3 - Execute the calldataâ
Load the EOAâ
Like in other guides, an important step is to load our EOA that is a controller for our Universal Profile.
- web3.js
- ethers.js
const PRIVATE_KEY = '0x...'; // your EOA private key (controller address)
const EOA = web3.eth.accounts.wallet.add(PRIVATE_KEY);
const PRIVATE_KEY = '0x...'; // your EOA private key (controller address)
const EOA = new ethers.Wallet(PRIVATE_KEY).connect(provider);
Send the execute calldataâ
The final step is to pass the encoded calldata to the Universal Profile. Since we are calling from an EOA that is a controller on the UP, the Key Manager will authorize the transaction.
- web3.js
- ethers.js
await universalProfile.methods
.execute(OPERATION_CALL, targetContract.address, 0, targetCalldata)
.send({
from: EOA.address,
gasLimit: 300_000,
});
await universalProfile
.connect(EOA)
.execute(OPERATION_CALL, targetContract.address, 0, targetCalldata);
Final Codeâ
- web3.js
- ethers.js
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import TargetContractABI from './TargetContractABI.json';
import Web3 from 'web3';
const web3 = new Web3('https://rpc.testnet.lukso.network');
const universalProfileAddress = '0x...';
const universalProfile = new web3.eth.Contract(
UniversalProfile.abi,
universalProfileAddress,
);
const targetContractAddress = '0x...';
const targetContract = new web3.eth.Contract(
TargetContractABI,
targetContractAddress,
);
// 1. encode the calldata to be run on the UP
const targetCalldata = targetContract.methods
.myCoolfunction('dummyParameter')
.encodeABI();
const OPERATION_CALL = 0;
const PRIVATE_KEY = '0x...'; // your EOA private key (controller address)
const EOA = web3.eth.accounts.wallet.add(PRIVATE_KEY);
// 2. execute the calldata through the UP
await universalProfile.methods
.execute(OPERATION_CALL, targetContract.address, 0, targetCalldata)
.send({
from: EOA.address,
gasLimit: 300_000,
});
import { ethers } from 'ethers';
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import TargetContractABI from './TargetContractABI.json';
const provider = new ethers.JsonRpcProvider(
'https://rpc.testnet.lukso.network',
);
const universalProfileAddress = '0x...';
const universalProfile = new ethers.Contract(
universalProfileAddress,
UniversalProfile.abi,
provider,
);
const targetContractAddress = '0x...';
const targetContract = new ethers.Contract(
targetContractAddress,
TargetContractABI,
provider,
);
// 1. encode the calldata to be run on the UP,
const targetCalldata = targetContract.interface.encodeFunctionData(
'myCoolfunction',
['dummyParameter'],
);
const OPERATION_CALL = 0;
const PRIVATE_KEY = '0x...'; // your EOA private key (controller address)
const EOA = new ethers.Wallet(PRIVATE_KEY).connect(provider);
// 2. execute the calldata through the UP
await universalProfile
.connect(EOA)
.execute(OPERATION_CALL, targetContract.address, 0, targetCalldata);