libraries:
some examples:
yarn add @polyjuice-provider/ethers
or
npm install --save @polyjuice-provider/ethers
once you install this module, then you got 3 main tools to run with ethers
for compatibility:
- PolyjuiceJsonRpcProvider (compatible version of JsonRpcProvider)
- PolyjuiceWallet (compatible version of Wallet)
- PolyjuiceWebsocketProvider (compatible version of WebSocketProvider)
replacement:
new providers.JsonRpcProvider(..) ---> new PolyjuiceJsonRpcProvider(...)
new Wallet(..) --> new PolyjuiceWallet(...)
new providers.WebSocketProvider(..) ---> new PolyjuiceWebsocketProvider(...)
init library:
import { ContractFactory } from "ethers";
import { PolyjuiceConfig } from "@polyjuice-provider/base";
import { PolyjuiceWallet, PolyjuiceJsonRpcProvider } from "@polyjuice-provider/ethers";
const polyjuiceConfig: PolyjuiceConfig = {
rollupTypeHash: 'godwoken rollup type hash', // this is optional
ethAccountLockCodeHash: 'godwoken eth account lock code hash', // this is optional
creatorId: 'polyjuice creator account id', // this is optional
defaultFromAddress: 'a default eth address, which will be used as a default from in ethereum transaction', // this is optional
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
const rpc = new PolyjuiceJsonRpcProvider(polyjuiceConfig, polyjuiceConfig.web3Url);
const deployer = new PolyjuiceWallet('<your deployer private key>', polyjuiceConfig, rpc);
you can let provider find the polyjuiceConfig info by itself as well:
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
const rpc = new PolyjuiceJsonRpcProvider(polyjuiceConfig, polyjuiceConfig.web3Url);
const deployer = new PolyjuiceWallet('<your deployer private key>', polyjuiceConfig, rpc);
that way provider will fetch polyjuiceConfig from web3 rpc server when those information are empty.
sometimes abiItem
can be omitted from constructor too: when you are not interacting with smart contracts, therefore there is no AbiItems needed to pass.
const polyjuiceConfig: PolyjuiceConfig = {
web3Url: 'godwoken web3 rpc url',
};
const rpc = new PolyjuiceJsonRpcProvider(polyjuiceConfig, polyjuiceConfig.web3Url);
const deployer = new PolyjuiceWallet('<your deployer private key>', polyjuiceConfig, rpc);
if you have multiple smart-contracts on the frontend, you can pass multiple abis to provider via setMultiAbi()
/ addAbi()
:
const polyjuiceConfig: PolyjuiceConfig = {
web3Url: 'godwoken web3 rpc url',
};
const provider = new PolyjuiceJsonRpcProvider(polyjuiceConfig, polyjuiceConfig.web3Url);
const abi_items_1 = [...];
const abi_items_2 = [...];
const abi_items_3 = [...];
provider.setMultiAbi([abi_items_1, abi_items_2, abi_items_3]);
// or
provider.addAbi(abi_items1);
provider.addAbi(abi_items2);
provider.addAbi(abi_items3);
when init websocket provider, one thing to pay attention is that you still need to feed PolyjuiceConfig with web3-http-rpc-url:
import { PolyjuiceWebsocketProvider } from "@polyjuice-provider/ethers";
const wsRpcUrl = "ws://localhost:8024/ws";
const httpRpcUrl = "http://localhost:8024";
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: httpRpcUrl, // this must be http/https url, ws url will not work here!
};
const rpc = new PolyjuiceWebsocketProvider(polyjuiceConfig, wsRpcUrl);
const deployer = new PolyjuiceWallet('<your deployer private key>', polyjuiceConfig, rpc);
import { ContractFactory } from "ethers";
import { PolyjuiceConfig } from "@polyjuice-provider/base";
import { PolyjuiceWallet, PolyjuiceJsonRpcProvider } from "@polyjuice-provider/ethers";
const polyjuiceConfig: PolyjuiceConfig = {
web3Url: 'godwoken web3 rpc url',
};
const rpc = new PolyjuiceJsonRpcProvider(polyjuiceConfig, polyjuiceConfig.web3Url);
const deployer = new PolyjuiceWallet('<your deployer private key>', polyjuiceConfig, rpc);
const implementationFactory = new ContractFactory(
contract.abi,
contract.bytecode,
deployer,
);
await deployer.godwoker.init();
const deployArgs = ['<your contract constructor args>'];
// you need the following step to convert the deployArgs before deploying contract:
const newDeployArgs = await deployer.convertDeployArgs(
deployArgs,
contract.abi as AbiItems,
contract.bytecode
);
const tx = implementationFactory.getDeployTransaction(...newDeployArgs);
tx.gasPrice = 0;
tx.gasLimit = 1_000_000;
deployer.sendTransaction(tx);
a more complete and real example can be found here
if your dapp are using ethers
and metamask
, you can simply change it like following:
import { providers, ContractFactory, Signer } from "ethers";
import { PolyjuiceHttpProvider } from "@polyjuice-provider/web3";
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
export async function createEthersSignerWithMetamask(): Promise<
Signer | undefined
> {
if ((window as any).ethereum) {
const provider = new providers.Web3Provider(
new PolyjuiceHttpProvider(polyjuiceConfig.web3Url!, polyjuiceConfig)
);
let signer;
try {
await (window as any).ethereum.enable();
signer = provider.getSigner((window as any).ethereum.selectedAddress);
} catch (error) {
// User denied account access...
throw error;
}
return signer;
}
console.error(
"Non-Ethereum browser detected. You should consider trying MetaMask!"
);
return undefined;
}
const signer = await createEthersSignerWithMetamask();
const contract = new ethers.Contract(
'your contract address',
'your contract abi',
signer
);
let overrides = {
gasLimit: 0x54d30,
gasPrice: 0x0,
value: 0x0,
};
const txResponse = await contract.METHOD_NAME(..args, overrides);
console.log(txResponse);
known issue:
if you want to use Metamask
and ethers.Contract
to deploy contract, then do not use the contract.address as your deployed contract address:
const deployContractWithEtherContractFactory = async () => {
const signer = await createEthersSignerWithMetamask();
const contractDeployer = new ContractFactory(
'your contract abi',
'your contract compiled bytecode',
signer
);
let overrides = {
gasLimit: 0x54d30,
gasPrice: 0x0,
value: 0x0,
};
const contract = await contractDeployer.deploy(overrides);
await contract.deployed();
// ! please do not use `contract.address` as contractAddress here.
// due to an known issue, it is wrong eth address in polyjuice.
// instead, you should get address through txReceipt.
const txReceipt = await rpc.eth_getTransactionReceipt(contract.deployTransaction.hash);
console.log(`contract address: ${txReceipt.contractAddress)}`);
}
yarn add @polyjuice-provider/web3
or
npm install --save @polyjuice-provider/web3
once you install this module, then you got 4 main tools to run with web3.js
for compatibility:
- PolyjuiceHttpProvider (compatible version of web3-providers-http)
- PolyjuiceAccounts (compatible version of web3.eth.accounts)
- PolyjuiceHttpProviderCli (old version solution for signing tx with web3.js in nodejs environment, now recommend use PolyjuiceAccounts instead of this module)
- PolyjuiceWebsocketProvider (compatible version of web3-providers-ws)
replacement:
new Web3HttpProvider(..) --> new PolyjuiceHttpProvider(...)
new Web3EthAccounts(..) ---> new PolyjuiceAccounts(...)
new Web3WsProvider(..) --> new PolyjuiceWebsocketProvider(...)
init library:
import { PolyjuiceConfig } from "@polyjuice-provider/base";
import { PolyjuiceHttpProvider, PolyjuiceAccounts } from "@polyjuice-provider/web3";
const polyjuiceConfig: PolyjuiceConfig = {
rollupTypeHash: 'godwoken rollup type hash', // this is optional
ethAccountLockCodeHash: 'godwoken eth account lock code hash', // this is optional
creatorId: 'polyjuice creator account id', // this is optional
defaultFromAddress: 'a default eth address, which will be used as a default from in ethereum transaction', // this is optional
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
provider = new PolyjuiceHttpProvider(
polyjuiceConfig.web3Url,
polyjuiceConfig,
);
polyjuiceAccounts = new PolyjuiceAccounts(polyjuiceConfig);
you can let provider find the polyjuiceConfig info by itself as well:
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
provider = new PolyjuiceHttpProvider(
polyjuiceConfig.web3Url,
polyjuiceConfig,
);
polyjuiceAccounts = new PolyjuiceAccounts(polyjuiceConfig);
that way provider will fetch polyjuiceConfig from web3 rpc server when those information are empty.
sometimes abiItem
can be omitted from constructor too: when you are not interacting with smart contracts, therefore there is no AbiItems needed to pass.
const polyjuiceConfig: PolyjuiceConfig = {
web3Url: 'godwoken web3 rpc url',
};
provider = new PolyjuiceHttpProvider(
polyjuiceConfig.web3Url,
polyjuiceConfig,
);
polyjuiceAccounts = new PolyjuiceAccounts(polyjuiceConfig);
if you have multiple smart-contracts on the frontend, you can pass multiple abis to provider via setMultiAbi()
/ addAbi()
:
const polyjuiceConfig: PolyjuiceConfig = {
web3Url: 'godwoken web3 rpc url',
};
const provider = new PolyjuiceHttpProvider(
polyjuiceConfig.web3Url,
polyjuiceConfig,
);
const abi_items_1 = [...];
const abi_items_2 = [...];
const abi_items_3 = [...];
provider.setMultiAbi([abi_items_1, abi_items_2, abi_items_3]);
// or
provider.addAbi(abi_items1);
provider.addAbi(abi_items2);
provider.addAbi(abi_items3);
when init websocket provider, one thing to pay attention is that you still need to feed PolyjuiceConfig with web3-http-rpc-url:
import { PolyjuiceWebsocketProvider } from "@polyjuice-provider/web3";
const wsRpcUrl = "ws://localhost:8024/ws";
const httpRpcUrl = "http://localhost:8024";
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: httpRpcUrl, // this must be http/https url, ws url will not work here!
};
const rpc = new PolyjuiceWebsocketProvider(wsRpcUrl, polyjuiceConfig);
const Web3 = require("web3");
const { PolyjuiceHttpProvider, PolyjuiceAccounts } = require("@polyjuice-provider/web3");
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
provider = new PolyjuiceHttpProvider(
godwokenRpcUrl,
polyjuiceConfig,
);
polyjuiceAccounts = new PolyjuiceAccounts(polyjuiceConfig);
await polyjuiceAccounts.godwoker.init();
const web3 = new Web3(provider);
web3.eth.accounts = polyjuiceAccounts;
web3.eth.Contract._accounts = web3.eth.accounts;
web3.eth.accounts.wallet.add(`your private key`);
const myContract = await web3.eth.Contract(`your contract's abi`);
const deployArgs = ['your contract constructor args'];
// you need the following step to convert the deployArgs before deploying contract:
const newDeployArgs = await polyjuiceAccounts.convertDeployArgs(
deployArgs,
'contract abi items',
'contract binary'
);
const contractInstance = myContract
.deploy({
data: `contract bin`,
arguments: newDeployArgs,
})
.send({
gas: "0x30d40",
gasPrice: "0x00"
});
const contract_deployed_address = contractInstance._address;
if your dapp are using web3.js
and metamask
, you can change it like this:
import Web3 from 'web3';
import { PolyjuiceConfig } from "@polyjuice-provider/base";
import { PolyjuiceHttpProvider } from '@polyjuice-provider/web3';
const polyjuiceConfig: PolyjuiceConfig = {
abiItems: ['your abi items array'],
web3Url: 'godwoken web3 rpc url',
};
var provider = new PolyjuiceHttpProvider('http://localhost:8024', polyjuiceConfig);
var web3 = new Web3(provider);
var contract = web3.eth.Contract(abi, contract_address);
yarn add @polyjuice-provider/truffle
or
npm install --save @polyjuice-provider/truffle
once you install this module, then you got the following tool to run inside truffle project for compatibility:
- PolyjuiceHDWalletProvider (compatible version of @truffle/hdwallet-provider)
replacement:
new HDWalletProvider(..) --> new PolyjuiceHDWalletProvider(...)
use PolyjuiceHDWalletProvider
in truffle-config.js for your truffle project.
const { PolyjuiceHDWalletProvider } = require("@polyjuice-provider/truffle");
const { PolyjuiceHttpProvider } = require("@polyjuice-provider/web3");
const polyjuiceConfig = {
web3Url: process.env.WEB3_JSON_RPC,
};
const polyjuiceHttpProvider = new PolyjuiceHttpProvider(
polyjuiceConfig.web3Url,
polyjuiceConfig
);
const polyjuiceTruffleProvider = new PolyjuiceHDWalletProvider(
[
{
privateKeys: [process.env.PRIVATE_KEY],
providerOrUrl: polyjuiceHttpProvider,
},
],
polyjuiceConfig
);
module.exports = {
networks: {
development: {
gasPrice: "0", // important for dryRun mode. 0 must be string type.
network_id: "*", // Any network (default: none)
provider: () => polyjuiceTruffleProvider,
}
};
checkout this example
Note: if contract constructor arguments contains address type parameter, you need to provide polyjuiceAddress instead of ethAddress, here provider can not do address-converting for you