Skip to content

Commit

Permalink
Merge pull request #745 from lukso-network/update-create-lsp7-token
Browse files Browse the repository at this point in the history
Update create lsp7 token file
  • Loading branch information
Hugoo authored Dec 12, 2023
2 parents f0eacc1 + f389a02 commit 1707bd5
Showing 1 changed file with 97 additions and 51 deletions.
148 changes: 97 additions & 51 deletions docs/learn/smart-contract-developers/create-lsp7-token.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ You can learn about the project setup by checking the [Getting Started](./gettin

:::

:::note

For the following guide, we are using `hardhat v2.19.1`, `ethers v6` and `@lukso/lsp-smart-contracts`
.

:::

## Create a custom LSP7 Token

In this guide you will create a custom [LSP7 Digital Asset](../../standards/tokens/LSP7-Digital-Asset.md) and pre-mint a certain amount of tokens to a specific address. To build your smart contract you will use the following LSP7 preset and extension:
Expand All @@ -25,21 +32,32 @@ You can modify the `mint()` function to adjust the amount of initially minted to

```solidity title="contracts/MyCustomToken.sol"
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.9;
pragma solidity ^0.8.4;
import "@lukso/lsp-smart-contracts/contracts/LSP7DigitalAsset/presets/LSP7Mintable.sol";
import "@lukso/lsp-smart-contracts/contracts/LSP7DigitalAsset/extensions/LSP7Burnable.sol";
contract CustomToken is LSP7Mintable, LSP7Burnable {
// parameters for LSP7Mintable constructor are:
// token name,
// token symbol,
// token owner,
// boolean isNonDivisible
// for more informations, check https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-7-DigitalAsset.md
constructor() LSP7Mintable("My Custom Token", "MCT", msg.sender, false) {
mint(msg.sender, 20000 * 10**decimals(), true, '0x' );
}
// for more informations, check https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-7-DigitalAsset.md
constructor(
string memory tokenName_,
string memory tokenSymbol_,
address tokenContractOwner_,
uint256 lsp4TokenType_, // for details see: https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-4-DigitalAsset-Metadata.md#lsp4tokentype
bool isNonDivisible_
)
LSP7Mintable(
tokenName_,
tokenSymbol_,
tokenContractOwner_,
uint256 lsp4TokenType_,
isNonDivisible_
)
{
{
mint(msg.sender, 20_000 * 10 ** decimals(), true, "0x"); // deployer gets 20k tokens
}
}
}
```

Expand Down Expand Up @@ -108,55 +126,78 @@ The `privateKey` coming from your UP extension is the private key of the EOA tha
:::
Create the script that will deploy the contract as your Universal Profile.

1. Create a `ethers.wallet` instance with your private key (the `signer`)
1. Add your Universal Profile address to your `.env` file in `UP_ADDR`
2. Load the associated UP
3. Get the bytecode of your contract
4. use `staticCall` method to get the address of the contract
5. deploy the contract
4. Use `staticCall` method to get the address of the contract
5. Deploy the contract

```ts title="scripts/deployUP.ts"
import hre from 'hardhat';
import { ethers } from 'hardhat';
import * as dotenv from 'dotenv';
import UniversalProfile from '@lukso/lsp-smart-contracts/artifacts/LSP0ERC725Account.json';
import UniversalProfileArtifact from '@lukso/lsp-smart-contracts/artifacts/LSP0ERC725Account.json';
import { CustomToken__factory } from '../typechain-types';

// load env vars
dotenv.config();
const { UP_ADDR, PRIVATE_KEY } = process.env;
const { UP_ADDR } = process.env;

async function main() {
// setup provider
const provider = new ethers.JsonRpcProvider(
'https://rpc.testnet.lukso.network',
);
// setup signer (the browser extension controller)
const signer = new ethers.Wallet(PRIVATE_KEY as string, provider);
// load the associated UP
const UP = await ethers.getContractAt('UniversalProfile', UP_ADDR as string);
console.log('🔑 EOA: ', signer.address);
console.log('🆙 Universal Profile: ', await UP.getAddress());
const universalProfile = await ethers.getContractAtFromArtifact(
UniversalProfileArtifact,
UP_ADDR as string,
);

/**
* Custom LSP7 Token
*/
console.log('⏳ Deploying the custom Token');
const CustomTokenBytecode =
hre.artifacts.readArtifactSync('CustomToken').bytecode;
const CustomTokenBytecode = CustomToken__factory.bytecode; // bytecode of the custom token without the constructor params

// custom token constructor params
const tokenName = 'My Custom Token';
const tokenSymbol = 'MCT';
const tokenContractOwnerAddress = (await ethers.getSigners())[0].address;
const tokenType = 0; // generic token
const isNonDivisible = false;

// encode constructor params
const abiEncoder = new ethers.AbiCoder();
const encodedConstructorParams = abiEncoder.encode(
['string', 'string', 'address', 'uint256', 'bool'],
[
tokenName,
tokenSymbol,
tokenContractOwnerAddress,
tokenType,
isNonDivisible,
],
);

// get the address of the contract that will be created
const CustomTokenAddress = await UP.connect(signer)
.getFunction('execute')
.staticCall(1, ethers.ZeroAddress, 0, CustomTokenBytecode);
// add the constructor params to the Custom Token bytecode
const CustomTokenBytecodeWithConstructor =
CustomTokenBytecode + encodedConstructorParams.slice(2);

// get the address of the Custom Token contract that will be created
const CustomTokenAddress = await universalProfile.staticCall(
1, // Operation type: CREATE
ethers.ZeroAddress,
0, // Value is empty
CustomTokenBytecodeWithConstructor,
);

// deploy CustomLSP7 as the UP (signed by the browser extension controller)
const tx1 = await UP.connect(signer).execute(
1,
// deploy the Custom Token contract
const tx = await universalProfile.execute(
1, // Operation type: CREATE
ethers.ZeroAddress,
0,
CustomTokenBytecode,
0, // Value is empty
CustomTokenBytecodeWithConstructor,
);

await tx1.wait();
// wait for the tx to be mined
await tx.wait();

console.log(
'✅ Custom Token successfully deployed at address: ',
CustomTokenAddress,
Expand Down Expand Up @@ -186,26 +227,31 @@ Deploying with an EOA is more straightforward, but you miss on the Universal Pro

```ts title="scripts/deployEOA.ts"
import { ethers } from 'hardhat';
import * as dotenv from 'dotenv';

dotenv.config();

async function main() {
// Hardhat has some issues with EIP 1559 settings, so you need to force it
// See this issue for more info: https://github.com/NomicFoundation/hardhat/issues/3418
const { maxFeePerGas, maxPriorityFeePerGas } =
await ethers.provider.getFeeData();

const customToken = await ethers.getContractFactory('CustomToken');

const Token = await customToken.deploy({
maxFeePerGas,
maxPriorityFeePerGas,
type: 2,
});
// custom token constructor params
const tokenName = 'My Custom Token';
const tokenSymbol = 'MCT';
const tokenContractOwnerAddress = (await ethers.getSigners())[0].address;
const tokenType = 0; // generic token
const isNonDivisible = false;

const Token = await customToken.deploy(
tokenName,
tokenSymbol,
tokenContractOwnerAddress,
tokenType,
isNonDivisible,
);

const token = await Token.waitForDeployment();
const CustomTokenAddress = await token.getAddress();
console.log(`Token address: ${CustomTokenAddress}`);
console.log(
'✅ Custom Token successfully deployed at address: ',
CustomTokenAddress,
);
}

main()
Expand Down

0 comments on commit 1707bd5

Please sign in to comment.