@ethersproject/wallet#Wallet TypeScript Examples
The following examples show how to use
@ethersproject/wallet#Wallet.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: media.ts From zora-v1-subgraph with MIT License | 6 votes |
export async function transfer(
mediaAddress: string,
wallet: Wallet,
tokenId: BigNumber,
to: string
): Promise<string> {
const media = MediaFactory.connect(mediaAddress, wallet)
const tx = await media.transferFrom(wallet.address, to, tokenId)
await tx.wait()
return tx.hash
}
Example #2
Source File: getTransactionReceipt.test.ts From bodhi.js with Apache License 2.0 | 6 votes |
it('getTransactionReceipt', async () => {
const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944';
const account1 = evmAccounts[0];
const account2 = evmAccounts[1];
const provider = EvmRpcProvider.from(endpoint);
const account1Wallet = new Wallet(account1.privateKey).connect(provider as any);
const acaContract = new Contract(ADDRESS.ACA, ACAABI.abi, account1Wallet);
await provider.isReady();
const pairs = createTestPairs();
const oneAca = 10n ** BigInt(provider.api.registry.chainDecimals[0]);
const Alice = pairs.alice;
/** transfer aca */
console.log('transfer aca');
const extrinsic = provider.api.tx.balances.transfer(account1.defaultSubstrateAddress, 100n * oneAca);
await extrinsic.signAsync(Alice);
await sendTx(provider.api, extrinsic);
const result = await acaContract.functions.transfer(account2.evmAddress, 10n * oneAca, {
gasLimit: BigNumber.from(34132001n),
gasPrice: BigNumber.from(200786445289n),
type: 0
});
const receipt = await provider.getTransactionReceiptAtBlock(result.hash, result.blockHash);
expect(receipt.blockHash).equal(result.blockHash);
expect(receipt.logs.length).equal(1);
expect(receipt.logs[0].blockNumber).equal(result.blockNumber);
expect(receipt.logs[0].topics.length).equal(3);
await provider.disconnect();
});
Example #3
Source File: media.ts From zora-v1-subgraph with MIT License | 6 votes |
export async function updateTokenMetadataURI(
mediaAddress: string,
wallet: Wallet,
tokenId: BigNumber,
tokenMetadataURI: string
) {
const media = await MediaFactory.connect(mediaAddress, wallet)
const tx = await media.updateTokenMetadataURI(tokenId, tokenMetadataURI)
console.log(tx)
await tx.wait()
}
Example #4
Source File: index.ts From snapshot.js with MIT License | 6 votes |
async sign(web3: Web3Provider | Wallet, address: string, message, types) {
// @ts-ignore
const signer = web3?.getSigner ? web3.getSigner() : web3;
if (!message.from) message.from = address;
if (!message.timestamp)
message.timestamp = parseInt((Date.now() / 1e3).toFixed());
const data: any = { domain, types, message };
const sig = await signer._signTypedData(domain, data.types, message);
console.log('Sign', { address, sig, data });
return await this.send({ address, sig, data });
}
Example #5
Source File: index.ts From pownft-miner with Apache License 2.0 | 6 votes |
function loadConfig() : Config {
const targetFile = join(__dirname, '..', 'config.json');
const config = JSON.parse(readFileSync(targetFile) as any);
const accountPath = `m/44'/60'/0'/0/${config.index}`;
const provider = new JsonRpcProvider(config.provider);
const wallet = Wallet.fromMnemonic(config.mnemonic, accountPath).connect(provider);
const gasLimit = parseUnits(BigNumber.from(config.gasLimit).toString(), 'gwei');
return {
provider,
signer: wallet,
numCores: config.numCores,
gasLimit,
chunkSize: config.chunkSize,
dryRun: config.dryRun,
}
}
Example #6
Source File: seed.ts From zora-v1-subgraph with MIT License | 6 votes |
async function setUpNewCurrency(
provider: JsonRpcProvider,
masterWallet: Wallet,
marketAddress: string,
name: string,
symbol: string
) {
let currencyAddress = await deployCurrency(masterWallet, name, symbol)
// mint 100,000 BRECK for each wallet
console.log('Currency Address: ', currencyAddress)
console.log('Minting Currency for Each Generated Wallet')
for (const wallet of generatedWallets(provider)) {
await mintCurrency(
masterWallet,
currencyAddress,
wallet.address,
BigNumber.from('100000000000000000000000')
)
}
// for each address approve the market max uint256
console.log('Granting Approval to Market Contract for each Generated Wallet')
for (const wallet of generatedWallets(provider)) {
await approveCurrency(wallet, currencyAddress, marketAddress)
}
}
Example #7
Source File: createClaimSignature.ts From bodhi.js with Apache License 2.0 | 6 votes |
createClaimSignature = (privateKey: string, tx: ClaimPayload): string => {
const payload = createClaimPayload(tx);
const wallet = new Wallet(privateKey);
return joinSignature(
wallet._signingKey().signDigest(
_TypedDataEncoder.hash(
payload.domain,
{
Transaction: payload.types.Transaction
},
payload.message
)
)
);
}
Example #8
Source File: HoprChannels.spec.ts From hoprnet with GNU General Public License v3.0 | 6 votes |
describe('funding HoprChannel catches failures', function () {
let fixtures: Awaited<ReturnType<typeof useFixtures>>, channels: HoprChannels, accountA: Wallet
before(async function () {
// All of these tests revert, so we can rely on stateless single fixture.
fixtures = await useFixtures()
channels = fixtures.channels
accountA = fixtures.accountA
await fixtures.fundAndApprove(accountA, 100)
})
it('should fail to fund channel A->A', async function () {
await expect(
channels.connect(accountA).fundChannelMulti(ACCOUNT_A.address, ACCOUNT_A.address, '70', '30')
).to.be.revertedWith('source and destination must not be the same')
})
it('should fail to fund channel 0->A', async function () {
await expect(
channels.connect(accountA).fundChannelMulti(ethers.constants.AddressZero, ACCOUNT_B.address, '70', '30')
).to.be.revertedWith('source must not be empty')
})
it('should fail to fund channel A->0', async function () {
await expect(
channels.connect(accountA).fundChannelMulti(ACCOUNT_A.address, ethers.constants.AddressZero, '70', '30')
).to.be.revertedWith('destination must not be empty')
})
it('should fail to fund a channel with 0 amount', async function () {
await expect(
channels.connect(accountA).fundChannelMulti(ACCOUNT_A.address, ACCOUNT_B.address, '0', '0')
).to.be.revertedWith('amount must be greater than 0')
})
})
Example #9
Source File: mediaInfo.ts From core with GNU General Public License v3.0 | 6 votes |
async function start() {
const args = require('minimist')(process.argv.slice(2), {
string: ['tokenURI', 'metadataURI', 'contentHash', 'metadataHash'],
});
if (!args.chainId) {
throw new Error('--chainId chain ID is required');
}
if (!args.tokenId && args.tokenId !== 0) {
throw new Error('--tokenId token ID is required');
}
const path = `${process.cwd()}/.env${
args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local'
}`;
await require('dotenv').config({ path });
const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT);
const wallet = new Wallet(`0x${process.env.PRIVATE_KEY}`, provider);
const sharedAddressPath = `${process.cwd()}/addresses/${args.chainId}.json`;
// @ts-ignore
const addressBook = JSON.parse(await fs.readFileSync(sharedAddressPath));
if (!addressBook.media) {
throw new Error(`Media contract has not yet been deployed`);
}
const media = MediaFactory.connect(addressBook.media, wallet);
const tokenURI = await media.tokenURI(args.tokenId);
const contentHash = await media.tokenContentHashes(args.tokenId);
const metadataURI = await media.tokenMetadataURI(args.tokenId);
const metadataHash = await media.tokenMetadataHashes(args.tokenId);
console.log(`Media Information for token ${args.tokenId}`);
console.log({ tokenURI, contentHash, metadataURI, metadataHash });
}
Example #10
Source File: index.ts From snapshot.js with MIT License | 5 votes |
async unsubscribe(
web3: Web3Provider | Wallet,
address: string,
message: Unsubscribe
) {
return await this.sign(web3, address, message, unsubscribeTypes);
}
Example #11
Source File: bridge.test.ts From bodhi.js with Apache License 2.0 | 5 votes |
describe('e2e test', () => {
const signer = new Wallet('0x5a214c9bcb10dfe58af9b349cad6f4564cd6f10d880bdfcf780e5812c3cbc855');
const provider = EvmRpcProvider.from(endpoint);
const bridge = new Eip1193Bridge(provider, signer as any);
it('eth_getBlockByNumber latest', async () => {
const result = await bridge.send('eth_getBlockByNumber', ['latest', false]);
expect(typeof result.number).equal('string');
});
it('eth_getBlockByNumber u32', async () => {
await expect(bridge.send('eth_getBlockByNumber', ['0xffffffff', false])).become(null);
await expect(bridge.send('eth_getBlockByNumber', ['0x1ffffffff', false])).rejectedWith(
'block number should be less than u32'
);
});
it('eth_getBlockByHash', async () => {
await expect(
bridge.send('eth_getBlockByHash', ['0xff2d5d74f16df09b810225ffd9e1442250914ae6de9459477118d675713c732c', false])
).become(null);
const latest = await bridge.send('eth_getBlockByNumber', ['latest', false]);
const block = await bridge.send('eth_getBlockByHash', [latest.hash, false]);
expect(block.hash).equal(latest.hash);
});
it('eth_getBalance', async () => {
await expect(
bridge.send('eth_getBalance', ['0xb00cB924ae22b2BBb15E10c17258D6a2af980421', '0xffffffff'])
).rejectedWith('header not found');
});
after(() => {
provider.disconnect();
});
});
Example #12
Source File: index.ts From snapshot.js with MIT License | 5 votes |
async proposal(
web3: Web3Provider | Wallet,
address: string,
message: Proposal
) {
if (!message.discussion) message.discussion = '';
return await this.sign(web3, address, message, proposalTypes);
}
Example #13
Source File: index.ts From sdk with ISC License | 5 votes |
makeWalletSignerWithProvider = (
chainId: number,
privKey: string
): Wallet => new Wallet(privKey, rpcProviderForChain(chainId))
Example #14
Source File: utils.ts From hardhat-deploy with MIT License | 5 votes |
function transformNamedAccounts(
configNamedAccounts: {[name: string]: any},
chainIdGiven: string | number,
accounts: string[],
networkConfigName: string
): {
namedAccounts: {[name: string]: string};
unnamedAccounts: string[];
unknownAccounts: string[];
addressesToProtocol: {[address: string]: string};
} {
const addressesToProtocol: {[address: string]: string} = {};
const unknownAccountsDict: {[address: string]: boolean} = {};
const knownAccountsDict: {[address: string]: boolean} = {};
for (const account of accounts) {
knownAccountsDict[account.toLowerCase()] = true;
}
const namedAccounts: {[name: string]: string} = {};
const usedAccounts: {[address: string]: boolean} = {};
// TODO transform into checksum address
if (configNamedAccounts) {
const accountNames = Object.keys(configNamedAccounts);
// eslint-disable-next-line no-inner-declarations
function parseSpec(spec: any): string | undefined {
let address: string | undefined;
switch (typeof spec) {
case 'string':
// eslint-disable-next-line no-case-declarations
const protocolSplit = spec.split('://');
if (protocolSplit.length > 1) {
if (protocolSplit[0].toLowerCase() === 'ledger') {
address = protocolSplit[1];
addressesToProtocol[address.toLowerCase()] =
protocolSplit[0].toLowerCase();
// knownAccountsDict[address.toLowerCase()] = true; // TODO ? this would prevent auto impersonation in fork/test
} else if (protocolSplit[0].toLowerCase() === 'privatekey') {
address = new Wallet(protocolSplit[1]).address;
addressesToProtocol[address.toLowerCase()] =
'privatekey://' + protocolSplit[1];
} else {
throw new Error(
`unsupported protocol ${protocolSplit[0]}:// for named accounts`
);
}
} else {
if (spec.slice(0, 2).toLowerCase() === '0x') {
if (!isAddress(spec)) {
throw new Error(
`"${spec}" is not a valid address, if you used to put privateKey there, use the "privatekey://" prefix instead`
);
}
address = spec;
} else {
address = parseSpec(configNamedAccounts[spec]);
}
}
break;
case 'number':
if (accounts) {
address = accounts[spec];
}
break;
case 'undefined':
break;
case 'object':
if (spec) {
if (spec.type === 'object') {
address = spec;
} else {
const newSpec = chainConfig(
spec,
chainIdGiven,
networkConfigName
);
if (typeof newSpec !== 'undefined') {
address = parseSpec(newSpec);
}
}
}
break;
}
if (address) {
if (typeof address === 'string') {
address = getAddress(address);
}
}
return address;
}
for (const accountName of accountNames) {
const spec = configNamedAccounts[accountName];
const address = parseSpec(spec);
if (address) {
namedAccounts[accountName] = address;
usedAccounts[address.toLowerCase()] = true;
if (!knownAccountsDict[address.toLowerCase()]) {
unknownAccountsDict[address.toLowerCase()] = true;
}
}
}
}
const unnamedAccounts = [];
for (const address of accounts) {
if (!usedAccounts[address.toLowerCase()]) {
unnamedAccounts.push(getAddress(address));
}
}
return {
namedAccounts,
unnamedAccounts,
unknownAccounts: Object.keys(unknownAccountsDict).map(getAddress),
addressesToProtocol,
};
}
Example #15
Source File: claim.test.ts From bodhi.js with Apache License 2.0 | 5 votes |
describe('create Claim Signature', () => {
it('invalid substrateAddress', async () => {
expect(() => {
createClaimPayload({
salt: '0x000',
chainId: 55,
substrateAddress: '5G'
});
}).throw('invalid substrateAddress');
});
it('missing salt', async () => {
expect(() => {
// @ts-ignore
createClaimPayload({
chainId: 55,
substrateAddress: '5G'
});
}).throw('missing salt');
});
it('missing chainId', async () => {
expect(() => {
// @ts-ignore
createClaimPayload({
salt: '0x000',
substrateAddress: '5G'
});
}).throw('missing chainId');
});
it('claim payload', async () => {
const payload = createClaimPayload({
salt: '0x702ba380a53e096363da1b73f2a05faff77c274fd356253eb877e6d221b7ffe7',
chainId: 595,
substrateAddress: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
});
expect(payload.domain.name).equal('Acala EVM claim');
});
it('create claim signature', async () => {
const wallet = new Wallet('0xc192608c543cda2e2c2a2ec33237d4e9d0922831bdac423c90af697dee017aaf');
expect(wallet.address).equal('0x183d3DDcF0D69A84677ab1aC42a7014dA7971695');
const signature = createClaimSignature(wallet.privateKey, {
salt: '0x702ba380a53e096363da1b73f2a05faff77c274fd356253eb877e6d221b7ffe7',
chainId: 595,
substrateAddress: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'
});
expect(signature).equal(
'0xd71741a11559335ce336daad28bb04bd0ed2977b9da31a1f7686162209a151676cbc475679844ff98febe3e439fec3c24ddf5560467a5f53cc1472d4eada8a211c'
);
});
});
Example #16
Source File: relayer.ts From snapshot-hub with MIT License | 5 votes |
wallet = new Wallet(privateKey)
Example #17
Source File: HoprChannels.spec.ts From hoprnet with GNU General Public License v3.0 | 5 votes |
useFixtures = deployments.createFixture(
async (_, ops: { skipAnnounceForAccountA: boolean; skipAnnounceForAccountB: boolean }) => {
const deployer = ethers.provider.getSigner()
const deployerPubKey = await recoverPublicKeyFromSigner(deployer)
const accountA = new ethers.Wallet(ACCOUNT_A.privateKey).connect(ethers.provider)
const accountAPubKey = PublicKey.fromPrivKeyString(accountA.privateKey)
const accountB = new ethers.Wallet(ACCOUNT_B.privateKey).connect(ethers.provider)
const accountBPubKey = PublicKey.fromPrivKeyString(accountB.privateKey)
// run migrations
const contracts = await deployments.fixture()
const token = (await ethers.getContractFactory('HoprToken')).attach(contracts['HoprToken'].address) as HoprToken
const channels = (await ethers.getContractFactory('HoprChannels')).attach(
contracts['HoprChannels'].address
) as HoprChannels
const mockChannels = (await (
await ethers.getContractFactory('ChannelsMock', deployer)
).deploy(token.address, 0)) as ChannelsMock
// create deployer the minter
const minterRole = await token.MINTER_ROLE()
await token.connect(deployer).grantRole(minterRole, await deployer.getAddress())
const fundEther = async (addr: string, amount: BigNumberish) =>
await deployer.sendTransaction({ to: addr, value: amount })
const fund = async (addr: string, amount: BigNumberish) =>
await token.connect(deployer).mint(addr, amount + '', ethers.constants.HashZero, ethers.constants.HashZero)
const approve = async (account: Wallet, amount: BigNumberish) =>
await token.connect(account).approve(channels.address, amount)
const fundAndApprove = async (account: Wallet, amount: BigNumberish) => {
await fund(account.address, amount)
await approve(account, amount)
}
const TICKET_AB_WIN = await createTicket(
{
recipient: ACCOUNT_B.address,
proofOfRelaySecret: PROOF_OF_RELAY_SECRET_0,
ticketEpoch: '0',
ticketIndex: '1',
amount: '10',
winProb: WIN_PROB_100.toString(),
channelEpoch: '1'
},
ACCOUNT_A,
SECRET_1
)
await fundEther(accountA.address, ethers.utils.parseEther(ChannelStatus.Open + ''))
await fundEther(accountB.address, ethers.utils.parseEther(ChannelStatus.Open + ''))
// announce
if (!ops?.skipAnnounceForAccountA) {
await channels
.connect(accountA)
.announce(accountAPubKey.toUncompressedPubKeyHex(), [], { gasLimit: BigNumber.from('100000') })
}
if (!ops?.skipAnnounceForAccountB) {
await channels
.connect(accountB)
.announce(accountBPubKey.toUncompressedPubKeyHex(), [], { gasLimit: BigNumber.from('100000') })
}
return {
token,
channels,
deployer,
deployerPubKey,
accountA,
accountAPubKey,
accountB,
accountBPubKey,
fund,
approve,
mockChannels,
fundAndApprove,
TICKET_AB_WIN
}
}
)
Example #18
Source File: media.ts From zora-v1-subgraph with MIT License | 5 votes |
export async function totalSupply(mediaAddress: string, wallet: Wallet) {
const media = MediaFactory.connect(mediaAddress, wallet)
return await media.totalSupply()
}
Example #19
Source File: deploy.ts From core with GNU General Public License v3.0 | 5 votes |
async function start() {
const args = require('minimist')(process.argv.slice(2));
if (!args.chainId) {
throw new Error('--chainId chain ID is required');
}
const path = `${process.cwd()}/.env${
args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local'
}`;
await require('dotenv').config({ path });
const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT);
const wallet = new Wallet(`0x${process.env.PRIVATE_KEY}`, provider);
const sharedAddressPath = `${process.cwd()}/addresses/${args.chainId}.json`;
// @ts-ignore
const addressBook = JSON.parse(await fs.readFileSync(sharedAddressPath));
if (addressBook.market) {
throw new Error(
`market already exists in address book at ${sharedAddressPath}. Please move it first so it is not overwritten`
);
}
if (addressBook.media) {
throw new Error(
`media already exists in address book at ${sharedAddressPath}. Please move it first so it is not overwritten`
);
}
console.log('Deploying Market...');
const deployTx = await new MarketFactory(wallet).deploy();
console.log('Deploy TX: ', deployTx.deployTransaction.hash);
await deployTx.deployed();
console.log('Market deployed at ', deployTx.address);
addressBook.market = deployTx.address;
console.log('Deploying Media...');
const mediaDeployTx = await new MediaFactory(wallet).deploy(
addressBook.market
);
console.log(`Deploy TX: ${mediaDeployTx.deployTransaction.hash}`);
await mediaDeployTx.deployed();
console.log(`Media deployed at ${mediaDeployTx.address}`);
addressBook.media = mediaDeployTx.address;
console.log('Configuring Market...');
const market = MarketFactory.connect(addressBook.market, wallet);
const tx = await market.configure(addressBook.media);
console.log(`Market configuration tx: ${tx.hash}`);
await tx.wait();
console.log(`Market configured.`);
await fs.writeFile(sharedAddressPath, JSON.stringify(addressBook, null, 2));
console.log(`Contracts deployed and configured. ☼☽`);
}
Example #20
Source File: media.ts From zora-v1-subgraph with MIT License | 5 votes |
export async function burn(mediaAddress: string, wallet: Wallet, tokenId: BigNumber) {
const media = await MediaFactory.connect(mediaAddress, wallet)
const tx = await media.burn(tokenId)
console.log(tx)
await tx.wait()
}
Example #21
Source File: mint.ts From core with GNU General Public License v3.0 | 5 votes |
async function start() {
const args = require('minimist')(process.argv.slice(2), {
string: ['tokenURI', 'metadataURI', 'contentHash', 'metadataHash'],
});
if (!args.chainId) {
throw new Error('--chainId chain ID is required');
}
if (!args.tokenURI) {
throw new Error('--tokenURI token URI is required');
}
if (!args.metadataURI) {
throw new Error('--metadataURI metadata URI is required');
}
if (!args.contentHash) {
throw new Error('--contentHash content hash is required');
}
if (!args.metadataHash) {
throw new Error('--metadataHash content hash is required');
}
if (!args.creatorShare && args.creatorShare !== 0) {
throw new Error('--creatorShare creator share is required');
}
const path = `${process.cwd()}/.env${
args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local'
}`;
await require('dotenv').config({ path });
const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT);
// const wallet = new Wallet(`0x${process.env.PRIVATE_KEY}`, provider);
const wallet = new Wallet(`0x${process.env.PRIVATE_KEY}`, provider);
const sharedAddressPath = `${process.cwd()}/addresses/${args.chainId}.json`;
// @ts-ignore
const addressBook = JSON.parse(await fs.readFileSync(sharedAddressPath));
if (!addressBook.media) {
throw new Error(`Media contract has not yet been deployed`);
}
const media = MediaFactory.connect(addressBook.media, wallet);
console.log(
'Minting... ',
args.tokenURI,
args.contentHash,
args.metadataURI,
args.metadataHash
);
await media.mint(
{
tokenURI: args.tokenURI,
metadataURI: args.metadataURI,
contentHash: Uint8Array.from(Buffer.from(args.contentHash, 'hex')),
metadataHash: Uint8Array.from(Buffer.from(args.metadataHash, 'hex')),
},
{
prevOwner: Decimal.new(0),
creator: Decimal.new(args.creatorShare),
owner: Decimal.new(100 - args.creatorShare),
}
);
console.log(`New piece is minted ☼☽`);
}
Example #22
Source File: auctionHouse.ts From zora-v1-subgraph with MIT License | 5 votes |
async function runAuction() {
const args = require('minimist')(process.argv.slice(2))
if (!args.chainId) {
throw new Error('--chainId chain ID is required')
}
if(!args.tokenId && args.tokenId !== 0) {
throw new Error('--tokenId is required')
}
const path = `${process.cwd()}/.env${
args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local'
}`
await require('dotenv').config({path})
const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT)
let [creator, curator, bidder1, bidder2] = privateKeys.map((pk) => new Wallet(pk, provider))
const sharedAddressPath = `${process.cwd()}/config/${args.chainId}.json`
// @ts-ignore
const config = JSON.parse(await fs.readFile(sharedAddressPath))
if (config.mediaAddress === null) {
throw new Error('media address not specified in config')
}
if (config.marketAddress === null) {
throw new Error('market address not specified in config')
}
if(config.auctionHouseAddress === null) {
throw new Error('auctionHouse address not specified in config')
}
const { mediaAddress, marketAddress, auctionHouseAddress} = config;
const TENTH_ETH = ethers.utils.parseUnits("0.1", "ether") as BigNumber;
const ONE_ETH = ethers.utils.parseUnits("1", "ether") as BigNumber;
const TWO_ETH = ethers.utils.parseUnits("2", "ether") as BigNumber;
const ONE_DAY = 24 * 60 * 60;
const media = MediaFactory.connect(mediaAddress, creator)
// @ts-ignore
const auction = AuctionHouse__factory.connect(auctionHouseAddress, creator)
// Approve the auction
console.log('approving transfer to auction')
await (await media.approve(auctionHouseAddress, args.tokenId)).wait()
// Create the auction
console.log('creating auction')
await (await auction.createAuction(args.tokenId, mediaAddress, ONE_DAY, TENTH_ETH.toString(), curator.address, 15, ethers.constants.AddressZero)).wait()
console.log('approving auction as curator')
// @ts-ignore
await (await auction.connect(curator).setAuctionApproval(mediaAddress, args.tokenId, true)).wait()
console.log('Creating first bid')
await auction
// @ts-ignore
.connect(bidder1)
.createBid(media.address, 0, ONE_ETH.toString(), { value: ONE_ETH.toString() });
console.log('Creating second bid')
await auction
// @ts-ignore
.connect(bidder2)
.createBid(media.address, 0, TWO_ETH.toString(), { value: TWO_ETH.toString() });
console.log('fast forwarding time')
await provider.send("evm_increaseTime", [
ONE_DAY
]);
await auction.endAuction(media.address, args.tokenId);
}
Example #23
Source File: tx.test.ts From bodhi.js with Apache License 2.0 | 4 votes |
describe('transaction tests', () => {
const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944';
const provider = EvmRpcProvider.from(endpoint);
const account1 = evmAccounts[0];
const account2 = evmAccounts[1];
const account3 = evmAccounts[2];
const account4 = evmAccounts[3];
const wallet1 = new Wallet(account1.privateKey).connect(provider as any);
const wallet2 = new Wallet(account2.privateKey).connect(provider as any);
const wallet3 = new Wallet(account3.privateKey).connect(provider as any);
const wallet4 = new Wallet(account4.privateKey).connect(provider as any);
let chainId: number;
let storageByteDeposit: bigint;
let txFeePerGas: bigint;
let txGasLimit: BigNumber;
let txGasPrice: BigNumber;
before('prepare common variables', async () => {
await provider.isReady();
chainId = await provider.chainId();
storageByteDeposit = (provider.api.consts.evm.storageDepositPerByte as UInt).toBigInt();
txFeePerGas = (provider.api.consts.evm.txFeePerGas as UInt).toBigInt();
({ txGasLimit, txGasPrice } = calcEthereumTransactionParams({
gasLimit: 2100001n,
validUntil: 360001n,
storageLimit: 64001n,
txFeePerGas,
storageByteDeposit
}));
});
after('clean up', async () => {
await provider.disconnect();
});
describe('test eth gas', () => {
it('getEthResources', async () => {
const randomWallet = Wallet.createRandom().connect(provider);
const amount = '1000000000000000000';
const resources = await provider.getEthResources({
type: 0,
from: wallet3.address,
to: randomWallet.address,
value: BigNumber.from(amount)
});
await wallet3.sendTransaction({
type: 0,
to: randomWallet.address,
value: BigNumber.from(amount),
...resources
});
expect((await randomWallet.getBalance()).toString()).eq(amount);
});
it('getPrice', async () => {
const randomWallet = Wallet.createRandom().connect(provider);
const amount = '1000000000000000000';
const params = await wallet3.populateTransaction({
type: 0,
to: randomWallet.address,
value: BigNumber.from(amount)
});
const data = provider.validSubstrateResources({
gasLimit: params.gasLimit,
gasPrice: params.gasPrice
});
console.log({
gasLimit: data.gasLimit.toString(),
storageLimit: data.storageLimit.toString(),
validUntil: data.validUntil.toString()
});
// expect((await randomWallet.getBalance()).toString()).eq(amount);
});
});
describe('test the error tx', () => {
it('InvalidDecimals', async () => {
await expect(
wallet1.sendTransaction({
type: 0,
to: wallet2.address,
value: 1000001,
gasLimit: txGasLimit,
gasPrice: txGasPrice
})
).to.be.rejectedWith('InvalidDecimals');
});
it('OutOfFund', async () => {
await expect(
wallet1.sendTransaction({
type: 0,
to: wallet2.address,
value: 1000000000n * 10n ** 18n,
gasLimit: txGasLimit,
gasPrice: txGasPrice
})
).to.be.rejectedWith('OutOfFund');
});
it('ExistentialDeposit', async () => {
await expect(
wallet3.sendTransaction({
type: 0,
to: Wallet.createRandom().address,
value: 1000000,
gasLimit: txGasLimit,
gasPrice: txGasPrice
})
).to.be.rejectedWith('ExistentialDeposit');
});
});
describe('test deploy contract (hello world)', () => {
const deployHelloWorldData =
'0x60806040526040518060400160405280600c81526020017f48656c6c6f20576f726c642100000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b61022e806101756000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c605f76c14610030575b600080fd5b61003861004e565b6040516100459190610175565b60405180910390f35b6000805461005b906101c6565b80601f0160208091040260200160405190810160405280929190818152602001828054610087906101c6565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b600081519050919050565b600082825260208201905092915050565b60005b838110156101165780820151818401526020810190506100fb565b83811115610125576000848401525b50505050565b6000601f19601f8301169050919050565b6000610147826100dc565b61015181856100e7565b93506101618185602086016100f8565b61016a8161012b565b840191505092915050565b6000602082019050818103600083015261018f818461013c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806101de57607f821691505b602082108114156101f2576101f1610197565b5b5091905056fea26469706673582212204d363ed34111d1be492d4fd086e9f2df62b3c625e89ade31f30e63201ed1e24f64736f6c63430008090033';
let partialDeployTx;
before(() => {
partialDeployTx = {
chainId,
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: deployHelloWorldData,
value: BigNumber.from(0)
};
});
describe('with wallet', () => {
it('succeeds', async () => {
const response = await wallet1.sendTransaction({
...partialDeployTx,
type: 0
});
const receipt = await response.wait(0);
expect(receipt.type).equal(0);
expect(receipt.status).equal(1);
expect(receipt.from).equal(wallet1.address);
});
});
describe('with legacy EIP-155 signature', () => {
it('serialize, parse, and send tx correctly', async () => {
const unsignedTx: AcalaEvmTX = {
...partialDeployTx,
nonce: await wallet1.getTransactionCount()
};
const rawTx = await wallet1.signTransaction(unsignedTx);
const parsedTx = parseTransaction(rawTx);
expect(parsedTx.gasPrice.eq(txGasPrice)).equal(true);
expect(parsedTx.gasLimit.eq(txGasLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(null);
expect(parsedTx.maxPriorityFeePerGas).equal(undefined);
expect(parsedTx.maxFeePerGas).equal(undefined);
const response = await provider.sendTransaction(rawTx);
const receipt = await response.wait(0);
expect(receipt.type).equal(0); // TODO: should be null, need to fix getPartialTransactionReceipt
expect(receipt.status).equal(1);
expect(receipt.from).equal(wallet1.address);
});
});
describe('with EIP-1559 signature', () => {
it('serialize, parse, and send tx correctly', async () => {
const priorityFee = BigNumber.from(2);
const unsignedTx: AcalaEvmTX = {
...partialDeployTx,
nonce: await wallet1.getTransactionCount(),
gasPrice: undefined,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: txGasPrice,
type: 2
};
const rawTx = await wallet1.signTransaction(unsignedTx);
const parsedTx = parseTransaction(rawTx);
expect(parsedTx.maxFeePerGas.eq(txGasPrice)).equal(true);
expect(parsedTx.maxPriorityFeePerGas.eq(priorityFee)).equal(true);
expect(parsedTx.gasLimit.eq(txGasLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(2);
expect(parsedTx.gasPrice).equal(null);
const response = await provider.sendTransaction(rawTx);
const receipt = await response.wait(0);
expect(receipt.type).equal(0); // TODO: should be 2, need to fix getPartialTransactionReceipt
expect(receipt.status).equal(1);
expect(receipt.from).equal(wallet1.address);
});
});
describe('with EIP-712 signature', () => {
let rawTx1: string;
let rawTx2: string;
it('serialize, parse, and send tx correctly', async () => {
const gasLimit = BigNumber.from('210000');
const validUntil = 10000;
const storageLimit = 100000;
const unsignEip712Tx: AcalaEvmTX = {
...partialDeployTx,
nonce: await wallet1.getTransactionCount(),
salt: provider.genesisHash,
gasLimit,
validUntil,
storageLimit,
type: 0x60,
accessList: []
};
const sig = signTransaction(account1.privateKey, unsignEip712Tx);
rawTx1 = serializeTransaction(unsignEip712Tx, sig);
const parsedTx = parseTransaction(rawTx1);
expect(parsedTx.gasLimit.eq(gasLimit)).equal(true);
expect(parsedTx.validUntil.eq(validUntil)).equal(true);
expect(parsedTx.storageLimit.eq(storageLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(96);
expect(parsedTx.maxPriorityFeePerGas).equal(undefined);
expect(parsedTx.maxFeePerGas).equal(undefined);
});
it('eip712 tip', async () => {
const gasLimit = BigNumber.from('210000');
const validUntil = 10000;
const storageLimit = 100000;
const unsignEip712Tx: AcalaEvmTX = {
...partialDeployTx,
nonce: (await wallet1.getTransactionCount()) + 1,
salt: provider.genesisHash,
gasLimit,
validUntil,
storageLimit,
tip: 2,
type: 0x60,
accessList: []
};
const sig = signTransaction(account1.privateKey, unsignEip712Tx);
rawTx2 = serializeTransaction(unsignEip712Tx, sig);
const parsedTx = parseTransaction(rawTx2);
expect(parsedTx.gasLimit.eq(gasLimit)).equal(true);
expect(parsedTx.validUntil.eq(validUntil)).equal(true);
expect(parsedTx.storageLimit.eq(storageLimit)).equal(true);
expect(parsedTx.tip.eq(2)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(96);
expect(parsedTx.maxPriorityFeePerGas).equal(undefined);
expect(parsedTx.maxFeePerGas).equal(undefined);
});
it('send eip712 tx', async () => {
await provider.sendTransaction(rawTx1);
await provider.sendTransaction(rawTx2);
});
});
});
describe('test call contract (transfer ACA)', () => {
const ACADigits = provider.api.registry.chainDecimals[0];
const acaContract = new Contract(ADDRESS.ACA, ACAABI.abi, wallet1);
const iface = new Interface(ACAABI.abi);
const queryBalance = (addr) => acaContract.balanceOf(addr) as BigNumber;
const transferAmount = parseUnits('100', ACADigits);
let partialTransferTX: any;
before(() => {
partialTransferTX = {
chainId,
to: ADDRESS.ACA,
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: iface.encodeFunctionData('transfer', [account2.evmAddress, transferAmount]),
value: BigNumber.from(0)
};
});
it('evm address match', () => {
expect(computeDefaultSubstrateAddress(account1.evmAddress)).to.equal(account1.defaultSubstrateAddress);
expect(computeDefaultSubstrateAddress(account2.evmAddress)).to.equal(account2.defaultSubstrateAddress);
});
describe('with provider', () => {
it('has correct balance after transfer', async () => {
const pairs = createTestPairs();
const alice = pairs.alice;
const oneAca = 10n ** BigInt(ACADigits);
const amount = 1000n * oneAca;
const balance = await queryBalance(account1.evmAddress);
const extrinsic = provider.api.tx.balances.transfer(account1.defaultSubstrateAddress, amount);
await extrinsic.signAsync(alice);
await sendTx(provider.api, extrinsic);
const _balance = await queryBalance(account1.evmAddress);
expect(_balance.sub(balance).toBigInt()).equal(amount);
});
});
describe('with legacy EIP-155 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: await wallet1.getTransactionCount()
};
const rawTx = await wallet1.signTransaction(transferTX);
const parsedTx = parseTransaction(rawTx);
const response = await provider.sendTransaction(rawTx);
const receipt = await response.wait(0);
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check sender's balance is correct
// expect(balance1.sub(_balance1).toNumber()).equal(transferAmount.toNumber() + gasUsed);
expect(_balance2.sub(balance2).toNumber()).equal(transferAmount.toNumber());
});
});
describe('with EIP-1559 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const priorityFee = BigNumber.from(2);
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: await wallet1.getTransactionCount(),
gasPrice: undefined,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: txGasPrice,
type: 2
};
const rawTx = await wallet1.signTransaction(transferTX);
const parsedTx = parseTransaction(rawTx);
const response = await provider.sendTransaction(rawTx);
const receipt = await response.wait(0);
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check sender's balance is correct
// expect(balance1.sub(_balance1).toNumber()).equal(transferAmount.toNumber() + gasUsed);
expect(_balance2.sub(balance2).toNumber()).equal(transferAmount.toNumber());
});
});
describe('with EIP-712 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const gasLimit = BigNumber.from('210000');
const validUntil = 10000;
const storageLimit = 100000;
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: await wallet1.getTransactionCount(),
salt: provider.genesisHash,
gasLimit,
validUntil,
storageLimit,
type: 0x60,
accessList: []
};
const sig = signTransaction(account1.privateKey, transferTX);
const rawTx = serializeTransaction(transferTX, sig);
const parsedTx = parseTransaction(rawTx);
await provider.sendTransaction(rawTx);
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check sender's balance is correct
// expect(balance1.sub(_balance1).toNumber()).equal(transferAmount.toNumber() + gasUsed);
expect(_balance2.sub(balance2).toNumber()).equal(transferAmount.toNumber());
});
});
});
});
Example #24
Source File: deploy.ts From zora-v1-subgraph with MIT License | 4 votes |
async function start() {
const args = require('minimist')(process.argv.slice(2))
if (!args.chainId) {
throw new Error('--chainId chain ID is required')
}
const path = `${process.cwd()}/.env${
args.chainId === 1 ? '.prod' : args.chainId === 4 ? '.dev' : '.local'
}`
await require('dotenv').config({ path })
const provider = new JsonRpcProvider(process.env.RPC_ENDPOINT)
const wallet = new Wallet(`0x${process.env.PRIVATE_KEY}`, provider)
const sharedAddressPath = `${process.cwd()}/config/${args.chainId}.json`
// @ts-ignore
const config = JSON.parse(await fs.readFileSync(sharedAddressPath))
if (config.marketAddress) {
throw new Error(
`market already exists in address book at ${sharedAddressPath}. Please move it first so it is not overwritten`
)
}
if (config.mediaAddress) {
throw new Error(
`media already exists in address book at ${sharedAddressPath}. Please move it first so it is not overwritten`
)
} if (!config.wethAddress && args.chainId !== 50) {
throw new Error(
`weth Address missing in address book at ${sharedAddressPath}. Please add it first`
)
}
console.log('Deploying Market...')
const deployTx = await new MarketFactory(wallet).deploy()
console.log('Deploy TX: ', deployTx.deployTransaction.hash)
await deployTx.deployed()
console.log('Market deployed at ', deployTx.address)
config.marketAddress = deployTx.address.substring(2)
const receipt = await provider.getTransactionReceipt(deployTx.deployTransaction.hash)
config.marketStartBlock = receipt.blockNumber
console.log('Deploying Media...')
const mediaDeployTx = await new MediaFactory(wallet).deploy(config.marketAddress)
console.log(`Deploy TX: ${mediaDeployTx.deployTransaction.hash}`)
await mediaDeployTx.deployed()
console.log(`Media deployed at ${mediaDeployTx.address}`)
config.mediaAddress = mediaDeployTx.address.substring(2)
const mediaReceipt = await provider.getTransactionReceipt(
mediaDeployTx.deployTransaction.hash
)
config.mediaStartBlock = mediaReceipt.blockNumber
console.log('Configuring Market...')
const market = MarketFactory.connect(config.marketAddress, wallet)
const tx = await market.configure(config.mediaAddress)
console.log(`Market configuration tx: ${tx.hash}`)
await tx.wait()
console.log(`Market configured.`)
// Deploy WETH locally if necessary
if(args.chainId === 50) {
console.log('Deploying WETH...')
// @ts-ignore
const wethDeploy = await new WETH__factory(wallet).deploy()
await wethDeploy.deployed()
config.wethAddress = wethDeploy.address
}
console.log('Deploying Auction House')
// @ts-ignore
const auctionHouseDeployTx = await new AuctionHouse__factory(wallet).deploy(config.mediaAddress, config.wethAddress)
console.log(`Deploy TX: ${auctionHouseDeployTx.deployTransaction.hash}`)
await auctionHouseDeployTx.deployed()
console.log(`Auction house deployed at ${auctionHouseDeployTx.address}`)
config.auctionHouseAddress = auctionHouseDeployTx.address.substring(2)
const auctionHouseReceipt = await provider.getTransactionReceipt(
auctionHouseDeployTx.deployTransaction.hash
)
config.auctionHouseStartBlock = auctionHouseReceipt.blockNumber
config.network = args.chainId === 4 ? 'rinkeby' : 'mainnet'
await fs.writeFile(sharedAddressPath, JSON.stringify(config, null, 2))
console.log(`Contracts deployed and configured. ☼☽`)
}
Example #25
Source File: ProviderInteractions-test.ts From sdk with ISC License | 4 votes |
describe("SynapseBridge - Provider Interactions tests", async function(this: Mocha.Suite) {
interface TestOpts {
executeSuccess: boolean,
canBridge: boolean,
}
interface TestCase extends BridgeSwapTestCase<TestOpts> {
callStatic: boolean,
}
const executeFailAmt: BigNumber = parseEther("420.696969");
const testCases: TestCase[] = [
{
args: {
tokenFrom: Tokens.ETH,
tokenTo: Tokens.WETH,
chainIdFrom: ChainId.OPTIMISM,
chainIdTo: ChainId.ETH,
amountFrom: executeFailAmt,
},
expected: {
executeSuccess: false,
canBridge: false,
},
callStatic: false,
},
{
args: {
tokenFrom: Tokens.ETH,
tokenTo: Tokens.WETH,
chainIdFrom: ChainId.BOBA,
chainIdTo: ChainId.ETH,
amountFrom: executeFailAmt,
},
expected: {
executeSuccess: false,
canBridge: false,
},
callStatic: true,
},
{
args: {
tokenFrom: Tokens.ETH,
tokenTo: Tokens.WETH_E,
chainIdFrom: ChainId.ARBITRUM,
chainIdTo: ChainId.AVALANCHE,
amountFrom: parseEther("0.005"),
},
expected: {
executeSuccess: true,
canBridge: true,
},
callStatic: true,
},
// {
// args: {
// tokenFrom: Tokens.WETH_E,
// tokenTo: Tokens.ETH,
// chainIdFrom: ChainId.AVALANCHE,
// chainIdTo: ChainId.ARBITRUM,
// amountFrom: parseEther("0.05"),
// },
// expected: {
// executeSuccess: false,
// canBridge: false,
// },
// callStatic: true,
// },
{
args: {
tokenFrom: Tokens.ETH,
tokenTo: Tokens.NETH,
chainIdFrom: ChainId.ETH,
chainIdTo: ChainId.OPTIMISM,
amountFrom: executeFailAmt,
},
expected: {
executeSuccess: false,
canBridge: false,
},
callStatic: true,
},
{
args: {
tokenFrom: Tokens.ETH,
tokenTo: Tokens.NETH,
chainIdFrom: ChainId.ETH,
chainIdTo: ChainId.OPTIMISM,
amountFrom: executeFailAmt,
},
expected: {
executeSuccess: false,
canBridge: false,
},
callStatic: false,
},
{
args: {
tokenFrom: Tokens.NUSD,
tokenTo: Tokens.USDT,
chainIdFrom: ChainId.POLYGON,
chainIdTo: ChainId.FANTOM,
amountFrom: parseEther("666"),
},
expected: {
executeSuccess: false,
canBridge: false,
},
callStatic: false,
},
];
const getBridgeEstimate = async (
tc: TestCase,
{
address,
bridgeInstance,
}: WalletArgs
): Promise<EstimateOutputs> =>
bridgeInstance.estimateBridgeTokenOutput(tc.args)
.then(res =>
({
outputEstimate: res,
bridgeArgs: {
...tc.args,
amountTo: res.amountToReceive,
addressTo: address,
}
})
)
.catch(rejectPromise)
testCases.forEach(tc => {
const
describeNetFromTitle: string = `${tc.args.tokenFrom.symbol} on ${Networks.networkName(tc.args.chainIdFrom)}`,
desribeNetToTitle: string = `${tc.args.tokenTo.symbol} on ${Networks.networkName(tc.args.chainIdTo)}`,
execModeTitle: string = tc.callStatic ? "(CallStatic)" : "(Signer Sends)",
describeTitle: string = `Test ${describeNetFromTitle} to ${desribeNetToTitle} ${execModeTitle}`,
executionTestSuffix: string = `should ${tc.expected.executeSuccess ? "execute succesfully" : "fail"}`;
const
executeTxnTestTitle = (txnKind: string): string => `${txnKind} transaction ${executionTestSuffix}`,
approvalTxnTestTitle: string = executeTxnTestTitle("ERC20.Approve"),
bridgeTxnTestTitle: string = executeTxnTestTitle("SynapseBridge token bridge");
describe(describeTitle, function(this: Mocha.Suite) {
let
walletArgs: WalletArgs,
wallet: Wallet,
bridgeInstance: Bridge.SynapseBridge;
before(async function(this: Mocha.Context) {
this.timeout(DEFAULT_TEST_TIMEOUT);
walletArgs = await buildWalletArgs(
tc.args.chainIdFrom,
bridgeInteractionsPrivkey.privkey
);
wallet = walletArgs.wallet;
bridgeInstance = walletArgs.bridgeInstance;
})
function executeTxnFunc(
tc: TestCase,
prom: Promise<TxnResponse>,
approval: boolean=false
): (ctx: Mocha.Context) => PromiseLike<any> {
return async function (ctx: Mocha.Context): Promise<void | any> {
if (approval && tc.args.tokenFrom.isEqual(Tokens.ETH)) return
ctx.timeout(20*1000);
let execProm = executeTransaction(prom);
return (await (tc.expected.executeSuccess
? expectFulfilled(execProm)
: expectRejected(execProm)
))
}
}
function callStaticFunc(
tc: TestCase,
prom: Promise<StaticCallResult>,
approval: boolean=false
): (ctx: Mocha.Context) => PromiseLike<any> {
return async function (ctx: Mocha.Context): Promise<void | any> {
if (approval && tc.args.tokenFrom.isEqual(Tokens.ETH)) return
ctx.timeout(5*1000);
let execProm = callStatic(prom);
return (await (tc.expected.executeSuccess
? expectFulfilled(execProm)
: expectRejected(execProm)
))
}
}
let
outputEstimate: Bridge.BridgeOutputEstimate,
doBridgeArgs: Bridge.BridgeTransactionParams;
step("acquire output estimate", async function(this: Mocha.Context) {
this.timeout(DEFAULT_TEST_TIMEOUT);
let prom = getBridgeEstimate(tc, walletArgs);
await expectFulfilled(prom);
const {outputEstimate: estimate, bridgeArgs: bridgeParams} = await prom;
expectNotZero(estimate.amountToReceive);
outputEstimate = estimate;
doBridgeArgs = bridgeParams;
return
});
describe("- checkCanBridge()", function(this: Mocha.Suite) {
const canBridgeTestTitle: string = `should${tc.expected.canBridge ? "" : " not"} be able to bridge`;
it(canBridgeTestTitle, function(this: Mocha.Context, done: Mocha.Done) {
this.timeout(3.5*1000);
this.slow(2*1000);
let prom = bridgeInstance.checkCanBridge({
token: tc.args.tokenFrom,
signer: wallet,
amount: tc.args.amountFrom,
}).then(({canBridge}) => canBridge)
expect(prom).to.eventually.equal(tc.expected.canBridge).notify(done);
})
});
describe("- Transaction Builders", function(this: Mocha.Suite) {
let
approvalTxn: PopulatedTransaction,
bridgeTxn: PopulatedTransaction;
const
approveTitle: string = "approval transaction should be populated successfully",
bridgeTitle: string = "bridge transaction should be populated successfully";
step(approveTitle, async function(this: Mocha.Context) {
if (tc.args.tokenFrom.isEqual(Tokens.ETH)) return
this.timeout(DEFAULT_TEST_TIMEOUT);
return (await expectFulfilled(
bridgeInstance
.buildApproveTransaction({token: tc.args.tokenFrom})
.then((txn) => approvalTxn = txn)
))
});
step(bridgeTitle, async function(this: Mocha.Context) {
this.timeout(DEFAULT_TEST_TIMEOUT);
return (await expectFulfilled(
bridgeInstance.buildBridgeTokenTransaction(doBridgeArgs)
.then((txn) => bridgeTxn = txn)
))
});
const approval = true;
step(approvalTxnTestTitle, async function(this: Mocha.Context) {
if (tc.callStatic) {
return await callStaticFunc(
tc,
staticCallPopulatedTransaction(approvalTxn, wallet),
approval
)(this)
} else {
return await executeTxnFunc(
tc,
wallet.sendTransaction(approvalTxn),
approval
)(this)
}
});
step(bridgeTxnTestTitle, async function(this: Mocha.Context) {
if (tc.callStatic) {
return await callStaticFunc(
tc,
staticCallPopulatedTransaction(bridgeTxn, wallet)
)(this)
} else {
return await executeTxnFunc(
tc,
wallet.sendTransaction(bridgeTxn)
)(this)
}
});
});
(tc.callStatic ? describe.skip : describe)("- Magic Executors", function(this: Mocha.Suite) {
const approval = true;
step(approvalTxnTestTitle, async function(this: Mocha.Context) {
return await executeTxnFunc(
tc,
bridgeInstance.executeApproveTransaction({token: tc.args.tokenFrom}, wallet),
approval
)(this)
});
step(bridgeTxnTestTitle, async function (this: Mocha.Context) {
return await executeTxnFunc(
tc,
bridgeInstance.executeBridgeTokenTransaction(doBridgeArgs, wallet)
)(this)
});
})
})
})
})
Example #26
Source File: bridge.test.ts From optimism-dai-bridge with GNU Affero General Public License v3.0 | 4 votes |
describe('bridge', () => {
let l1Signer: Wallet
let l1Escrow: L1Escrow
let l2Signer: Wallet
let watcher: Watcher
let l1Dai: Dai
let l1DAITokenBridge: L1DAITokenBridge
let l1DAITokenBridgeV2: L1DAITokenBridge
let l1GovernanceRelay: L1GovernanceRelay
let l2Dai: Dai
let l2DAITokenBridge: L2DAITokenBridge
let l2DAITokenBridgeV2: L2DAITokenBridge
let l2GovernanceRelay: L2GovernanceRelay
let l2UpgradeSpell: TestBridgeUpgradeSpell
beforeEach(async () => {
;({ l1Signer, l2Signer, watcher } = await setupTest())
l1Dai = await deployUsingFactory(l1Signer, await l1.getContractFactory('Dai'), [ZERO_GAS_OPTS])
console.log('L1 DAI: ', l1Dai.address)
await waitForTx(l1Dai.mint(l1Signer.address, initialL1DaiNumber))
l2Dai = await deployUsingFactory(l2Signer, await l1.getContractFactory('Dai'), [ZERO_GAS_OPTS])
console.log('L2 DAI: ', l2Dai.address)
l1Escrow = await deployUsingFactory(l1Signer, await l1.getContractFactory('L1Escrow'), [ZERO_GAS_OPTS])
console.log('L1 Escrow: ', l1Escrow.address)
const futureL1DAITokenBridgeAddress = await getAddressOfNextDeployedContract(l1Signer)
l2DAITokenBridge = await deployUsingFactory(l2Signer, await l1.getContractFactory('L2DAITokenBridge'), [
optimismConfig._L2_OVM_L2CrossDomainMessenger,
l2Dai.address,
l1Dai.address,
futureL1DAITokenBridgeAddress,
ZERO_GAS_OPTS,
])
console.log('L2 DAI Token Bridge: ', l2DAITokenBridge.address)
l1DAITokenBridge = await deployUsingFactory(l1Signer, await l1.getContractFactory('L1DAITokenBridge'), [
l1Dai.address,
l2DAITokenBridge.address,
l2Dai.address,
optimismConfig.Proxy__OVM_L1CrossDomainMessenger,
l1Escrow.address,
ZERO_GAS_OPTS,
])
await waitForTx(l1Escrow.approve(l1Dai.address, l1DAITokenBridge.address, ethers.constants.MaxUint256))
expect(l1DAITokenBridge.address).to.be.eq(
futureL1DAITokenBridgeAddress,
'Predicted address of l1DAITokenBridge doesnt match actual address',
)
console.log('L1 DAI Deposit: ', l1DAITokenBridge.address)
const futureL1GovRelayAddress = await getAddressOfNextDeployedContract(l1Signer)
l2GovernanceRelay = await deployUsingFactory(l2Signer, await l1.getContractFactory('L2GovernanceRelay'), [
optimismConfig._L2_OVM_L2CrossDomainMessenger,
futureL1GovRelayAddress,
ZERO_GAS_OPTS,
])
console.log('L2 Governance Relay: ', l2DAITokenBridge.address)
l1GovernanceRelay = await deployUsingFactory(l1Signer, await l1.getContractFactory('L1GovernanceRelay'), [
l2GovernanceRelay.address,
optimismConfig.Proxy__OVM_L1CrossDomainMessenger,
ZERO_GAS_OPTS,
])
expect(l1GovernanceRelay.address).to.be.eq(
futureL1GovRelayAddress,
'Predicted address of l1GovernanceRelay doesnt match actual address',
)
console.log('L1 Governance Relay: ', l1GovernanceRelay.address)
await waitForTx(l2Dai.rely(l2DAITokenBridge.address, ZERO_GAS_OPTS))
await waitForTx(l2Dai.rely(l2GovernanceRelay.address, ZERO_GAS_OPTS))
await waitForTx(l2Dai.deny(l2Signer.address, ZERO_GAS_OPTS))
await waitForTx(l2DAITokenBridge.rely(l2GovernanceRelay.address, ZERO_GAS_OPTS))
await waitForTx(l2DAITokenBridge.deny(l2Signer.address, ZERO_GAS_OPTS))
console.log('Permission sanity checks...')
expect(await getActiveWards(l2Dai)).to.deep.eq([l2DAITokenBridge.address, l2GovernanceRelay.address])
expect(await getActiveWards(l2DAITokenBridge)).to.deep.eq([l2GovernanceRelay.address])
console.log('Permissions updated.')
})
it('moves l1 tokens to l2', async () => {
await waitForTx(l1Dai.approve(l1DAITokenBridge.address, depositAmount))
await waitToRelayTxsToL2(
l1DAITokenBridge.depositERC20(l1Dai.address, l2Dai.address, depositAmount, defaultGasLimit, '0x'),
watcher,
)
const balance = await l2Dai.balanceOf(l1Signer.address)
expect(balance.toString()).to.be.eq(depositAmount)
})
it('moves l2 tokens to l1', async () => {
await waitForTx(l1Dai.approve(l1DAITokenBridge.address, depositAmount))
await waitToRelayTxsToL2(
l1DAITokenBridge.depositERC20(l1Dai.address, l2Dai.address, depositAmount, defaultGasLimit, '0x'),
watcher,
)
const balance = await l2Dai.balanceOf(l1Signer.address)
expect(balance.toString()).to.be.eq(depositAmount)
await relayMessagesToL1(
l2DAITokenBridge.withdraw(l2Dai.address, depositAmount, defaultGasLimit, '0x', ZERO_GAS_OPTS),
watcher,
l1Signer,
)
const l2BalanceAfterWithdrawal = await l2Dai.balanceOf(l1Signer.address)
expect(l2BalanceAfterWithdrawal.toString()).to.be.eq('0')
const l1Balance = await l1Dai.balanceOf(l1Signer.address)
expect(l1Balance.toString()).to.be.eq(initialL1DaiNumber)
})
it('upgrades the bridge through governance relay', async () => {
const futureL2DAITokenBridgeV2Address = await getAddressOfNextDeployedContract(l1Signer)
l2DAITokenBridgeV2 = await deployUsingFactory(l2Signer, await l1.getContractFactory('L2DAITokenBridge'), [
optimismConfig._L2_OVM_L2CrossDomainMessenger,
l2Dai.address,
l1Dai.address,
futureL2DAITokenBridgeV2Address,
ZERO_GAS_OPTS,
])
console.log('L2 DAI Token Bridge V2: ', l2DAITokenBridgeV2.address)
l1DAITokenBridgeV2 = await deployUsingFactory(l1Signer, await l1.getContractFactory('L1DAITokenBridge'), [
l1Dai.address,
l2DAITokenBridgeV2.address,
l2Dai.address,
optimismConfig.Proxy__OVM_L1CrossDomainMessenger,
l1Escrow.address,
ZERO_GAS_OPTS,
])
expect(l1DAITokenBridgeV2.address).to.be.eq(
futureL2DAITokenBridgeV2Address,
'Predicted address of l1DAITokenBridgeV2 doesnt match actual address',
)
await waitForTx(
l1Escrow.approve(l1Dai.address, l1DAITokenBridgeV2.address, ethers.constants.MaxUint256, ZERO_GAS_OPTS),
)
console.log('L1 DAI Deposit V2: ', l1DAITokenBridgeV2.address)
l2UpgradeSpell = await deployUsingFactory(l2Signer, await l1.getContractFactory('TestBridgeUpgradeSpell'), [
ZERO_GAS_OPTS,
])
console.log('L2 Bridge Upgrade Spell: ', l2UpgradeSpell.address)
// Close L1 bridge V1
await l1DAITokenBridge.connect(l1Signer).close(ZERO_GAS_OPTS)
console.log('L1 Bridge Closed')
// Close L2 bridge V1
console.log('Executing spell to close L2 Bridge v1 and grant minting permissions to L2 Bridge v2')
await waitToRelayTxsToL2(
l1GovernanceRelay
.connect(l1Signer)
.relay(
l2UpgradeSpell.address,
l2UpgradeSpell.interface.encodeFunctionData('upgradeBridge', [
l2DAITokenBridge.address,
l2DAITokenBridgeV2.address,
]),
spellGasLimit,
ZERO_GAS_OPTS,
),
watcher,
)
console.log('L2 Bridge Closed')
console.log('Testing V2 bridge deposit/withdrawal...')
await waitForTx(l1Dai.approve(l1DAITokenBridgeV2.address, depositAmount, ZERO_GAS_OPTS))
await waitToRelayTxsToL2(
l1DAITokenBridgeV2.depositERC20(
l1Dai.address,
l2Dai.address,
depositAmount,
defaultGasLimit,
'0x',
ZERO_GAS_OPTS,
),
watcher,
)
const balance = await l2Dai.balanceOf(l1Signer.address)
expect(balance.toString()).to.be.eq(depositAmount)
await relayMessagesToL1(
l2DAITokenBridgeV2.withdraw(l2Dai.address, depositAmount, defaultGasLimit, '0x', ZERO_GAS_OPTS),
watcher,
l1Signer,
)
const l2BalanceAfterWithdrawal = await l2Dai.balanceOf(l1Signer.address)
expect(l2BalanceAfterWithdrawal.toString()).to.be.eq('0')
const l1Balance = await l1Dai.balanceOf(l1Signer.address)
expect(l1Balance.toString()).to.be.eq(initialL1DaiNumber)
})
})
Example #27
Source File: endpoint.test.ts From bodhi.js with Apache License 2.0 | 4 votes |
describe('eth_sendRawTransaction', () => {
const eth_sendRawTransaction = rpcGet('eth_sendRawTransaction');
const eth_getTransactionCount = rpcGet('eth_getTransactionCount');
const eth_getBalance = rpcGet('eth_getBalance');
const eth_chainId = rpcGet('eth_chainId');
const eth_gasPrice = rpcGet('eth_gasPrice');
const eth_estimateGas = rpcGet('eth_estimateGas');
const account1 = evmAccounts[0];
const account2 = evmAccounts[1];
const wallet1 = new Wallet(account1.privateKey);
let chainId: number;
let txGasLimit: BigNumber;
let txGasPrice: BigNumber;
let genesisHash: string;
let api: ApiPromise;
before('prepare common variables', async () => {
chainId = BigNumber.from((await eth_chainId()).data.result).toNumber();
txGasLimit = BigNumber.from(34132001);
txGasPrice = BigNumber.from(200786445289);
const endpoint = process.env.ENDPOINT_URL || 'ws://127.0.0.1:9944';
const wsProvider = new WsProvider(endpoint);
api = await ApiPromise.create({ provider: wsProvider });
genesisHash = api.genesisHash.toHex(); // TODO: why EIP-712 salt has to be genesis hash?
});
after(async () => {
await api.disconnect();
});
describe('deploy contract (hello world)', () => {
const deployHelloWorldData =
'0x60806040526040518060400160405280600c81526020017f48656c6c6f20576f726c642100000000000000000000000000000000000000008152506000908051906020019061004f929190610062565b5034801561005c57600080fd5b50610166565b82805461006e90610134565b90600052602060002090601f01602090048101928261009057600085556100d7565b82601f106100a957805160ff19168380011785556100d7565b828001600101855582156100d7579182015b828111156100d65782518255916020019190600101906100bb565b5b5090506100e491906100e8565b5090565b5b808211156101015760008160009055506001016100e9565b5090565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061014c57607f821691505b602082108114156101605761015f610105565b5b50919050565b61022e806101756000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c605f76c14610030575b600080fd5b61003861004e565b6040516100459190610175565b60405180910390f35b6000805461005b906101c6565b80601f0160208091040260200160405190810160405280929190818152602001828054610087906101c6565b80156100d45780601f106100a9576101008083540402835291602001916100d4565b820191906000526020600020905b8154815290600101906020018083116100b757829003601f168201915b505050505081565b600081519050919050565b600082825260208201905092915050565b60005b838110156101165780820151818401526020810190506100fb565b83811115610125576000848401525b50505050565b6000601f19601f8301169050919050565b6000610147826100dc565b61015181856100e7565b93506101618185602086016100f8565b61016a8161012b565b840191505092915050565b6000602082019050818103600083015261018f818461013c565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806101de57607f821691505b602082108114156101f2576101f1610197565b5b5091905056fea26469706673582212204d363ed34111d1be492d4fd086e9f2df62b3c625e89ade31f30e63201ed1e24f64736f6c63430008090033';
let partialDeployTx;
before(() => {
partialDeployTx = {
chainId,
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: deployHelloWorldData,
value: BigNumber.from(0)
};
});
describe('with legacy EIP-155 signature', () => {
it('serialize, parse, and send tx correctly', async () => {
const unsignedTx: AcalaEvmTX = {
...partialDeployTx,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result
};
const rawTx = await wallet1.signTransaction(unsignedTx);
const parsedTx = parseTransaction(rawTx);
expect(parsedTx.gasPrice.eq(txGasPrice)).equal(true);
expect(parsedTx.gasLimit.eq(txGasLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(null);
expect(parsedTx.maxPriorityFeePerGas).equal(undefined);
expect(parsedTx.maxFeePerGas).equal(undefined);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
});
});
describe('with EIP-1559 signature', () => {
it('serialize, parse, and send tx correctly', async () => {
const priorityFee = BigNumber.from(2);
const unsignedTx: AcalaEvmTX = {
...partialDeployTx,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
gasPrice: undefined,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: txGasPrice,
type: 2
};
const rawTx = await wallet1.signTransaction(unsignedTx);
const parsedTx = parseTransaction(rawTx);
expect(parsedTx.maxFeePerGas.eq(txGasPrice)).equal(true);
expect(parsedTx.maxPriorityFeePerGas.eq(priorityFee)).equal(true);
expect(parsedTx.gasLimit.eq(txGasLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(2);
expect(parsedTx.gasPrice).equal(null);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
});
});
describe('with EIP-712 signature', () => {
it('serialize, parse, and send tx correctly', async () => {
const gasLimit = BigNumber.from('210000');
const validUntil = 10000;
const storageLimit = 100000;
const unsignEip712Tx: AcalaEvmTX = {
...partialDeployTx,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
salt: genesisHash,
gasLimit,
validUntil,
storageLimit,
type: 0x60
};
const sig = signTransaction(account1.privateKey, unsignEip712Tx);
const rawTx = serializeTransaction(unsignEip712Tx, sig);
const parsedTx = parseTransaction(rawTx);
expect(parsedTx.gasLimit.eq(gasLimit)).equal(true);
expect(parsedTx.validUntil.eq(validUntil)).equal(true);
expect(parsedTx.storageLimit.eq(storageLimit)).equal(true);
expect(parsedTx.from).equal(wallet1.address);
expect(parsedTx.data).equal(deployHelloWorldData);
expect(parsedTx.type).equal(96);
expect(parsedTx.maxPriorityFeePerGas).equal(undefined);
expect(parsedTx.maxFeePerGas).equal(undefined);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
});
});
});
describe('call contract (transfer ACA)', () => {
const ETHDigits = 18;
const ACADigits = 12;
const acaContract = new Contract(ADDRESS.ACA, TokenABI.abi, wallet1);
const iface = new Interface(TokenABI.abi);
const queryBalance = async (addr) =>
BigNumber.from((await eth_getBalance([addr, 'latest'])).data.result).div(10 ** (ETHDigits - ACADigits));
const transferAmount = parseUnits('100', ACADigits);
let partialTransferTX: Partial<AcalaEvmTX>;
before(() => {
partialTransferTX = {
chainId,
to: ADDRESS.ACA,
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: iface.encodeFunctionData('transfer', [account2.evmAddress, transferAmount]),
value: BigNumber.from(0)
};
});
describe('with legacy EIP-155 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result
};
const rawTx = await wallet1.signTransaction(transferTX);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
describe('with EIP-1559 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const priorityFee = BigNumber.from(2);
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
gasPrice: undefined,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: txGasPrice,
type: 2
};
const rawTx = await wallet1.signTransaction(transferTX);
const parsedTx = parseTransaction(rawTx);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
describe('with EIP-712 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const gasLimit = BigNumber.from('210000');
const validUntil = 10000;
const storageLimit = 100000;
const transferTX: AcalaEvmTX = {
...partialTransferTX,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
salt: genesisHash,
gasLimit,
validUntil,
storageLimit,
type: 0x60
};
const sig = signTransaction(account1.privateKey, transferTX);
const rawTx = serializeTransaction(transferTX, sig);
const parsedTx = parseTransaction(rawTx);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
});
describe('MetaMask send native ACA token', () => {
const ETHDigits = 18;
const ACADigits = 12;
const queryBalance = async (addr) => BigNumber.from((await eth_getBalance([addr, 'latest'])).data.result);
const transferAmount = parseUnits('16.8668', ETHDigits);
let partialNativeTransferTX: Partial<AcalaEvmTX>;
const estimateGas = async (): Promise<{
gasPrice: string;
gasLimit: string;
}> => {
const gasPrice = (await eth_gasPrice([])).data.result;
const gasLimit = (
await eth_estimateGas([
{
from: account1.evmAddress,
to: account2.evmAddress,
value: transferAmount,
data: null,
gasPrice
}
])
).data.result;
return {
gasPrice,
gasLimit
};
};
before(() => {
partialNativeTransferTX = {
chainId,
to: account2.evmAddress,
data: '0x',
value: transferAmount
};
});
describe('with legacy EIP-155 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const transferTX: AcalaEvmTX = {
...partialNativeTransferTX,
...(await estimateGas()),
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result
};
const rawTx = await wallet1.signTransaction(transferTX);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
describe('with EIP-1559 signature', () => {
it('has correct balance after transfer', async () => {
const balance1 = await queryBalance(account1.evmAddress);
const balance2 = await queryBalance(account2.evmAddress);
const priorityFee = BigNumber.from(2);
const { gasPrice, gasLimit } = await estimateGas();
const transferTX: AcalaEvmTX = {
...partialNativeTransferTX,
gasLimit,
nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
gasPrice: undefined,
maxPriorityFeePerGas: priorityFee,
maxFeePerGas: gasPrice,
type: 2
};
const rawTx = await wallet1.signTransaction(transferTX);
const parsedTx = parseTransaction(rawTx);
const res = await eth_sendRawTransaction([rawTx]);
expect(res.status).to.equal(200);
expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
const _balance1 = await queryBalance(account1.evmAddress);
const _balance2 = await queryBalance(account2.evmAddress);
// TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
describe('with EIP-712 signature', () => {
// TODO: EIP-712 doesn't use ETH gasLimit and gasPrice, do we need to support it?
it.skip('has correct balance after transfer', async () => {
// const balance1 = await queryBalance(account1.evmAddress);
// const balance2 = await queryBalance(account2.evmAddress);
// const gasLimit = BigNumber.from('210000');
// const validUntil = 10000;
// const storageLimit = 100000;
// const transferTX: AcalaEvmTX = {
// ...partialNativeTransferTX,
// ...(await estimateGas()),
// nonce: (await eth_getTransactionCount([wallet1.address, 'pending'])).data.result,
// salt: genesisHash,
// gasLimit,
// validUntil,
// storageLimit,
// type: 0x60
// };
// const sig = signTransaction(account1.privateKey, transferTX);
// const rawTx = serializeTransaction(transferTX, sig);
// const parsedTx = parseTransaction(rawTx);
// const res = await eth_sendRawTransaction([rawTx]);
// expect(res.status).to.equal(200);
// expect(res.data.error?.message).to.equal(undefined); // for TX error RPC will still return 200
// const _balance1 = await queryBalance(account1.evmAddress);
// const _balance2 = await queryBalance(account2.evmAddress);
// // TODO: check gasUsed is correct
// const gasUsed = balance1.sub(_balance1).sub(transferAmount).toBigInt();
// expect(_balance2.sub(balance2).toBigInt()).equal(transferAmount.toBigInt());
});
});
});
});
Example #28
Source File: batch-append.spec.ts From integration-tests with MIT License | 4 votes |
describe('Transaction Ingestion', () => {
let l1Provider: JsonRpcProvider
let l1Signer: Wallet
let l2Signer
let l2Provider: JsonRpcProvider
let addressResolver: Contract
let canonicalTransactionChain: Contract
let ctcAddress: string
const mnemonic = Config.Mnemonic()
let pre
before(async () => {
l1Provider = new JsonRpcProvider(Config.L1NodeUrlWithPort())
l1Signer = new Wallet(Config.DeployerPrivateKey()).connect(l1Provider)
const web3 = new Web3Provider(
ganache.provider({
mnemonic,
})
)
l2Provider = new OptimismProvider(Config.L2NodeUrlWithPort(), web3)
l2Signer = await l2Provider.getSigner()
const addressResolverAddress = add0x(Config.AddressResolverAddress())
const AddressResolverFactory = getContractFactory('Lib_AddressManager')
addressResolver = AddressResolverFactory.connect(l1Signer).attach(
addressResolverAddress
)
ctcAddress = await addressResolver.getAddress(
'OVM_CanonicalTransactionChain'
)
const CanonicalTransactionChainFactory = getContractFactory(
'OVM_CanonicalTransactionChain'
)
canonicalTransactionChain = CanonicalTransactionChainFactory.connect(
l1Signer
).attach(ctcAddress)
})
// The transactions are enqueue'd with a `to` address of i.repeat(40)
// meaning that the `to` value is different each iteration in a deterministic
// way. They need to be inserted into the L2 chain in an ascending order.
// Keep track of the receipts so that the blockNumber can be compared
// against the `L1BlockNumber` on the tx objects.
const receipts = []
it('should enqueue some transactions', async () => {
// Keep track of the L2 tip before submitting any transactions so that
// the subsequent transactions can be queried for in the next test
pre = await l2Provider.getBlock('latest')
// Enqueue some transactions by building the calldata and then sending
// the transaction to Layer 1
for (let i = 0; i < 5; i++) {
const input = ['0x' + `${i + 1}`.repeat(40), 500_000, `0x0${i}`]
const calldata = await canonicalTransactionChain.interface.encodeFunctionData(
'enqueue',
input
)
const txResponse = await l1Signer.sendTransaction({
data: calldata,
to: ctcAddress,
})
const receipt = await txResponse.wait()
receipts.push(receipt)
}
for (const receipt of receipts) {
receipt.should.be.a('object')
}
})
// The batch submitter will notice that there are transactions
// that are in the queue and submit them. L2 will pick up the
// sequencer batch appended event and play the transactions.
it('should order transactions correctly', async () => {
// Wait until each tx from the previous test has
// been executed
let tip
do {
tip = await l2Provider.getBlock('latest')
await sleep(5000)
} while (tip.number !== pre.number + 5)
const from = await l1Signer.getAddress()
// Keep track of an index into the receipts list and
// increment it for each block fetched.
let receiptIndex = 0
// Fetch blocks
for (let i = pre.number + 1; i < pre.number + 5; i++) {
const block = await l2Provider.getBlock(i)
const hash = block.transactions[0]
assert(typeof hash === 'string')
// Use as any hack because additional properties are
// added to the transaction response
const tx = (await l2Provider.getTransaction(hash)) as any
// The `to` addresses are defined in the previous test and
// increment sequentially.
assert.equal(tx.to, '0x' + `${i}`.repeat(40))
// The transaction type is EIP155
assert.equal(tx.txType, 'EIP155')
// The queue origin is Layer 1
assert.equal(tx.queueOrigin, 'l1')
// the L1TxOrigin is equal to the Layer one from
assert.equal(tx.l1TxOrigin, from.toLowerCase())
assert.equal(typeof tx.l1BlockNumber, 'number')
// Get the receipt and increment the recept index
const receipt = receipts[receiptIndex++]
assert.equal(tx.l1BlockNumber, receipt.blockNumber)
}
}).timeout(100000)
})