testContractHelper.ts•13.3 kB
import { ethers } from 'ethers';
import fs from 'fs';
import path from 'path';
// Define the interface for our token contract
export interface TestTokenInterface {
name(): Promise<string>;
symbol(): Promise<string>;
decimals(): Promise<number>;
totalSupply(): Promise<bigint>;
balanceOf(account: string): Promise<bigint>;
transfer(to: string, value: bigint): Promise<ethers.ContractTransactionResponse>;
approve(spender: string, value: bigint): Promise<ethers.ContractTransactionResponse>;
transferFrom(from: string, to: string, value: bigint): Promise<ethers.ContractTransactionResponse>;
allowance(owner: string, spender: string): Promise<bigint>;
connect(signer: ethers.Signer): TestToken;
getAddress(): Promise<string>;
}
export type TestToken = ethers.Contract & TestTokenInterface;
// ERC20 Test Token with basic functionality
const TOKEN_ABI = [
"function name() view returns (string)",
"function symbol() view returns (string)",
"function decimals() view returns (uint8)",
"function totalSupply() view returns (uint256)",
"function balanceOf(address) view returns (uint256)",
"function transfer(address, uint256) returns (bool)",
"function approve(address, uint256) returns (bool)",
"function transferFrom(address, address, uint256) returns (bool)",
"function allowance(address, address) view returns (uint256)"
];
// Use existing contract on hardhat node
// Rather than deploying a new one, let's try to use a known address
// This is a common pattern for testing and will avoid bytecode issues
// The Hardhat default first account deploys contracts at predictable addresses
export async function deployTestToken(
provider: ethers.Provider,
signer: ethers.Signer
): Promise<TestToken> {
try {
// Use a predetermined address for a hardhat node's first deployment
// Hardhat node is expected to be running on localhost:8545
// This is a predictable address for the first deployment from first account
const tokenAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
// Try to reuse the contract if it exists
try {
const contractCode = await provider.getCode(tokenAddress);
if (contractCode !== '0x' && contractCode.length > 2) {
console.log("Found existing contract, reusing at: " + tokenAddress);
const contract = new ethers.Contract(tokenAddress, TOKEN_ABI, signer);
return contract as unknown as TestToken;
}
} catch (error) {
// If there was an error getting the code, the node might not be running
console.log("Could not connect to existing contract, trying to deploy...");
}
// If no contract exists, deploy a minimal ERC20 contract
// Use simpler bytecode for testing purposes
const minimalTokenBytecode = "0x60806040526012600560006101000a81548160ff021916908360ff16021790555034801561002c57600080fd5b50600560009054906101000a900460ff1660ff16600a6100579190610224565b620f4240610065919061026f565b600481905550600454600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506103df565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008160ff168360ff1610156101d3576000828660ff16866101318d0119183a0af16f01f1600114935050505b61013d90506101b2565b506000199392505050565b60006101ea60ff841683610103565b9050919050565b600081115481116101815750610224610224565b600090565b6000610231826101dd565b9150610224565b6000819050919050565b600061024c8261023c565b91506102578261023c565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561029057610a2561023c565b505050565b60008135168060011a1a600080616c8e868c5161023c565b9150816102bb8761023c565b9250828202905080831117158015610212565b9a5050501061023c565b60008254600a16816102e8600182016101a5565b9050600060b99390955091505061023c565b610300828261023c565b505050565b6129b8806103ee6000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c806370a082311161005b57806370a082311461015b578063a9059cbb1461018b578063dd62ed3e146101bb578063313ce5671461010b57610088565b806306fdde031461008d57806318160ddd146100ab57806323b872dd146100c9578063095ea7b3146100f9575b600080fd5b610095610207565b6040516100a29190610d3f565b60405180910390f35b6100b361023a565b6040516100c09190610d73565b60405180910390f35b6100e360048036038101906100de9190610dbe565b610240565b6040516100f09190610e1d565b60405180910390f35b610113600480360381019061010e9190610e69565b610428565b6040516101209190610e1d565b60405180910390f35b61011361051a565b6040516101509190610e45565b60405180910390f35b61017560048036038101906101709190610ea9565b61052d565b6040516101829190610d73565b60405180910390f35b6101a560048036038101906101a09190610e69565b610576565b6040516101b29190610e1d565b60405180910390f35b6101d560048036038101906101d09190610ed6565b610694565b6040516101e29190610d73565b60405180910390f35b61020761071b565b604051610214919061093f565b60405180910390f35b60606000601290508585836003f35b60045481565b60008061024b61071b565b9050600061025b6002896106ba565b90506000610269888461071b565b141561027f5761027e82898b8a6107a7565b5b8773ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258460405161069990610efb565b60405180910390a48091505095945050505050565b6000610418600360008681526020019081526020016000205484111561047c5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161033d565b6000610418600360008681526020019081526020016000205484111561047c5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161033d565b670de0b6b3a764000081565b60008060008173ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080610581610723565b9050600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561061d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161061490610f70565b60405180910390fd5b600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115610691576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161068890610fdc565b60405180910390fd5b60008061069c610723565b9050600061069c33876106ba565b90506000610699876106ba565b815181529150506000908152602001604005b60008383602087013352336000527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602052604051610699916020820180602001909291908260006107d4565b600560009054906101000a900460ff1681565b604080516024808252818301909252606091829190602082018180368337505081519050915050919050565b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461083290610ffc565b92505081905550828473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161094c9190610d73565b60405180910390a4505050565b600090565b610963816110de565b82525050565b600060208201905081810360008301526109838184610950565b905092915050565b600081519050919050565b600082825260208201905092915050565b60005b838110156109c55780820151818401526020810190506109aa565b838111156109d4576000848401525b50505050565b6000601f19601f8301169050919050565b60006109f68261098b565b610a008185610996565b9350610a108185602086016109a7565b610a19816109da565b840191505092915050565b60006020820190508181036000830152610a3e81846109eb565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610a7682610a4b565b9050919050565b610a8681610a6b565b8114610a9157600080fd5b50565b600081359050610aa381610a7d565b92915050565b6000819050919050565b610abc81610aa9565b8114610ac757600080fd5b50565b600081359050610ad981610ab3565b92915050565b600080fd5b600067ffffffffffffffff821115610b0457610b03610ae1565b5b610b0d826109da565b9050602081019050919050565b82818337600083830152505050565b6000610b3c610b3784610ae9565b610ac8565b905082815260208101848484011115610b5857610b57610adc565b5b610b63848285610b1a565b509392505050565b600082601f830112610b8057610b7f610ad7565b5b8135610b90848260208601610b29565b91505092915050565b60008060408385031215610bb057610baf610a46565b5b6000610bbe85828601610a94565b925050602085013567ffffffffffffffff811115610bdf57610bde610a42565b5b610beb85828601610b6b565b9150509250929050565b6000819050919050565b610c0881610bf5565b8114610c1357600080fd5b50565b600081359050610c2581610bff565b92915050565b60006020820190508181036000830152610c418184610aba565b905092915050565b6000602082019050610c6d6000830184610aba565b92915050565b600081519050919050565b600082825260208201905092915050565b6000610c9a82610c73565b610ca48185610c7e565b9350610cb48185602086016109a7565b610cbd816109da565b840191505092915050565b60006020820190508181036000830152610ce18184610c8f565b905092915050565b6000607884610adc565b610cfa83610ad756b9050610d0482610ae956b838387610b1a56b826109da56b6000610d1f610d1a84610ae956b905082815260208101848484011115610d3b57610d3a610adc56b5b610d46848285610b1a56b50939250505056b1610d5581610bf556b8252505056b60006080820190508181036000830152610d748161095a56b9050610d836020830184610d4c56b9291505056b600080600060608486031215610df257610df1610a4656b5b6000610e0086828701610a9456b9350506020610e1186828701610a9456b9250506040610e2286828701610aca56b915050925092509256b6000811515905091905056b610e4181610e2c56b8252505056b6000602082019050610e5c6000830184610e3856b9291505056b60008060408385031215610e8057610e7f610a4656b5b6000610e8e85828601610a9456b9250506020610e9f85828601610aca56b915050925092905056b600060208284031215610ebf57610ebe610a4656b5b6000610ecd84828501610a9456b9150509291505056b60008060408385031215610eed57610eec610a4656b5b6000610efb85828601610a9456b9250506020610f0c85828601610a9456b915050925092905056b60008282526020820190509291505056b7f45524332303a207472616e7366657220746f20746865207a65726f206164647260008201527f657373000000000000000000000000000000000000000000000000000000000060208201525056b6000610f5a602483610f1356b9150610f6582610f2456b0408201905091905056b60006020820190508181036000830152610f8981610fb956b905091905056b7f45524332303a207472616e7366657220616d6f756e742065786365656473206260008201527f616c616e6365000000000000000000000000000000000000000000000000000060208201525056b6000610fc6602683610f1356b9150610fd182610f9056b0408201905091905056b60006020820190508181036000830152610ff581610fb956b905091905056b600082821c90509291505056b600061101c60001984600802610ffe56b198083169150509291505056b6000611035838361100b56b915082600202821790509291505056b600081156110555761105756b9291505056b6110588161103c56b8252505056b600060408201905061107360008301856110c956b818103602083015261108581846110cd56b9050939250505056b60008282526020820190509291505056b600081905060208201905091905056b6110b881610e2c56b8252505056b6110c781610a6b56b8252505056b60006110d582846110af56b6020820191508190509291505056b6110eb81610bf556b8252505056b6000610cfa6000830184610ca956b91905056b6000610d4c6000830184610ca956b91905056b6000610c0282610c0a56b90509291505056b6000610c0a82610c0256b90509291505056b60008154610c1356b90505b600a6000190481161580156112b0578267ffffffffffffffff16610c4057610c40610c0a56b8152602001906001019061129e56b8460409050519081116129b857600080fdfea2646970667358221220c70bceba00be357d55a3afa0cadf3f5fb9c95bc84be3bdde3a35ddbad7687e1264736f6c634300081100330000000000000000000000000000000000000000000000000000000000";
console.log("Deploying new contract...");
// For Bun tests, use a direct JsonRpcProvider with our local node
const hardhatProvider = new ethers.JsonRpcProvider("http://localhost:8545");
const hardhatSigner = await hardhatProvider.getSigner(0); // Use the first account
// Create contract factory with minimal bytecode
const factory = new ethers.ContractFactory(
TOKEN_ABI,
minimalTokenBytecode,
hardhatSigner
);
// Deploy with explicit gas
const contract = await factory.deploy({
gasLimit: 6000000
});
await contract.waitForDeployment();
const deployedAddress = await contract.getAddress();
console.log(`Deployed new test token at: ${deployedAddress}`);
return contract.connect(signer) as unknown as TestToken;
} catch (error) {
console.error('Failed to get/deploy token contract:', error);
throw error;
}
}
/**
* Get a token contract at an existing address
*
* @param address - Address of the token contract
* @param provider - Ethereum provider
* @param signer - Optional signer to use for the contract
* @returns The token contract
*/
export async function getTestTokenAt(
address: string,
provider: ethers.Provider,
signer?: ethers.Signer
): Promise<TestToken> {
try {
const contract = new ethers.Contract(
address,
TOKEN_ABI,
signer || provider
);
// Verify the contract exists
const code = await provider.getCode(address);
if (code === '0x') {
throw new Error('No contract found at the specified address');
}
return contract as unknown as TestToken;
} catch (error) {
console.error('Failed to get token at address:', address, error);
throw error;
}
}