Skip to content

Commit 53aaba3

Browse files
nhussein11eshaben
andauthored
FIX - web3js refactor (#1244)
* fix: web3js refactor + llms * Update smart-contracts/libraries/web3-js.md * Update smart-contracts/libraries/web3-js.md * Update smart-contracts/libraries/web3-js.md * Update smart-contracts/libraries/web3-js.md * edit file location * remove unnecessary title * update where to go next section * llms * fix: unneeded tip * fix: wording * fix: chain name to polkadotTestNet --------- Co-authored-by: Erin Shaben <[email protected]>
1 parent 7a76986 commit 53aaba3

File tree

11 files changed

+4711
-4033
lines changed

11 files changed

+4711
-4033
lines changed

.ai/categories/smart-contracts.md

Lines changed: 3368 additions & 3180 deletions
Large diffs are not rendered by default.

.ai/categories/tooling.md

Lines changed: 702 additions & 514 deletions
Large diffs are not rendered by default.

.ai/pages/smart-contracts-libraries-web3-js.md

Lines changed: 361 additions & 173 deletions
Large diffs are not rendered by default.

.ai/site-index.json

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5209,15 +5209,15 @@
52095209
},
52105210
{
52115211
"id": "smart-contracts-libraries-web3-js",
5212-
"title": "Web3.js",
5212+
"title": "Deploy Contracts to Polkadot Hub with Web3.js",
52135213
"slug": "smart-contracts-libraries-web3-js",
52145214
"categories": [
52155215
"Smart Contracts",
52165216
"Tooling"
52175217
],
52185218
"raw_md_url": "https://raw.githubusercontent.com/polkadot-developers/polkadot-docs/master/.ai/pages/smart-contracts-libraries-web3-js.md",
52195219
"html_url": "https://docs.polkadot.com/smart-contracts/libraries/web3-js/",
5220-
"preview": "!!! smartcontract \"PolkaVM Preview Release\" PolkaVM smart contracts with Ethereum compatibility are in **early-stage development and may be unstable or incomplete**. !!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.",
5220+
"preview": "!!! warning Web3.js has been [sunset](https://blog.chainsafe.io/web3-js-sunset/){target=\\_blank}. You can find guides on using [Ethers.js](/smart-contracts/libraries/ethers-js/){target=\\_blank} and [viem](/smart-contracts/libraries/viem/){target=\\_blank} in the Libraries section.",
52215221
"outline": [
52225222
{
52235223
"depth": 2,
@@ -5254,10 +5254,20 @@
52545254
"title": "Compile Contracts",
52555255
"anchor": "compile-contracts"
52565256
},
5257+
{
5258+
"depth": 3,
5259+
"title": "Sample Storage Smart Contract",
5260+
"anchor": "sample-storage-smart-contract"
5261+
},
5262+
{
5263+
"depth": 3,
5264+
"title": "Compile the Smart Contract",
5265+
"anchor": "compile-the-smart-contract"
5266+
},
52575267
{
52585268
"depth": 2,
5259-
"title": "Contract Deployment",
5260-
"anchor": "contract-deployment"
5269+
"title": "Deploy the Compiled Contract",
5270+
"anchor": "deploy-the-compiled-contract"
52615271
},
52625272
{
52635273
"depth": 2,
@@ -5271,12 +5281,12 @@
52715281
}
52725282
],
52735283
"stats": {
5274-
"chars": 13266,
5275-
"words": 1579,
5276-
"headings": 10,
5277-
"estimated_token_count_total": 3035
5284+
"chars": 20325,
5285+
"words": 2290,
5286+
"headings": 12,
5287+
"estimated_token_count_total": 4600
52785288
},
5279-
"hash": "sha256:f0d36333d0d3afff7f6374a61d0f6d1fb878c9ef4c4e4c24447745661dbe59d0",
5289+
"hash": "sha256:7cf1e07d1b8ef4e7b893398976907159a932f23f708d4e1d7ac1d09b80881787",
52805290
"token_estimator": "heuristic-v1"
52815291
},
52825292
{
Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,71 @@
1-
const { compile } = require('@parity/resolc');
2-
const { readFileSync, writeFileSync } = require('fs');
1+
const solc = require('solc');
2+
const { readFileSync, writeFileSync, mkdirSync, existsSync } = require('fs');
33
const { basename, join } = require('path');
44

5-
const compileContract = async (solidityFilePath, outputDir) => {
5+
const ensureDir = (dirPath) => {
6+
if (!existsSync(dirPath)) {
7+
mkdirSync(dirPath, { recursive: true });
8+
}
9+
};
10+
11+
const compileContract = (solidityFilePath, abiDir, artifactsDir) => {
612
try {
713
// Read the Solidity file
814
const source = readFileSync(solidityFilePath, 'utf8');
9-
10-
// Construct the input object for the compiler
15+
const fileName = basename(solidityFilePath);
16+
17+
// Construct the input object for the Solidity compiler
1118
const input = {
12-
[basename(solidityFilePath)]: { content: source },
19+
language: 'Solidity',
20+
sources: {
21+
[fileName]: {
22+
content: source,
23+
},
24+
},
25+
settings: {
26+
outputSelection: {
27+
'*': {
28+
'*': ['abi', 'evm.bytecode'],
29+
},
30+
},
31+
},
1332
};
14-
15-
console.log(`Compiling contract: ${basename(solidityFilePath)}...`);
16-
33+
34+
console.log(`Compiling contract: ${fileName}...`);
35+
1736
// Compile the contract
18-
const out = await compile(input);
19-
20-
for (const contracts of Object.values(out.contracts)) {
21-
for (const [name, contract] of Object.entries(contracts)) {
22-
console.log(`Compiled contract: ${name}`);
37+
const output = JSON.parse(solc.compile(JSON.stringify(input)));
38+
39+
// Check for errors
40+
if (output.errors) {
41+
const errors = output.errors.filter(error => error.severity === 'error');
42+
if (errors.length > 0) {
43+
console.error('Compilation errors:');
44+
errors.forEach(err => console.error(err.formattedMessage));
45+
return;
46+
}
47+
// Show warnings
48+
const warnings = output.errors.filter(error => error.severity === 'warning');
49+
warnings.forEach(warn => console.warn(warn.formattedMessage));
50+
}
51+
52+
// Ensure output directories exist
53+
ensureDir(abiDir);
54+
ensureDir(artifactsDir);
2355

56+
// Process compiled contracts
57+
for (const [sourceFile, contracts] of Object.entries(output.contracts)) {
58+
for (const [contractName, contract] of Object.entries(contracts)) {
59+
console.log(`Compiled contract: ${contractName}`);
60+
2461
// Write the ABI
25-
const abiPath = join(outputDir, `${name}.json`);
62+
const abiPath = join(abiDir, `${contractName}.json`);
2663
writeFileSync(abiPath, JSON.stringify(contract.abi, null, 2));
2764
console.log(`ABI saved to ${abiPath}`);
28-
65+
2966
// Write the bytecode
30-
const bytecodePath = join(outputDir, `${name}.polkavm`);
31-
writeFileSync(
32-
bytecodePath,
33-
Buffer.from(contract.evm.bytecode.object, 'hex'),
34-
);
67+
const bytecodePath = join(artifactsDir, `${contractName}.bin`);
68+
writeFileSync(bytecodePath, contract.evm.bytecode.object);
3569
console.log(`Bytecode saved to ${bytecodePath}`);
3670
}
3771
}
@@ -40,7 +74,8 @@ const compileContract = async (solidityFilePath, outputDir) => {
4074
}
4175
};
4276

43-
const solidityFilePath = './Storage.sol';
44-
const outputDir = '.';
77+
const solidityFilePath = join(__dirname, '../contracts/Storage.sol');
78+
const abiDir = join(__dirname, '../abis');
79+
const artifactsDir = join(__dirname, '../artifacts');
4580

46-
compileContract(solidityFilePath, outputDir);
81+
compileContract(solidityFilePath, abiDir, artifactsDir);
Lines changed: 60 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,98 @@
1-
import { readFileSync } from 'fs';
2-
import { Web3 } from 'web3';
1+
const { writeFileSync, existsSync, readFileSync } = require('fs');
2+
const { join } = require('path');
3+
const { Web3 } = require('web3');
4+
5+
const scriptsDir = __dirname;
6+
const abisDir = join(__dirname, '../abis');
7+
const artifactsDir = join(__dirname, '../artifacts');
8+
9+
const createProvider = (rpcUrl, chainId, chainName) => {
10+
const web3 = new Web3(rpcUrl);
11+
return web3;
12+
};
313

414
const getAbi = (contractName) => {
515
try {
6-
return JSON.parse(readFileSync(`${contractName}.json`), 'utf8');
16+
const abiPath = join(abisDir, `${contractName}.json`);
17+
return JSON.parse(readFileSync(abiPath, 'utf8'));
718
} catch (error) {
819
console.error(
9-
`Could not find ABI for contract ${contractName}:`,
10-
error.message
20+
`Could not find ABI for contract ${contractName}:`,
21+
error.message,
1122
);
1223
throw error;
1324
}
1425
};
1526

1627
const getByteCode = (contractName) => {
1728
try {
18-
return `0x${readFileSync(`${contractName}.polkavm`).toString('hex')}`;
29+
const bytecodePath = join(artifactsDir, `${contractName}.bin`);
30+
const bytecode = readFileSync(bytecodePath, 'utf8').trim();
31+
return bytecode.startsWith('0x') ? bytecode : `0x${bytecode}`;
1932
} catch (error) {
2033
console.error(
21-
`Could not find bytecode for contract ${contractName}:`,
22-
error.message
34+
`Could not find bytecode for contract ${contractName}:`,
35+
error.message,
2336
);
2437
throw error;
2538
}
2639
};
2740

28-
export const deploy = async (config) => {
41+
const deployContract = async (contractName, privateKey, providerConfig) => {
42+
console.log(`Deploying ${contractName}...`);
2943
try {
30-
// Initialize Web3 with RPC URL
31-
const web3 = new Web3(config.rpcUrl);
44+
const web3 = createProvider(
45+
providerConfig.rpc,
46+
providerConfig.chainId,
47+
providerConfig.name,
48+
);
3249

33-
// Prepare account
34-
const account = web3.eth.accounts.privateKeyToAccount(config.privateKey);
50+
const formattedPrivateKey = privateKey.startsWith('0x') ? privateKey : `0x${privateKey}`;
51+
const account = web3.eth.accounts.privateKeyToAccount(formattedPrivateKey);
3552
web3.eth.accounts.wallet.add(account);
53+
web3.eth.defaultAccount = account.address;
3654

37-
// Load abi
38-
const abi = getAbi('Storage');
39-
40-
// Create contract instance
55+
const abi = getAbi(contractName);
56+
const bytecode = getByteCode(contractName);
4157
const contract = new web3.eth.Contract(abi);
42-
43-
// Prepare deployment
44-
const deployTransaction = contract.deploy({
45-
data: getByteCode('Storage'),
46-
arguments: [], // Add constructor arguments if needed
58+
const deployTx = contract.deploy({
59+
data: bytecode,
4760
});
4861

49-
// Estimate gas
50-
const gasEstimate = await deployTransaction.estimateGas({
51-
from: account.address,
52-
});
53-
54-
// Get current gas price
62+
const gas = await deployTx.estimateGas();
5563
const gasPrice = await web3.eth.getGasPrice();
5664

57-
// Send deployment transaction
58-
const deployedContract = await deployTransaction.send({
65+
console.log(`Estimated gas: ${gas}`);
66+
console.log(`Gas price: ${web3.utils.fromWei(gasPrice, 'gwei')} gwei`);
67+
68+
const deployedContract = await deployTx.send({
5969
from: account.address,
60-
gas: gasEstimate,
70+
gas: gas,
6171
gasPrice: gasPrice,
6272
});
6373

64-
// Log and return contract details
65-
console.log(`Contract deployed at: ${deployedContract.options.address}`);
66-
return deployedContract;
74+
const address = deployedContract.options.address;
75+
console.log(`Contract ${contractName} deployed at: ${address}`);
76+
77+
const addressesFile = join(scriptsDir, 'contract-address.json');
78+
const addresses = existsSync(addressesFile)
79+
? JSON.parse(readFileSync(addressesFile, 'utf8'))
80+
: {};
81+
82+
addresses[contractName] = address;
83+
writeFileSync(addressesFile, JSON.stringify(addresses, null, 2), 'utf8');
6784
} catch (error) {
68-
console.error('Deployment failed:', error);
69-
throw error;
85+
console.error(`Failed to deploy contract ${contractName}:`, error);
7086
}
7187
};
7288

73-
// Example usage
74-
const deploymentConfig = {
75-
rpcUrl: 'INSERT_RPC_URL',
76-
privateKey: 'INSERT_PRIVATE_KEY',
77-
contractName: 'INSERT_CONTRACT_NAME',
89+
const providerConfig = {
90+
rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io', // TODO: replace to `https://services.polkadothub-rpc.com/testnet` when ready
91+
chainId: 420420422,
92+
name: 'polkadotTestNet',
7893
};
7994

80-
deploy(deploymentConfig)
81-
.then((contract) => console.log('Deployment successful'))
82-
.catch((error) => console.error('Deployment error'));
95+
const privateKey = 'INSERT_PRIVATE_KEY';
96+
97+
deployContract('Storage', privateKey, providerConfig);
98+

.snippets/code/smart-contracts/libraries/web3-js/fetchLastBlock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const createProvider = (rpcUrl) => {
88
const PROVIDER_RPC = {
99
rpc: 'https://testnet-passet-hub-eth-rpc.polkadot.io',
1010
chainId: 420420422,
11-
name: 'polkadot-hub-testnet',
11+
name: 'polkadotTestNet',
1212
};
1313

1414
const main = async () => {

0 commit comments

Comments
 (0)