From 1dc20a8f507e5dd0b089b801dd5c277cf34863a1 Mon Sep 17 00:00:00 2001 From: maxvia87 Date: Mon, 27 Nov 2023 16:38:18 +0100 Subject: [PATCH 1/2] update create lsp7 token file --- .../create-lsp7-token.md | 147 ++++++++++++------ 1 file changed, 96 insertions(+), 51 deletions(-) diff --git a/docs/learn/smart-contract-developers/create-lsp7-token.md b/docs/learn/smart-contract-developers/create-lsp7-token.md index 207a7c3c3a..35b71d412d 100644 --- a/docs/learn/smart-contract-developers/create-lsp7-token.md +++ b/docs/learn/smart-contract-developers/create-lsp7-token.md @@ -14,6 +14,12 @@ 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 v0.13.0`. + +::: + ## 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: @@ -25,21 +31,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.0; 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 + } + } } ``` @@ -108,55 +125,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, @@ -186,26 +226,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() From 79f116bc63415e9997a7d04e684342da66b3ed42 Mon Sep 17 00:00:00 2001 From: Felix Hildebrandt Date: Mon, 11 Dec 2023 17:53:59 +0100 Subject: [PATCH 2/2] apply suggestions + add comment --- docs/learn/smart-contract-developers/create-lsp7-token.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/learn/smart-contract-developers/create-lsp7-token.md b/docs/learn/smart-contract-developers/create-lsp7-token.md index 35b71d412d..2d2aa795bd 100644 --- a/docs/learn/smart-contract-developers/create-lsp7-token.md +++ b/docs/learn/smart-contract-developers/create-lsp7-token.md @@ -16,7 +16,8 @@ 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 v0.13.0`. +For the following guide, we are using `hardhat v2.19.1`, `ethers v6` and `@lukso/lsp-smart-contracts` +. ::: @@ -31,7 +32,7 @@ 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.0; +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";