diff --git a/config.test.json b/config.test.json index 4c9c36f..a7bcc78 100644 --- a/config.test.json +++ b/config.test.json @@ -1 +1 @@ -{"appName":"RosettaNet","port":3000,"host":"localhost","rpcUrls":["http://127.0.0.1:6050"],"chainId":"0x52535453","accountClass":"0x56ab4cd1d769d746256546b81f34f5b4f416da9e3d5696d2f362ab1a86fae9","ethAddress":"0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","strkAddress":"0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d","rosettanet":"0x2005d48f7bbdff70f7102eab69d67909800ebc562044469e89dcf4544c2c48e","featureTarget":"0x0000000000000000000000004645415455524553","logging":{"active":true,"sniffer":true,"output":"file","minSeverity":"0","fileName":"./e2e/logs.log","format":"text"}} \ No newline at end of file +{"appName":"RosettaNet","port":3000,"host":"localhost","rpcUrls":["http://127.0.0.1:6050"],"chainId":"0x52535453","accountClass":"0x70af38bca727839a6f1501f883f0dcc3e3a73033fd48b852e25da2e0163d92","ethAddress":"0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","strkAddress":"0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d","rosettanet":"0x4cad109dfee10dfe764a439956c64bf219085915550ca79a5f7f91ca0f7e080","validateFeeEstimator":"0x4c28482306cd18d2af6c0df29a32a92944f2251de3e3a83e913eee2efa68be8","featureTarget":"0x0000000000000000000000004645415455524553","logging":{"active":true,"sniffer":true,"output":"file","minSeverity":"0","fileName":"./e2e/logs.log","format":"text"}} \ No newline at end of file diff --git a/e2e/jest.globalSetup.ts b/e2e/jest.globalSetup.ts index 1432b80..3a185ef 100644 --- a/e2e/jest.globalSetup.ts +++ b/e2e/jest.globalSetup.ts @@ -11,15 +11,19 @@ export default async function globalSetup() { const rosettanetClass = await declareContract(account, 'Rosettanet') const accountClass = await declareContract(account, 'RosettaAccount') + const validateFeeEstimator = await declareContract(account, 'ValidateFeeEstimator') const rosettanetAddress = await deployContract(account, rosettanetClass, [ accountClass, account.address, STRK_ADDRESS, ]) + const validateFeeEstimatorAddress = await deployContract(account, validateFeeEstimator, []) + const nodeConfig = testConfig nodeConfig.accountClass = accountClass nodeConfig.rosettanet = rosettanetAddress + nodeConfig.validateFeeEstimator = validateFeeEstimatorAddress await updateNodeConfig(JSON.stringify(nodeConfig)) await fundAccountsForBalanceTests(); diff --git a/e2e/libraries/ethers.test.ts b/e2e/libraries/ethers.test.ts index 758d811..01859af 100644 --- a/e2e/libraries/ethers.test.ts +++ b/e2e/libraries/ethers.test.ts @@ -5,293 +5,295 @@ import { ETH_ADDRESS, SN_ADDRESS_TEST_1, STRK_ADDRESS } from '../constants'; import { getEthAddress } from '../registers'; describe('Using ethers.js with Rosettanet RPC', () => { - test.only('Retrive balance of the account', async () => { - const TestAccount1 = await getEthAddress(SN_ADDRESS_TEST_1); - const provider = new ethers.JsonRpcProvider(SERVER); - const balanceWei = await provider.getBalance(TestAccount1.ethereum); - - // Convert balance to Ether string - const balanceEther = ethers.formatEther(balanceWei); - expect(balanceEther).toBe("1250.0") - }, 30000) - - test.only('Retrive eth balance using erc20 contract', async () => { - const TestAccount1 = await getEthAddress(SN_ADDRESS_TEST_1); - const EthToken = await getEthAddress(ETH_ADDRESS) - const provider = new ethers.JsonRpcProvider(SERVER); - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)' - ]; - const tokenContract = new ethers.Contract(EthToken.ethereum, ERC20_ABI, provider); - - // Get balance - const balance = await tokenContract.balanceOf(TestAccount1.ethereum); - - // Get token decimals - const decimals = await tokenContract.decimals(); - expect(balance).toBe(BigInt("1000001461819925596660")) - expect(decimals).toBe(BigInt(18)) - }, 30000) - - test.only('Sends simple STRK transfer transaction. This may deploy account contract initially.', async () => { - const provider = new ethers.JsonRpcProvider(SERVER); - - // Fund initial address first - const devAcc = getDevAccount(); - const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D - const wallet = new ethers.Wallet(privateKey, provider); - - const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); - await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') // sends 100 strk - - const toAddress = '0x8b4ee3F7a16ed6b793BD7907f87778AC11624c27'; - - // We cant directly send transaction with wallet.sendTransaction. Because it expects precalculated tx hash from rpc. - // And it reverts if hash is different. - // TODO: In future we may return directly ethereum type eth hash and scanners matches them with actual starknet tx hashes? - const txRequest = await wallet.populateTransaction({ - to: toAddress, - value: ethers.parseEther('1.0') // 1 STRK - }); - - const signedTx = await wallet.signTransaction(txRequest); - - await provider.send('eth_sendRawTransaction', [signedTx]) - - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)' - ]; - const strkTokenAddress = await getEthAddress(STRK_ADDRESS); - - const strkContract = new ethers.Contract(strkTokenAddress.ethereum, ERC20_ABI, provider); - - const balance = await strkContract.balanceOf(toAddress); - - expect(balance).toBe(ethers.parseEther('1.0')) - - }) - - test.only('ERC20 transfer transaction. This may deploy account contract initially.', async () => { - const provider = new ethers.JsonRpcProvider(SERVER); - - const devAcc = getDevAccount(); - const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D - const wallet = new ethers.Wallet(privateKey, provider); - - const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); - await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 strk - const tokenAddress = await getEthAddress(ETH_ADDRESS); - - const toAddress = '0x8b4ee3F7a16ed6b793BD7907f87778AC11624c27'; - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)', - 'function transfer(address to, uint256 amount) public returns (bool)' - ]; - const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); - - const iface = new ethers.Interface(ERC20_ABI); - - const data = iface.encodeFunctionData('transfer', [ - toAddress, - ethers.parseUnits('1', 18) - ]); - - const txRequest = { - to: tokenAddress.ethereum, // Token kontrat adresi - data: data, - }; - - await erc20Contract.balanceOf(wallet.address); - - const tx = await wallet.populateTransaction(txRequest); - - const signedTx = await wallet.signTransaction(tx); - const sentTx = await provider.send('eth_sendRawTransaction', [signedTx]); - - - await provider.waitForTransaction(sentTx, 0); // 0 confirmations needed since its devnet - - const balance = await erc20Contract.balanceOf(toAddress); - - expect(balance).toBe(ethers.parseEther('1.0')) - }) - - test.only('ERC20 transfer transaction. From already deployed account contract.', async () => { - const provider = new ethers.JsonRpcProvider(SERVER); - - const devAcc = getDevAccount(); - const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D - const wallet = new ethers.Wallet(privateKey, provider); - - const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); - await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 eth - const tokenAddress = await getEthAddress(ETH_ADDRESS); - - const toAddress = '0x8B4ee3F7a16eD6B793bD7907F87778AC11624C28'; - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)', - 'function transfer(address to, uint256 amount) public returns (bool)' - ]; - const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); - - const iface = new ethers.Interface(ERC20_ABI); - - const data = iface.encodeFunctionData('transfer', [ - toAddress, - ethers.parseUnits('1', 18) - ]); - - const txRequest = { - to: tokenAddress.ethereum, // Token kontrat adresi - data: data, - }; - - await erc20Contract.balanceOf(wallet.address); - - const tx = await wallet.populateTransaction(txRequest); - - const signedTx = await wallet.signTransaction(tx); - const sentTx = await provider.send('eth_sendRawTransaction', [signedTx]); - - - await provider.waitForTransaction(sentTx, 0); // 0 confirmations needed since its devnet - - // Now its deployed. Lets send again with legacy tx - - const txRequestLegacy = { - to: tokenAddress.ethereum, // Token kontrat adresi - data: data, - type: 0 - }; - - const legacyTx = await wallet.populateTransaction(txRequestLegacy); - const signedLegacyTx = await wallet.signTransaction(legacyTx); - const sentLegacyTx = await provider.send('eth_sendRawTransaction', [signedLegacyTx]); - await provider.waitForTransaction(sentLegacyTx, 0); - - const balance = await erc20Contract.balanceOf(toAddress); - - expect(balance).toBe(ethers.parseEther('2.0')) - }) - - test.only('Multicall transaction that transfers erc20 to two different accounts', async () => { - const provider = new ethers.JsonRpcProvider(SERVER); - - const devAcc = getDevAccount(); - const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D - const wallet = new ethers.Wallet(privateKey, provider); - - const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); - await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 strk - - const MULTICALL_ABI = [ - 'function multicall((uint256,uint256,uint256[])[])' - ]; - - const iface = new ethers.Interface(MULTICALL_ABI); - - const receiver1SnAddress = await precalculateStarknetAddress('0x00012'); - const receiver2SnAddress = await precalculateStarknetAddress('0x00013'); - - const data = iface.encodeFunctionData('multicall', [[ - [ - ETH_ADDRESS, - '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', - [receiver1SnAddress, '1000', '0'] - ], - [ - ETH_ADDRESS, - '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', - [receiver2SnAddress, '2000', '0'] - ] - ]]); - - const txRequest = { - to: '0x0000000000000000000000004645415455524553', // Token kontrat adresi - data: data, - }; - - //const senderBalance = await erc20Contract.balanceOf(wallet.address); - //console.log(senderBalance) - - const tx = await wallet.populateTransaction(txRequest); - - const signedTx = await wallet.signTransaction(tx); - await provider.send('eth_sendRawTransaction', [signedTx]); - - const tokenAddress = await getEthAddress(ETH_ADDRESS); - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)', - 'function transfer(address to, uint256 amount) public returns (bool)' - ]; - const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); - const balance1 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000012'); - const balance2 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000013'); - expect(balance1).toBe(BigInt(1000)) - expect(balance2).toBe(BigInt(2000)) - }) - - test.only('Multicall tx with legacy transaction type', async () => { - const provider = new ethers.JsonRpcProvider(SERVER); - - const devAcc = getDevAccount(); - const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D - const wallet = new ethers.Wallet(privateKey, provider); - - const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); - await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 strk - - const MULTICALL_ABI = [ - 'function multicall((uint256,uint256,uint256[])[])' - ]; - - const iface = new ethers.Interface(MULTICALL_ABI); - - const receiver1SnAddress = await precalculateStarknetAddress('0x00014'); - const receiver2SnAddress = await precalculateStarknetAddress('0x00015'); - - const data = iface.encodeFunctionData('multicall', [[ - [ - ETH_ADDRESS, - '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', - [receiver1SnAddress, '1000', '0'] - ], - [ - ETH_ADDRESS, - '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', - [receiver2SnAddress, '2000', '0'] - ] - ]]); - - const txRequest = { - to: '0x0000000000000000000000004645415455524553', // Token kontrat adresi - data: data, - type: 0 - }; - - //const senderBalance = await erc20Contract.balanceOf(wallet.address); - //console.log(senderBalance) - - const tx = await wallet.populateTransaction(txRequest); - - const signedTx = await wallet.signTransaction(tx); - await provider.send('eth_sendRawTransaction', [signedTx]); - - const tokenAddress = await getEthAddress(ETH_ADDRESS); - const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)', - 'function transfer(address to, uint256 amount) public returns (bool)' - ]; - const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); - const balance1 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000014'); - const balance2 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000015'); - expect(balance1).toBe(BigInt(1000)) - expect(balance2).toBe(BigInt(2000)) - }) + test.only('Retrive balance of the account', async () => { + const TestAccount1 = await getEthAddress(SN_ADDRESS_TEST_1); + const provider = new ethers.JsonRpcProvider(SERVER); + const balanceWei = await provider.getBalance(TestAccount1.ethereum); + + // Convert balance to Ether string + const balanceEther = ethers.formatEther(balanceWei); + expect(balanceEther).toBe("1250.0") + }, 30000) + + test.only('Retrive eth balance using erc20 contract', async () => { + const TestAccount1 = await getEthAddress(SN_ADDRESS_TEST_1); + const EthToken = await getEthAddress(ETH_ADDRESS) + const provider = new ethers.JsonRpcProvider(SERVER); + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)' + ]; + const tokenContract = new ethers.Contract(EthToken.ethereum, ERC20_ABI, provider); + + // Get balance + const balance = await tokenContract.balanceOf(TestAccount1.ethereum); + + // Get token decimals + const decimals = await tokenContract.decimals(); + expect(balance).toBe(BigInt("1000001461819925596660")) + expect(decimals).toBe(BigInt(18)) + }, 30000) + + test.only('Sends simple STRK transfer transaction. This may deploy account contract initially.', async () => { + const provider = new ethers.JsonRpcProvider(SERVER); + + // Fund initial address first + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + + const toAddress = '0x8b4ee3F7a16ed6b793BD7907f87778AC11624c27'; + + // We cant directly send transaction with wallet.sendTransaction. Because it expects precalculated tx hash from rpc. + // And it reverts if hash is different. + // TODO: In future we may return directly ethereum type eth hash and scanners matches them with actual starknet tx hashes? + const txRequest = await wallet.populateTransaction({ + to: toAddress, + value: ethers.parseEther('1.0') // 1 STRK + }); + + const signedTx = await wallet.signTransaction(txRequest); + + await provider.send('eth_sendRawTransaction', [signedTx]) + + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)' + ]; + const strkTokenAddress = await getEthAddress(STRK_ADDRESS); + + const strkContract = new ethers.Contract(strkTokenAddress.ethereum, ERC20_ABI, provider); + + const balance = await strkContract.balanceOf(toAddress); + + expect(balance).toBe(ethers.parseEther('1.0')) + + }) + + test.only('ERC20 transfer transaction. This may deploy account contract initially.', async () => { + const provider = new ethers.JsonRpcProvider(SERVER); + + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 erc20 + const tokenAddress = await getEthAddress(ETH_ADDRESS); + + const toAddress = '0x8b4ee3F7a16ed6b793BD7907f87778AC11624c27'; + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function transfer(address to, uint256 amount) public returns (bool)' + ]; + const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); + + const iface = new ethers.Interface(ERC20_ABI); + + const data = iface.encodeFunctionData('transfer', [ + toAddress, + ethers.parseUnits('1', 18) + ]); + + const txRequest = { + to: tokenAddress.ethereum, // Token kontrat adresi + data: data, + }; + + await erc20Contract.balanceOf(wallet.address); + + const tx = await wallet.populateTransaction(txRequest); + + const signedTx = await wallet.signTransaction(tx); + const sentTx = await provider.send('eth_sendRawTransaction', [signedTx]); + + + await provider.waitForTransaction(sentTx, 0); // 0 confirmations needed since its devnet + + const balance = await erc20Contract.balanceOf(toAddress); + + expect(balance).toBe(ethers.parseEther('1.0')) + }) + + test.only('ERC20 transfer transaction. From already deployed account contract.', async () => { + const provider = new ethers.JsonRpcProvider(SERVER); + + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 eth + const tokenAddress = await getEthAddress(ETH_ADDRESS); + + const toAddress = '0x8B4ee3F7a16eD6B793bD7907F87778AC11624C28'; + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function transfer(address to, uint256 amount) public returns (bool)' + ]; + const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); + + const iface = new ethers.Interface(ERC20_ABI); + + const data = iface.encodeFunctionData('transfer', [ + toAddress, + ethers.parseUnits('1', 18) + ]); + + const txRequest = { + to: tokenAddress.ethereum, // Token kontrat adresi + data: data, + }; + + console.log("ERC20 transfer transaction. From already deployed account contract", await erc20Contract.balanceOf(wallet.address)) + + const tx = await wallet.populateTransaction(txRequest); + + const signedTx = await wallet.signTransaction(tx); + const sentTx = await provider.send('eth_sendRawTransaction', [signedTx]); + + + await provider.waitForTransaction(sentTx, 0); // 0 confirmations needed since its devnet + + // Now its deployed. Lets send again with legacy tx + + const txRequestLegacy = { + to: tokenAddress.ethereum, // Token kontrat adresi + data: data, + type: 0 + }; + + const legacyTx = await wallet.populateTransaction(txRequestLegacy); + const signedLegacyTx = await wallet.signTransaction(legacyTx); + const sentLegacyTx = await provider.send('eth_sendRawTransaction', [signedLegacyTx]); + await provider.waitForTransaction(sentLegacyTx, 0); + + const balance = await erc20Contract.balanceOf(toAddress); + + expect(balance).toBe(ethers.parseEther('2.0')) + }) + + test.only('Multicall transaction that transfers erc20 to two different accounts', async () => { + const provider = new ethers.JsonRpcProvider(SERVER); + + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + + const MULTICALL_ABI = [ + 'function multicall((uint256,uint256,uint256[])[])' + ]; + + const iface = new ethers.Interface(MULTICALL_ABI); + + const receiver1SnAddress = await precalculateStarknetAddress('0x00012'); + const receiver2SnAddress = await precalculateStarknetAddress('0x00013'); + + const data = iface.encodeFunctionData('multicall', [[ + [ + ETH_ADDRESS, + '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', + [receiver1SnAddress, '1000', '0'] + ], + [ + ETH_ADDRESS, + '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', + [receiver2SnAddress, '2000', '0'] + ] + ]]); + + const txRequest = { + to: '0x0000000000000000000000004645415455524553', // Token kontrat adresi + data: data, + }; + + //const senderBalance = await erc20Contract.balanceOf(wallet.address); + //console.log(senderBalance) + + const tx = await wallet.populateTransaction(txRequest); + + const signedTx = await wallet.signTransaction(tx); + await provider.send('eth_sendRawTransaction', [signedTx]); + + const tokenAddress = await getEthAddress(ETH_ADDRESS); + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function transfer(address to, uint256 amount) public returns (bool)' + ]; + const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); + const balance1 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000012'); + const balance2 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000013'); + expect(balance1).toBe(BigInt(1000)) + expect(balance2).toBe(BigInt(2000)) + }) + + test.only('Multicall tx with legacy transaction type', async () => { + const provider = new ethers.JsonRpcProvider(SERVER); + + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c505'; // 0xAE97807Cf37BeF18e8347aD7B47658d6d96c503D + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendERC20FromSnAccount(devAcc, ETH_ADDRESS, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + + const MULTICALL_ABI = [ + 'function multicall((uint256,uint256,uint256[])[])' + ]; + + const iface = new ethers.Interface(MULTICALL_ABI); + + const receiver1SnAddress = await precalculateStarknetAddress('0x00014'); + const receiver2SnAddress = await precalculateStarknetAddress('0x00015'); + + const data = iface.encodeFunctionData('multicall', [[ + [ + ETH_ADDRESS, + '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', + [receiver1SnAddress, '1000', '0'] + ], + [ + ETH_ADDRESS, + '0x0083afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e', + [receiver2SnAddress, '2000', '0'] + ] + ]]); + + const txRequest = { + to: '0x0000000000000000000000004645415455524553', // Token kontrat adresi + data: data, + type: 0 + }; + + //const senderBalance = await erc20Contract.balanceOf(wallet.address); + //console.log(senderBalance) + + const tx = await wallet.populateTransaction(txRequest); + + const signedTx = await wallet.signTransaction(tx); + await provider.send('eth_sendRawTransaction', [signedTx]); + + const tokenAddress = await getEthAddress(ETH_ADDRESS); + const ERC20_ABI = [ + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function transfer(address to, uint256 amount) public returns (bool)' + ]; + const erc20Contract = new ethers.Contract(tokenAddress.ethereum, ERC20_ABI, wallet); + const balance1 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000014'); + const balance2 = await erc20Contract.balanceOf('0x0000000000000000000000000000000000000015'); + expect(balance1).toBe(BigInt(1000)) + expect(balance2).toBe(BigInt(2000)) + }) }) \ No newline at end of file diff --git a/e2e/rpc/sendRawTransaction.test.ts b/e2e/rpc/sendRawTransaction.test.ts index 9d0a5ff..518d73e 100644 --- a/e2e/rpc/sendRawTransaction.test.ts +++ b/e2e/rpc/sendRawTransaction.test.ts @@ -22,25 +22,25 @@ describe('Using ethers.js with Rosettanet RPC', () => { const toAddress = '0x8b4ee3F7a16ed6b793BD7907f87778AC11624c27'; const ERC20_ABI = [ - 'function balanceOf(address owner) view returns (uint256)', - 'function decimals() view returns (uint8)', - 'function transfer(address to, uint256 amount) public returns (bool)' + 'function balanceOf(address owner) view returns (uint256)', + 'function decimals() view returns (uint8)', + 'function transfer(address to, uint256 amount) public returns (bool)' ]; const tokenAddress = await getEthAddress(ETH_ADDRESS); const devAcc = getDevAccount() const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') - + const iface = new ethers.Interface(ERC20_ABI); - + const data = iface.encodeFunctionData('transfer', [ - toAddress, - ethers.parseUnits('1', 18) + toAddress, + ethers.parseUnits('1', 18) ]); - + const txRequest = { - to: tokenAddress.ethereum, // Token kontrat adresi - data: data, + to: tokenAddress.ethereum, // Token kontrat adresi + data: data, }; const tx = await wallet.populateTransaction(txRequest); @@ -116,7 +116,25 @@ describe('Using ethers.js with Rosettanet RPC', () => { }, 30000) test.only('Send already sent tx twice in array', async () => { - const txs = ['0x02f8b4845253545380843b9aca00852ecc889a0082520894b5e1278663de249f8580ec51b6b61739bd90621580b844a9059cbb0000000000000000000000008b4ee3f7a16ed6b793bd7907f87778ac11624c270000000000000000000000000000000000000000000000000de0b6b3a7640000c080a07ec65572fb7f245736b47900c99a0818f588c69a09e3dc3132bd752adf5a665ca06bb0ee1ce53ac2b0e88b6aecac60ffba66d90613ad3cc8b1ac13df5bae6221f9', '0x02f8b4845253545380843b9aca00852ecc889a0082520894b5e1278663de249f8580ec51b6b61739bd90621580b844a9059cbb0000000000000000000000008b4ee3f7a16ed6b793bd7907f87778ac11624c270000000000000000000000000000000000000000000000000de0b6b3a7640000c080a07ec65572fb7f245736b47900c99a0818f588c69a09e3dc3132bd752adf5a665ca06bb0ee1ce53ac2b0e88b6aecac60ffba66d90613ad3cc8b1ac13df5bae6221f9'] + const provider = new ethers.JsonRpcProvider(SERVER); + // Fund initial address first + const devAcc = getDevAccount(); + const privateKey = '0x9979f9c93cbca19e905a21ce4d6ee9233948bcfe67d95c11de664ebe4b78c506'; + const wallet = new ethers.Wallet(privateKey, provider); + + const precalculatedSnAddress = await precalculateStarknetAddress(wallet.address); + await sendStrksFromSnAccount(devAcc, precalculatedSnAddress, '100000000000000000000') // sends 100 strk + + const toAddress = '0xDbA5375833DBbA1D58C87864369D4Be5d1a24bCe'; + + const txRequest = await wallet.populateTransaction({ + to: toAddress, + value: ethers.parseEther('1.0') // 1 STRK + }); + + const signedTx = await wallet.signTransaction(txRequest); + + const txs = [signedTx, signedTx] // Sending same tx twice const response = await axios.post(SERVER, [{ jsonrpc: '2.0', @@ -127,9 +145,11 @@ describe('Using ethers.js with Rosettanet RPC', () => { jsonrpc: '2.0', method: 'eth_sendRawTransaction', params: [txs[1]], - id: 2, + id: 2, }]) + console.log(response.data) + expect(response.data.length).toBe(2) expect(response.data[0].id).toBe(1) expect(response.data[0].jsonrpc).toBe('2.0') diff --git a/e2e/utils.ts b/e2e/utils.ts index 9ddadd0..c274e28 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -20,6 +20,7 @@ export const testConfig = { '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d', rosettanet: '0x007288a71619eca9397bf0d3066d236b41de33fd6af3a420d16b2f55c93f8af7', + validateFeeEstimator: "0x0", featureTarget: "0x0000000000000000000000004645415455524553", logging: { active: true, @@ -80,7 +81,7 @@ export async function updateNodeConfig(config: string) { const configFilePath = path.resolve(__dirname, '../config.test.json') await fs.writeFile(configFilePath, config, 'utf-8') - console.log('Configuration updated.') + console.log('Contracts deployed & Configuration updated.') return } catch (ex) { console.error('Error at updating node config:', ex) @@ -130,19 +131,31 @@ export function getEthStrkHolderAccount(): Account { } export async function sendStrksFromSnAccount(account: Account, recipient: string, amount: BigNumberish) { - await account.execute({ - contractAddress: STRK_ADDRESS, - entrypoint: 'transfer', - calldata: [recipient, uint256.bnToUint256(amount).low, uint256.bnToUint256(amount).high] - }) + try { + await account.execute({ + contractAddress: STRK_ADDRESS, + entrypoint: 'transfer', + calldata: [recipient, uint256.bnToUint256(amount).low, uint256.bnToUint256(amount).high] + }) + return true + } catch (e) { + console.log(e); + throw new Error("Failed to sendStrksFromSnAccount"); + } } export async function sendERC20FromSnAccount(account: Account, erc20Contract: string, recipient: string, amount: BigNumberish) { - await account.execute({ - contractAddress: erc20Contract, - entrypoint: 'transfer', - calldata: [recipient, uint256.bnToUint256(amount).low, uint256.bnToUint256(amount).high] - }) + try { + await account.execute({ + contractAddress: erc20Contract, + entrypoint: 'transfer', + calldata: [recipient, uint256.bnToUint256(amount).low, uint256.bnToUint256(amount).high] + }) + return true + } catch (e) { + console.log(e); + throw new Error("Failed to sendERC20FromSnAccount"); + } } export function getProvider(): RpcProvider { diff --git a/scripts/e2e_tests_specific.sh b/scripts/e2e_tests_specific.sh index 1b848d9..828f5d3 100755 --- a/scripts/e2e_tests_specific.sh +++ b/scripts/e2e_tests_specific.sh @@ -10,7 +10,6 @@ start_devnet() { echo "Starting Starknet Devnet..." starknet-devnet \ --seed "$SEED" \ - --request-body-size-limit "$REQUEST_BODY_SIZE_LIMIT" \ --port "$PORT" & # Store the PID of the devnet process @@ -23,7 +22,7 @@ start_devnet() { # Function to run E2E tests run_e2e_tests() { echo "Running E2E tests..." - jest --config ./e2e/jest_specific.config.ts --runInBand + npx jest --config ./e2e/jest_specific.config.ts --runInBand } # Function to cleanup devnet process diff --git a/src/rpc/calls/sendRawTransaction.ts b/src/rpc/calls/sendRawTransaction.ts index d1c0508..d0a0241 100644 --- a/src/rpc/calls/sendRawTransaction.ts +++ b/src/rpc/calls/sendRawTransaction.ts @@ -61,9 +61,8 @@ export async function sendRawTransactionHandler( const signedValidRawTransaction: SignedRawTransaction | ValidationError = validateRawTransaction(tx) - writeLog(1, 'signed valid tx') - writeLog(1, JSON.stringify(signedValidRawTransaction,(k, v) => typeof v === 'bigint' ? v.toString() : v)) - //console.log(signedValidRawTransaction) + writeLog(1, 'signed valid tx') + writeLog(1, JSON.stringify(signedValidRawTransaction, (k, v) => typeof v === 'bigint' ? v.toString() : v)) if (!isSignedRawTransaction(signedValidRawTransaction)) { return { jsonrpc: request.jsonrpc, @@ -78,12 +77,11 @@ export async function sendRawTransactionHandler( const deployedAccountAddress: RosettanetAccountResult = await getRosettaAccountAddress(signedValidRawTransaction.from) if (!deployedAccountAddress.isDeployed) { - writeLog(0, JSON.stringify(signedValidRawTransaction,(k, v) => typeof v === 'bigint' ? v.toString() : v)) + writeLog(0, JSON.stringify(signedValidRawTransaction, (k, v) => typeof v === 'bigint' ? v.toString() : v)) return deployAndBroadcastTransaction(request, signedValidRawTransaction) } const starknetAccountAddress = deployedAccountAddress.contractAddress - // console.log(starknetAccountAddress) const rosettanetCalldata = prepareRosettanetCalldata( signedValidRawTransaction, ) @@ -112,7 +110,7 @@ export async function sendRawTransactionHandler( resourceBounds ) - writeLog(0, JSON.stringify(invokeTx,(k, v) => typeof v === 'bigint' ? v.toString() : v)) + writeLog(0, JSON.stringify(invokeTx, (k, v) => typeof v === 'bigint' ? v.toString() : v)) return await broadcastTransaction(request, invokeTx) } @@ -124,14 +122,14 @@ async function broadcastTransaction( ): Promise { const response: RPCResponse | StarknetRPCError = await callStarknet(< RPCRequest - >{ - jsonrpc: request.jsonrpc, - id: request.id, - params: params, - method: 'starknet_addInvokeTransaction', - }) + >{ + jsonrpc: request.jsonrpc, + id: request.id, + params: params, + method: 'starknet_addInvokeTransaction', + }) if (isStarknetRPCError(response)) { - writeLog(1, 'Starknet RPC returned error at broadcastTransaction: ' + JSON.stringify(response,(k, v) => typeof v === 'bigint' ? v.toString() : v)) + writeLog(1, 'Starknet RPC returned error at broadcastTransaction: ' + JSON.stringify(response, (k, v) => typeof v === 'bigint' ? v.toString() : v)) if (response.code == 55) { return { jsonrpc: request.jsonrpc, @@ -168,7 +166,9 @@ async function deployAndBroadcastTransaction( txn: SignedRawTransaction, ): Promise { const starknetNonce = '0x1' - writeLog(0,'will be deployed and executed') + writeLog(0, 'will be deployed and executed') + + const resourceBounds = await resourceBoundsFromSignedTxn(txn); // This means account is not registered on rosettanet registry. Lets deploy the address const accountDeployResult: AccountDeployResult | AccountDeployError = @@ -200,7 +200,6 @@ async function deployAndBroadcastTransaction( } } - const resourceBounds = await resourceBoundsFromSignedTxn(txn); const invokeTx = prepareStarknetInvokeTransaction( accountDeployResult.contractAddress, @@ -211,6 +210,6 @@ async function deployAndBroadcastTransaction( resourceBounds ) writeLog(0, 'invoke tx') - writeLog(0,JSON.stringify(invokeTx,(k, v) => typeof v === 'bigint' ? v.toString() : v)) + writeLog(0, JSON.stringify(invokeTx, (k, v) => typeof v === 'bigint' ? v.toString() : v)) return await broadcastTransaction(request, invokeTx) } diff --git a/src/utils/wrapper.ts b/src/utils/wrapper.ts index dd37ff9..da4f112 100644 --- a/src/utils/wrapper.ts +++ b/src/utils/wrapper.ts @@ -187,11 +187,11 @@ export async function estimateExecutionFee(sender: string, calldata: string[], n method: 'starknet_estimateFee', params: { request: [{ - type:'INVOKE', + type: 'INVOKE', version: '0x3', sender_address: sender, calldata: calldata, - signature: ["0x0","0x0","0x0","0x0","0x1c",...BnToU256(value)], + signature: ["0x0", "0x0", "0x0", "0x0", "0x1c", ...BnToU256(value)], nonce: addHexPrefix(nonce), tip: '0x0', paymaster_data: [], @@ -221,19 +221,19 @@ export async function estimateExecutionFee(sender: string, calldata: string[], n const executionFeeResult: RPCResponse | StarknetRPCError = await callStarknet(estimateFeeCall); - if(isStarknetRPCError(executionFeeResult)) { + if (isStarknetRPCError(executionFeeResult)) { writeLog(2, 'Error at starknet call on estimateFee @ wrapper.ts. Returning default.'); return DEFAULT_EXECUTION_FEE; } const fees = executionFeeResult.result[0]; - if(!fees || typeof fees.l1_data_gas_consumed !== 'string' || typeof fees.l1_gas_consumed !== 'string' || typeof fees.l2_gas_consumed !== 'string') { + if (!fees || typeof fees.l1_data_gas_consumed !== 'string' || typeof fees.l1_gas_consumed !== 'string' || typeof fees.l2_gas_consumed !== 'string') { writeLog(2, 'Error at starknet result estimateFee @ wrapper.ts. Returning default.'); return DEFAULT_EXECUTION_FEE; } - return { + return { l1_data: Number(BigInt(fees.l1_data_gas_consumed)), l1: Number(BigInt(fees.l1_gas_consumed)), l2: Number(BigInt(fees.l2_gas_consumed)), @@ -245,68 +245,69 @@ export async function mockValidateCost(caller: string, calldata: string[]): Prom const DEFAULT_VALIDATION_FEE: GasCost = { l1_data: 256, l1: 0, - l2: 20698786 + l2: 30698786 }; const estimateFeeCall = { - jsonrpc: '2.0', - method: 'starknet_estimateFee', - params: { - request: [{ - type:'INVOKE', - version: '0x3', - sender_address: feeEstimator, - calldata: [caller, ...calldata], - signature: ["0x0","0x0","0x0","0x0","0x1c","0x1","0x0"], - nonce: '0x1', - tip: '0x0', - paymaster_data: [], - account_deployment_data: [], - nonce_data_availability_mode: 'L1', - fee_data_availability_mode: 'L1', - resource_bounds: { - l1_gas: { - max_amount: '0x0', - max_price_per_unit: '0x0', - }, - l2_gas: { - max_amount: '0x0', - max_price_per_unit: '0x0', - }, - l1_data_gas: { - max_amount: '0x0', - max_price_per_unit: '0x0', - }, + jsonrpc: '2.0', + method: 'starknet_estimateFee', + params: { + request: [{ + type: 'INVOKE', + version: '0x3', + sender_address: feeEstimator, + calldata: [caller, ...calldata], + signature: ["0x0", "0x0", "0x0", "0x0", "0x1c", "0x1", "0x0"], + nonce: "0x0", + tip: '0x0', + paymaster_data: [], + account_deployment_data: [], + nonce_data_availability_mode: 'L1', + fee_data_availability_mode: 'L1', + resource_bounds: { + l1_gas: { + max_amount: '0x0', + max_price_per_unit: '0x0', }, - }], - simulation_flags: ['SKIP_VALIDATE'], - block_id: 'latest' - }, - id: 123 - }; + l2_gas: { + max_amount: '0x0', + max_price_per_unit: '0x0', + }, + l1_data_gas: { + max_amount: '0x0', + max_price_per_unit: '0x0', + }, + }, + }], + simulation_flags: ['SKIP_VALIDATE'], + block_id: 'latest' + }, + id: 123 + }; - const validationFeeResult: RPCResponse | StarknetRPCError = await callStarknet(estimateFeeCall); + const validationFeeResult: RPCResponse | StarknetRPCError = await callStarknet(estimateFeeCall); - if(isStarknetRPCError(validationFeeResult)) { - writeLog(2, 'Error at starknet call on mockValidateCost. Returning default.'); - return DEFAULT_VALIDATION_FEE; - } + if (isStarknetRPCError(validationFeeResult)) { + writeLog(2, 'Error at starknet call on mockValidateCost. Returning default.'); + return DEFAULT_VALIDATION_FEE; + } - const fees = validationFeeResult.result[0]; + const fees = validationFeeResult.result[0]; - if(!fees || typeof fees.l1_data_gas_consumed !== 'string' || typeof fees.l1_gas_consumed !== 'string' || typeof fees.l2_gas_consumed !== 'string') { - writeLog(2, 'Error at starknet result validation on mockValidateCost. Returning default.'); - return DEFAULT_VALIDATION_FEE; - } + if (!fees || typeof fees.l1_data_gas_consumed !== 'string' || typeof fees.l1_gas_consumed !== 'string' || typeof fees.l2_gas_consumed !== 'string') { + writeLog(2, 'Error at starknet result validation on mockValidateCost. Returning default.'); + return DEFAULT_VALIDATION_FEE; + } - const l1_data = Math.ceil(Number(BigInt(fees.l1_data_gas_consumed)) * 2.4); - const l1 = Math.ceil(Number(BigInt(fees.l1_gas_consumed)) * 2.0); - const l2 = Math.ceil(Number(BigInt(fees.l2_gas_consumed)) * 2.4); - return { - l1_data: l1_data >= DEFAULT_VALIDATION_FEE.l1_data ? l1_data: DEFAULT_VALIDATION_FEE.l1_data, - l1: l1 >= DEFAULT_VALIDATION_FEE.l1 ? l1: DEFAULT_VALIDATION_FEE.l1, - l2: l2 >= DEFAULT_VALIDATION_FEE.l2 ? l2: DEFAULT_VALIDATION_FEE.l2, - } + const l1_data = Math.ceil(Number(BigInt(fees.l1_data_gas_consumed)) * 2.4); + const l1 = Math.ceil(Number(BigInt(fees.l1_gas_consumed)) * 2.0); + const l2 = Math.ceil(Number(BigInt(fees.l2_gas_consumed)) * 2.4); + + return { + l1_data: l1_data >= DEFAULT_VALIDATION_FEE.l1_data ? l1_data : DEFAULT_VALIDATION_FEE.l1_data, + l1: l1 >= DEFAULT_VALIDATION_FEE.l1 ? l1 : DEFAULT_VALIDATION_FEE.l1, + l2: l2 >= DEFAULT_VALIDATION_FEE.l2 ? l2 : DEFAULT_VALIDATION_FEE.l2, + } } /*