From 6936861544080ca91aeed444a61a703ef05df15c Mon Sep 17 00:00:00 2001 From: YamenMerhi Date: Tue, 23 Jul 2024 17:27:34 +0300 Subject: [PATCH] Add deploy UniversalFactory code --- universal-factory/README.md | 3 + universal-factory/TargetContract.json | 42 ++++++++++++ .../check-universal-factory-exist.ts | 23 +++++++ universal-factory/deploy-contract.ts | 66 +++++++++++++++++++ universal-factory/deploy-nick-factory.ts | 23 +++++++ universal-factory/deploy-universal-factory.ts | 17 +++++ 6 files changed, 174 insertions(+) create mode 100644 universal-factory/README.md create mode 100644 universal-factory/TargetContract.json create mode 100644 universal-factory/check-universal-factory-exist.ts create mode 100644 universal-factory/deploy-contract.ts create mode 100644 universal-factory/deploy-nick-factory.ts create mode 100644 universal-factory/deploy-universal-factory.ts diff --git a/universal-factory/README.md b/universal-factory/README.md new file mode 100644 index 0000000..19e0603 --- /dev/null +++ b/universal-factory/README.md @@ -0,0 +1,3 @@ +# Deploy Multichain Contracts + +- https://docs.lukso.tech/learn/other-guides/deploy-multichain-contracts diff --git a/universal-factory/TargetContract.json b/universal-factory/TargetContract.json new file mode 100644 index 0000000..d6cc1ff --- /dev/null +++ b/universal-factory/TargetContract.json @@ -0,0 +1,42 @@ +{ + "abi": [ + { + "inputs": [ + { + "internalType": "uint256", + "name": "_number", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "number", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_number", + "type": "uint256" + } + ], + "name": "setNumber", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b5060405161010f38038061010f83398101604081905261002f91610037565b600055610050565b60006020828403121561004957600080fd5b5051919050565b60b18061005e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80633fb5c1cb1460375780638381f58a146049575b600080fd5b604760423660046063565b600055565b005b605160005481565b60405190815260200160405180910390f35b600060208284031215607457600080fd5b503591905056fea2646970667358221220958426080fb00e4b3e137866f9d1884559c2a31f2d3ee15cd4f2c8aee4a92e6764736f6c63430008110033" +} diff --git a/universal-factory/check-universal-factory-exist.ts b/universal-factory/check-universal-factory-exist.ts new file mode 100644 index 0000000..a06deb2 --- /dev/null +++ b/universal-factory/check-universal-factory-exist.ts @@ -0,0 +1,23 @@ +import { ethers } from 'ethers'; + +const RPC_URL = 'https://rpc.testnet.lukso.network'; +const provider = new ethers.JsonRpcProvider(RPC_URL); + +const checkDeployedCode = async (address: any) => { + const code = await provider.getCode(address); + return code !== '0x'; +}; + +// Fixed addresses + +// For more information check: https://github.com/Arachnid/deterministic-deployment-proxy +const NICK_FACTORY_ADDRESS = '0x4e59b44847b379578588920ca78fbf26c0b4956c'; + +// For more information check: https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-16-UniversalFactory.md +const LSP16_FACTORY_ADDRESS = '0x1600016e23e25D20CA8759338BfB8A8d11563C4e'; + +const isNickFactoryDeployed = await checkDeployedCode(NICK_FACTORY_ADDRESS); +const isLSP16FactoryDeployed = await checkDeployedCode(LSP16_FACTORY_ADDRESS); + +console.log('Nick Factory exists: ', isNickFactoryDeployed); +console.log('LSP16UniversalFactory exists: ', isLSP16FactoryDeployed); diff --git a/universal-factory/deploy-contract.ts b/universal-factory/deploy-contract.ts new file mode 100644 index 0000000..2ba530b --- /dev/null +++ b/universal-factory/deploy-contract.ts @@ -0,0 +1,66 @@ +import { ethers } from 'ethers'; + +const RPC_URL = 'https://rpc.testnet.lukso.network'; +const provider = new ethers.JsonRpcProvider(RPC_URL); + +import { abi as LSP16UniversalFactoryABI } from '@lukso/lsp-smart-contracts/artifacts/LSP16UniversalFactory.json'; +import { + abi as TargetContractABI, + bytecode as targetContractBytecode, +} from './TargetContract.json'; + +// The private key should not be comitted to a public GitHub repository. +const signer = new ethers.Wallet('', provider); + +// For more information check: https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-16-UniversalFactory.md +const LSP16_FACTORY_ADDRESS = '0x1600016e23e25D20CA8759338BfB8A8d11563C4e'; + +const lsp16UniversalFactory = new ethers.Contract( + LSP16_FACTORY_ADDRESS, + LSP16UniversalFactoryABI, + signer, +); + +// Dummy value +const constructorArgument = 123; +const encodedConstructorArg = ethers.AbiCoder.defaultAbiCoder().encode( + ['uint256'], + [constructorArgument], +); + +const contractBytecodeWithArg = + targetContractBytecode + encodedConstructorArg.substring(2); + +// On each script run, this salt should be different otherwise the deployment will fail +// Don't use random bytes as salt, use a deterministic salt to be able to deploy on a different network +// using the same salt, to produce the same address +// Should be a hex string like 0x1322322... (32 bytes) +const deploymentSalt = ''; + +// Precompute the address of the contract to be deployed without initialization +const precomputedAddressWithoutInit = + await lsp16UniversalFactory.computeAddress( + ethers.keccak256(contractBytecodeWithArg), + deploymentSalt, + false, // --> boolean indicating if the contract should be initialized or not after deployment + '0x', // --> bytes representing the calldata to initialize the contract + ); + +// Deploy contract without initialization +const deployTxWithoutInit = await lsp16UniversalFactory.deployCreate2( + contractBytecodeWithArg, + deploymentSalt, +); +await deployTxWithoutInit.wait(); + +const contractWithoutInit = new ethers.Contract( + precomputedAddressWithoutInit, + TargetContractABI, + signer, +); + +const numberInContractWithoutInit = await contractWithoutInit.number(); +console.log( + 'The number in the non-initialized contract is: ', + numberInContractWithoutInit, +); diff --git a/universal-factory/deploy-nick-factory.ts b/universal-factory/deploy-nick-factory.ts new file mode 100644 index 0000000..7fb3b37 --- /dev/null +++ b/universal-factory/deploy-nick-factory.ts @@ -0,0 +1,23 @@ +import { ethers } from 'ethers'; + +const RPC_URL = 'https://rpc.testnet.lukso.network'; +const provider = new ethers.JsonRpcProvider(RPC_URL); + +// The private key should not be comitted to a public GitHub repository. +const signer = new ethers.Wallet('', provider); + +const fundingTx = await signer.sendTransaction({ + // Standardized address + to: '0x3fab184622dc19b6109349b94811493bf2a45362', + value: ethers.parseEther('0.009'), // This value should be enough + // Check gasLimit and gasPrice to estimate exactly the value: https://github.com/Arachnid/deterministic-deployment-proxy +}); + +await fundingTx.wait(); + +// Sending raw transaction specified by the Nick factory +const rawTx = + '0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222'; + +const deployNickFactoryTx = await provider.broadcastTransaction(rawTx); +await deployNickFactoryTx.wait(); diff --git a/universal-factory/deploy-universal-factory.ts b/universal-factory/deploy-universal-factory.ts new file mode 100644 index 0000000..b676483 --- /dev/null +++ b/universal-factory/deploy-universal-factory.ts @@ -0,0 +1,17 @@ +import { ethers } from 'ethers'; + +const RPC_URL = 'https://rpc.testnet.lukso.network'; +const provider = new ethers.JsonRpcProvider(RPC_URL); + +// The private key should not be comitted to a public GitHub repository. +const signer = new ethers.Wallet('', provider); + +const lsp16Tx = await signer.sendTransaction({ + to: '0x4e59b44847b379578588920ca78fbf26c0b4956c', // Nick Factory Address + data: + '0xfaee762dee0012026f5380724e9744bdc5dd26ecd8f584fe9d72a4170d01c049' + // Standardized Salt + '60806040523480156100105...', // Standardized Bytecode + // Copy the full bytecode from https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-16-UniversalFactory.md#standardized-bytecode +}); + +await lsp16Tx.wait();