Skip to main content

Transfer LYX

In this guide, we will learn how to transfer LYX from our Universal Profile to any address (including another 🆙 ). We will cover:

  • the basics of the execute(...) function and how it works.
  • how to use this function to transfer LYX from our UP.

Guide - How to send LYX from a Universal Profile

tip

A complete "ready to use" JS file is available at the end in the Final Code section. If you want to run the code as standalone JavaScript files within the terminal or the browser, you can open the lukso-playground repository or use the correlated StackBlitz page. Remember that you will have to provide a controller key (EOA) of your Universal Profile in order to transfer funds.

Introduction

Let's recap what we have learned so far!

We previously saw how to use setData(...) to update data in our UP contract's storage. Let's now look at execute(...).

Basics of the execute(...) function

The execute(operation,to,value,data) function from ERC725X enable us to use our UP to interact with other addresses, such as transferring LYX or calling other smart contracts. This function takes four arguments (see ERC725 API docs).

We can use this function to transfer LYX from our UP to any address (including another UP). Transferring LYX from our UP is as simple as making a standard CALL to any address, attaching some value to the call.

For a regular LYX transfer, the parameters will be:

  • _operation: 0 (for CALL).
  • _to: the address we want to send LYX to (Externally Owned Account or contract address).
  • _value: the amount of LYX we want to transfer (in Wei).
  • _data: empty (0x since we are just transferring LYX).

Interacting via the Key Manager

Most of the functions on the UP contract, such as setData(...) and execute(...) can only be called by the owner. Therefore if we want to use our UP to do meaningful things, all interactions should go through the KM.

To transfer LYX from our UP, we need to perform the following steps:

  1. ABI encode the execute(operation,to,value,data) function call of our UP.
  2. pass the ABI encoded payload to the execute(payload) function on the KM.
info

Make sure to understand the difference between both execute(...) functions!

  • execute(operation,to,value,data) from the Universal Profile = generic executor function used to call and interact with EOAs or contracts + deploy new contracts from the UP.
  • execute(payload) from the Key Manager = used to run functions on the Universal Profile linked to the Key Manager (by forwarding ABI encoded payload), while verifying if the caller has the right permissions to do so.

Setup

To complete this mini-guide, we will need:

  • the UniversalProfile and KeyManager contracts ABIs from the @lukso/lsp-smart-contracts npm package.
  • the address of our Universal Profile we want to send LYX from.
npm install web3 @lukso/lsp-smart-contracts

Step 1 - Get some LYX

caution

You need to have LYX both in your EOA (which will pay for the transaction fees) and in your Universal Profile (where the LYX will be transferred from).

In order to send LYX from our Universal Profile, we will first request some free test LYX for our UP via the L16 Faucet.

  1. Visit the ➡️ LUKSO L16 Faucet Website.
  2. Paste the address of your Universal Profile in the input field and click in the "Give me LYX" button.

L16 Faucet screenshot

  1. Check the balance of your Universal Profile on the LUKSO L16 Block Explorer ⬇️

Paste the address of the Universal Profile in the address field in the top right corner of the block explorer.

If everything went successfully, you should see that the "Balance" field of your Universal Profile has been updated!

LUKSO L16 Network Block Explorer (screenshot)

Step 2 - Create the contracts instances

The first step is to create instances of our Universal Profile and Key Manager contracts.

  • 2.1 - First, we will use the Universal Profile to retrieve the address of the KeyManager via the owner() function.

  • 2.2 - Then, we will use the Key Manager to interact with our Universal Profile and send some LYX.

import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';

const myUP = new web3.eth.Contract(UniversalProfile.abi, myUPAddress);

// the KeyManager is the owner of the Universal Profile
// so we can call the owner() function to obtain the KeyManager's address
const owner = await myUP.methods.owner().call();

const myKM = new web3.eth.Contract(KeyManager.abi, owner);

Step 3 - Encode the payload to transfer LYX

With our contract instances ready, we now want to transfer some LYX from the UP using the execute(...) function. The next step is to ABI encode this function call with the correct parameters, as explained in the introduction.

We can use the encodeABI() method from web3.js

import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');

const OPERATION_CALL = 0;
const recipient = '0x...'; // address the recipient (any address, including an other UP)
const amount = web3.utils.toWei('3'); // amount of LYX we want to transfer
// payload executed at the target (here nothing, just a plain LYX transfer)
const data = '0x';

// encode the payload to transfer 3 LYX from the UP
const transferLYXPayload = await myUP.methods
.execute(OPERATION_CALL, recipient, amount, data)
.encodeABI();

Step 4 - Execute via the Key Manager

4.1 - Load our EOA

Like in other guides, the first step is to load our EOA that act as the main controller for our Universal Profile.

Load EOA from a private key
import Web3 from 'web3';
const web3 = new Web3('https://rpc.l16.lukso.network');

const PRIVATE_KEY = '0x...'; // your EOA private key (main controller address)

const myEOA = web3.eth.accounts.wallet.add(PRIVATE_KEY);

4.2 - Send the LYX transfer payload

The final step is to pass the encoded LYX transfer function to the Key Manager. Since we are calling from the UP's owner address, the Key Manager will authorize and execute the LYX transfer.

await myKM.methods.execute(transferLYXPayload).send({
from: myEOA.address,
gasLimit: 300_000,
});

Final Code

import Web3 from 'web3';
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/UniversalProfile.json';
import KeyManager from '@lukso/lsp-smart-contracts/artifacts/LSP6KeyManager.json';

const web3 = new Web3('https://rpc.l16.lukso.network');

const PRIVATE_KEY = '0x...'; // your EOA private key (main controller address)
const myEOA = web3.eth.accounts.wallet.add(PRIVATE_KEY); // amount of LYX we want to transfer

// 1. instantiate your contracts
const myUP = new web3.eth.Contract(UniversalProfile.abi, myUPAddress);

// the KeyManager is the owner of the Universal Profile
// so we can call the owner() function to obtain the KeyManager's address
const owner = await myUP.methods.owner().call();

const myKM = new web3.eth.Contract(KeyManager.abi, owner);

const OPERATION_CALL = 0;
const recipient = '0x...'; // address the recipient (any address, including an other UP)
const amount = web3.utils.toWei('3');
// payload executed at the target (here nothing, just a plain LYX transfer)
const data = '0x';

// 2. encode the payload to transfer 3 LYX from the UP
const transferLYXPayload = await myUP.methods
.execute(OPERATION_CALL, recipient, amount, data)
.encodeABI();

// 3. execute the LYX transfer via the Key Manager
await myKM.methods.execute(transferLYXPayload).send({
from: myEOA.address,
gasLimit: 300_000,
});