diff --git a/js/Bundle.js b/js/Bundle.js index c414a31c..234af309 100644 --- a/js/Bundle.js +++ b/js/Bundle.js @@ -30,7 +30,9 @@ Bundle.prototype.getNonce = async function(provider) { Bundle.prototype.estimate = async function({ fetch, relayerURL, replacing, getNextNonce }) { const res = await fetchPost( fetch, - `${relayerURL}/identity/${this.identity}/${this.network}/estimate${getNextNonce ? '?getNextNonce=true' : ''}`, + `${relayerURL}/identity/${this.identity}/${this.network}/estimate${ + getNextNonce ? '?getNextNonce=true' : '' + }`, { txns: this.txns, signer: this.signer, replacing, minFeeInUSDPerGas: this.minFeeInUSDPerGas } ) this.gasLimit = res.gasLimit @@ -51,7 +53,14 @@ Bundle.prototype.submit = async function({ fetch, relayerURL }) { const res = await fetchPost( fetch, `${relayerURL}/identity/${this.identity}/${this.network}/submit`, - { nonce: this.nonce, signer: this.signer, txns: this.txns, gasLimit: this.gasLimit, signature: this.signature, signatureTwo: this.signatureTwo } + { + nonce: this.nonce, + signer: this.signer, + txns: this.txns, + gasLimit: this.gasLimit, + signature: this.signature, + signatureTwo: this.signatureTwo + } ) return res } @@ -77,26 +86,27 @@ Bundle.prototype.estimateNoRelayer = async function({ provider, replacing }) { if (error && error.message.startsWith('execution reverted: ')) { const message = error.message.slice(20) return { success: false, message } - } else if (error) { + } + if (error) { // Match both the code and the regex to handle both errs from ethers and raw ones from nodes in case we use .send - if (!(error.code === 'UNPREDICTABLE_GAS_LIMIT' || error.message.match(UNPREDICTABLE_GAS_REGEX))) throw error + if (!(error.code === 'UNPREDICTABLE_GAS_LIMIT' || error.message.match(UNPREDICTABLE_GAS_REGEX))) + throw error return { success: false, message: await getErrMsg(provider, txParams, blockTag) } - } else { - this.gasLimit = gasLimit.toNumber() - // @TODO EIP1559-optimized estimations (good first issue for external contributors) - const feeData = await provider.getFeeData() - const gasPrice = feeData.gasPrice.toNumber() - const baseFee = gasPrice * gasLimit / 1e18 - return { - success: true, - gasLimit: this.gasLimit, - gasPrice, - feeInNative: { - slow: baseFee * 0.9, - medium: baseFee * 1.0, - fast: baseFee * 1.15, - ape: baseFee * 1.4 - } + } + this.gasLimit = gasLimit.toNumber() + // @TODO EIP1559-optimized estimations (good first issue for external contributors) + const feeData = await provider.getFeeData() + const gasPrice = feeData.gasPrice.toNumber() + const baseFee = (gasPrice * gasLimit) / 1e18 + return { + success: true, + gasLimit: this.gasLimit, + gasPrice, + feeInNative: { + slow: baseFee * 0.9, + medium: baseFee * 1.0, + fast: baseFee * 1.15, + ape: baseFee * 1.4 } } } @@ -128,7 +138,12 @@ function getSignable(userTxnBundle, isSingleSigMode) { if (signer.address) return abiCoder.encode( ['address', 'uint', 'uint', 'tuple(address, uint, bytes)[]'], - [userTxnBundle.identity, getChainID(userTxnBundle.network), userTxnBundle.nonce, userTxnBundle.txns] + [ + userTxnBundle.identity, + getChainID(userTxnBundle.network), + userTxnBundle.nonce, + userTxnBundle.txns + ] ) if (signer.quickAccManager) { const accHash = keccak256( @@ -141,7 +156,15 @@ function getSignable(userTxnBundle, isSingleSigMode) { // if (signer.isTypedData) return abiCoder.encode( ['address', 'uint', 'address', 'bytes32', 'uint', 'tuple(address, uint, bytes)[]', 'bool'], - [signer.quickAccManager, getChainID(userTxnBundle.network), userTxnBundle.identity, accHash, userTxnBundle.nonce, userTxnBundle.txns, !isSingleSigMode] + [ + signer.quickAccManager, + getChainID(userTxnBundle.network), + userTxnBundle.identity, + accHash, + userTxnBundle.nonce, + userTxnBundle.txns, + !isSingleSigMode + ] ) } throw new Error(`invalid signer object`) @@ -203,12 +226,12 @@ async function fetchPost(fetch, url, body) { // Signature of Error(string) const ERROR_SIG = '0x08c379a0' -async function getErrMsg (provider, txParams, blockTag) { +async function getErrMsg(provider, txParams, blockTag) { // .call always returns a hex string with ethers try { const returnData = await provider.call(txParams, blockTag) return returnData.startsWith(ERROR_SIG) - ? (new AbiCoder()).decode(['string'], '0x' + returnData.slice(10))[0] + ? new AbiCoder().decode(['string'], `0x${returnData.slice(10)}`)[0] : returnData } catch (e) { // weird infura case @@ -219,11 +242,14 @@ async function getErrMsg (provider, txParams, blockTag) { } } -async function estimateGasWithCatch (provider, blockTag, tx) { - return provider.send('eth_estimateGas', [tx, blockTag]) - .then(gasLimit => ({ gasLimit: BigNumber.from(gasLimit) })) - // with .send, the error is wrapped in another error - .catch(e => e.code === 'SERVER_ERROR' ? { error: e.error } : { error: e }) +async function estimateGasWithCatch(provider, blockTag, tx) { + return ( + provider + .send('eth_estimateGas', [tx, blockTag]) + .then(gasLimit => ({ gasLimit: BigNumber.from(gasLimit) })) + // with .send, the error is wrapped in another error + .catch(e => (e.code === 'SERVER_ERROR' ? { error: e.error } : { error: e })) + ) } // getNonce(require('ethers').getDefaultProvider('homestead'), { identity: '0x23c2c34f38ce66ccc10e71e9bb2a06532d52c5e8', signer: {address: '0x942f9CE5D9a33a82F88D233AEb3292E680230348'}, txns: [] }).then(console.log) diff --git a/js/IdentityProxyDeploy.js b/js/IdentityProxyDeploy.js index abe70d97..f3043abc 100644 --- a/js/IdentityProxyDeploy.js +++ b/js/IdentityProxyDeploy.js @@ -24,10 +24,10 @@ function sstoreCode(slotNumber, keyType, key, valueType, valueBuf) { function getProxyDeployBytecode(masterContractAddr, privLevels, opts = { privSlot: 0 }) { const { privSlot = 0 } = opts if (privLevels.length > 3) throw new Error('getProxyDeployBytecode: max 3 privLevels') - const storage = Buffer.concat(privLevels - .map(([addr, data]) => { - return data !== true ? - sstoreCode(privSlot, 'address', addr, 'bytes32', data) + const storage = Buffer.concat( + privLevels.map(([addr, data]) => { + return data !== true + ? sstoreCode(privSlot, 'address', addr, 'bytes32', data) : sstoreCode(privSlot, 'address', addr, 'bool', Buffer.from('01', 'hex')) }) ) @@ -36,14 +36,12 @@ function getProxyDeployBytecode(masterContractAddr, privLevels, opts = { privSlo // @TODO solve this case; this will remove the "max 3 privLevels" restriction const offset = storage.length + initial.length + 6 // 6 more bytes including the push added later on if (offset > 256) throw new Error('getProxyDeployBytecode: internal: offset>256') - const initialCode = Buffer.concat([ - storage, - initial, - evmPush(Buffer.from([offset])) - ]) + const initialCode = Buffer.concat([storage, initial, evmPush(Buffer.from([offset]))]) const masterAddrBuf = Buffer.from(masterContractAddr.slice(2).replace(/^(00)+/, ''), 'hex') if (masterAddrBuf > 20) throw new Error('invalid address') - return `0x${initialCode.toString('hex')}3d3981f3363d3d373d3d3d363d${evmPush(masterAddrBuf).toString('hex')}5af43d82803e903d91602b57fd5bf3` + return `0x${initialCode.toString('hex')}3d3981f3363d3d373d3d3d363d${evmPush( + masterAddrBuf + ).toString('hex')}5af43d82803e903d91602b57fd5bf3` } function getStorageSlotsFromArtifact(IdentityArtifact) { @@ -62,4 +60,3 @@ function getStorageSlotsFromArtifact(IdentityArtifact) { } module.exports = { evmPush, sstoreCode, getProxyDeployBytecode, getStorageSlotsFromArtifact } - diff --git a/test/TestADXToken.js b/test/TestADXToken.js index 5fc92255..0db1d707 100644 --- a/test/TestADXToken.js +++ b/test/TestADXToken.js @@ -109,5 +109,6 @@ contract('ADXToken', function(accounts) { // Governance can step down await adxSupplyController.setGovernance(governance, 0) - await expectEVMError(adxSupplyController.mint(tokenAddr, userAddr, largeAmnt), 'NOT_GOVERNANCE')}) + await expectEVMError(adxSupplyController.mint(tokenAddr, userAddr, largeAmnt), 'NOT_GOVERNANCE') + }) }) diff --git a/test/TestIdentity.js b/test/TestIdentity.js index 619d5643..ddc8250d 100644 --- a/test/TestIdentity.js +++ b/test/TestIdentity.js @@ -1,6 +1,14 @@ const promisify = require('util').promisify const { providers, Contract } = require('ethers') -const { Interface, randomBytes, getAddress, AbiCoder, keccak256, arrayify, hexlify } = require('ethers').utils +const { + Interface, + randomBytes, + getAddress, + AbiCoder, + keccak256, + arrayify, + hexlify +} = require('ethers').utils const { generateAddress2 } = require('ethereumjs-util') const Outpace = artifacts.require('OUTPACE') @@ -53,7 +61,7 @@ contract('Identity', function(accounts) { const anotherAccount = accounts[7] before(async function() { - //chainId = (await web3Provider.getNetwork()).chainId + // chainId = (await web3Provider.getNetwork()).chainId // we seem to be using 1 in testing conditions for whatever reason chainId = 1 @@ -71,16 +79,17 @@ contract('Identity', function(accounts) { const idWeb3 = await Identity.new([]) baseIdentityAddr = idWeb3.address - // a hardcoded test - assert.equal(getProxyDeployBytecode('0x02a63ec1bced5545296a5193e652e25ec0bae410', [['0xe5a4Dad2Ea987215460379Ab285DF87136E83BEA', true]]), '0x60017f02c94ba85f2ea274a3869293a0a9bf447d073c83c617963b0be7c862ec2ee44e553d602d80602e3d3981f3363d3d373d3d3d363d7302a63ec1bced5545296a5193e652e25ec0bae4105af43d82803e903d91602b57fd5bf3') - - const bytecode = getProxyDeployBytecode( - baseIdentityAddr, - [[userAcc, true]], - { - ...getStorageSlotsFromArtifact(Identity) - } + // a hardcoded test + assert.equal( + getProxyDeployBytecode('0x02a63ec1bced5545296a5193e652e25ec0bae410', [ + ['0xe5a4Dad2Ea987215460379Ab285DF87136E83BEA', true] + ]), + '0x60017f02c94ba85f2ea274a3869293a0a9bf447d073c83c617963b0be7c862ec2ee44e553d602d80602e3d3981f3363d3d373d3d3d363d7302a63ec1bced5545296a5193e652e25ec0bae4105af43d82803e903d91602b57fd5bf3' ) + + const bytecode = getProxyDeployBytecode(baseIdentityAddr, [[userAcc, true]], { + ...getStorageSlotsFromArtifact(Identity) + }) const receipt = await (await identityFactory.deploy(bytecode, 0, { gasLimit })).wait() const deployedEv = receipt.events.find(x => x.event === 'LogDeployed') id = new Contract(deployedEv.args.addr, Identity._json.abi, signer) @@ -93,7 +102,10 @@ contract('Identity', function(accounts) { }) it('protected methods', async function() { - await expectEVMError(id.setAddrPrivilege(userAcc, TRUE_BYTES, { gasLimit }), 'ONLY_IDENTITY_CAN_CALL') + await expectEVMError( + id.setAddrPrivilege(userAcc, TRUE_BYTES, { gasLimit }), + 'ONLY_IDENTITY_CAN_CALL' + ) }) it('deploy an Identity, counterfactually', async function() { @@ -143,11 +155,8 @@ contract('Identity', function(accounts) { const hash = hashTxns(id.address, 1, initialNonce, [relayerTx]) // Non-authorized address does not work - const invalidSig = await signMsg(evilAcc, hash) - await expectEVMError( - id.execute([relayerTx], invalidSig), - 'INSUFFICIENT_PRIVILEGE' - ) + const invalidSig = await signMsg(evilAcc, hash) + await expectEVMError(id.execute([relayerTx], invalidSig), 'INSUFFICIENT_PRIVILEGE') // Do the execute() correctly, verify if it worked const relayerTxSig = await signMsg(userAcc, hash) @@ -172,10 +181,7 @@ contract('Identity', function(accounts) { idInterface.encodeFunctionData('setAddrPrivilege', [userAcc, FALSE_BYTES]) ] const sig = await signMsg(userAcc, hashTxns(id.address, chainId, 1, [relayerDowngradeTx])) - await expectEVMError( - id.execute([relayerDowngradeTx], sig), - 'PRIVILEGE_NOT_DOWNGRADED' - ) + await expectEVMError(id.execute([relayerDowngradeTx], sig), 'PRIVILEGE_NOT_DOWNGRADED') }) it('quickAccount signature validation', async function() { @@ -195,13 +201,17 @@ contract('Identity', function(accounts) { ]) // The part that is evaluated by QuickAccManager - const sigInner = abiCoder.encode([ 'uint', 'bytes', 'bytes' ], [600, sig1, sig2]) - const sig = sigInner + abiCoder.encode(['address'], [quickAccManager.address]).slice(2) + '02' + const sigInner = abiCoder.encode(['uint', 'bytes', 'bytes'], [600, sig1, sig2]) + const sig = `${sigInner + abiCoder.encode(['address'], [quickAccManager.address]).slice(2)}02` // we need to deploy before being able to validate sigs const deployReceipt = await (await deploy()).wait() const deployedEv = deployReceipt.events.find(x => x.event === 'LogDeployed') - const identity = new Contract(deployedEv.args.addr, Identity._json.abi, web3Provider.getSigner(userAcc)) + const identity = new Contract( + deployedEv.args.addr, + Identity._json.abi, + web3Provider.getSigner(userAcc) + ) // 0x1626ba7e is the signature that the function has to return in case of successful verification assert.equal(await identity.isValidSignature(msgHash, sig), '0x1626ba7e') }) @@ -212,10 +222,16 @@ contract('Identity', function(accounts) { // First, prepare to authorize the quickAccount const quickAccount = [600, userAcc, anotherAccount] const accHash = keccak256(abiCoder.encode(['tuple(uint, address, address)'], [quickAccount])) - const authorizeQuickAcc = () => - (new Contract(id.address, Identity._json.abi, web3Provider.getSigner(userAcc))).executeBySender([ - [ id.address, 0, idInterface.encodeFunctionData('setAddrPrivilege', [quickAccManager.address, accHash]) ] - ]) + const authorizeQuickAcc = () => + new Contract(id.address, Identity._json.abi, web3Provider.getSigner(userAcc)).executeBySender( + [ + [ + id.address, + 0, + idInterface.encodeFunctionData('setAddrPrivilege', [quickAccManager.address, accHash]) + ] + ] + ) // Try relaying a txn const relayerTx = [ @@ -231,15 +247,13 @@ contract('Identity', function(accounts) { ]) // The part that is evaluated by QuickAccManager - const sigInner = abiCoder.encode([ 'uint', 'bytes', 'bytes' ], [600, sig1, sig2]) + const sigInner = abiCoder.encode(['uint', 'bytes', 'bytes'], [600, sig1, sig2]) // smart contract sig for quickAccManager.address - const dualSig = sigInner + abiCoder.encode(['address'], [quickAccManager.address]).slice(2) + '02' + const dualSig = `${sigInner + + abiCoder.encode(['address'], [quickAccManager.address]).slice(2)}02` // Not authorized yet - await expectEVMError( - id.execute([relayerTx], dualSig, { gasLimit }), - 'SV_WALLET_INVALID' - ) + await expectEVMError(id.execute([relayerTx], dualSig, { gasLimit }), 'SV_WALLET_INVALID') // Authorize the QuickAccManager with this accHash await authorizeQuickAcc() @@ -320,10 +334,7 @@ contract('Identity', function(accounts) { idInterface.encodeFunctionData('setAddrPrivilege', [userAcc, TRUE_BYTES]) ] - await expectEVMError( - id.executeBySender([relayerTx]), - 'INSUFFICIENT_PRIVILEGE' - ) + await expectEVMError(id.executeBySender([relayerTx]), 'INSUFFICIENT_PRIVILEGE') const idWithUser = new Contract(id.address, Identity._json.abi, web3Provider.getSigner(userAcc)) const receipt = await (await idWithUser.executeBySender([relayerTx], { @@ -615,7 +626,10 @@ contract('Identity', function(accounts) { */ function hashTxns(identityAddr, chainId, nonce, txns) { const abiCoder = new AbiCoder() - const encoded = abiCoder.encode(['address', 'uint', 'uint', 'tuple(address, uint, bytes)[]'], [identityAddr, chainId, nonce, txns]) + const encoded = abiCoder.encode( + ['address', 'uint', 'uint', 'tuple(address, uint, bytes)[]'], + [identityAddr, chainId, nonce, txns] + ) return arrayify(keccak256(encoded)) } @@ -629,7 +643,7 @@ contract('Identity', function(accounts) { async function signMsg(from, hash) { assert.equal(hash.length, 32, 'hash must be 32byte array buffer') // 01 is the enum number of EthSign signature type - return mapSignatureV(await web3Provider.getSigner(from).signMessage(hash)) + '01' + return `${mapSignatureV(await web3Provider.getSigner(from).signMessage(hash))}01` } function createAccount(privileges, opts) { diff --git a/test/TestStakingPool.js b/test/TestStakingPool.js index 32a9eda7..ba6e77d8 100644 --- a/test/TestStakingPool.js +++ b/test/TestStakingPool.js @@ -299,7 +299,9 @@ contract('StakingPool', function(accounts) { await expectEVMError(stakingPool.leave(parseADX('10000'), false), 'INSUFFICIENT_SHARES') - const receipt = await (await stakingPool.leave(sharesToMint, false, { gasLimit: 150000 })).wait() + const receipt = await (await stakingPool.leave(sharesToMint, false, { + gasLimit: 150000 + })).wait() const currentBlockTimestamp = (await web3.eth.getBlock('latest')).timestamp assert.equal(receipt.events.length, 2, 'should emit LogLeave event') diff --git a/truffle-config.js b/truffle-config.js index eddecbad..06f954fa 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -30,17 +30,20 @@ const HDWalletProvider = require('@truffle/hdwallet-provider') const fs = require('fs') + let mnemonicOrKeys try { - mnemonicOrKeys = fs.readFileSync('.deployKey').toString().trim() + mnemonicOrKeys = fs + .readFileSync('.deployKey') + .toString() + .trim() if (mnemonicOrKeys.length === 64) mnemonicOrKeys = [mnemonicOrKeys] // causes stuff to blow up cause we don't catch the errors from the provider - //console.log('Deploy addr:', (new HDWalletProvider(mnemonicOrKeys, 'wss://matic-mainnet-archive-ws.bwarelabs.com')).addresses[0]) -} catch(e) { + // console.log('Deploy addr:', (new HDWalletProvider(mnemonicOrKeys, 'wss://matic-mainnet-archive-ws.bwarelabs.com')).addresses[0]) +} catch (e) { console.error('WARNING: unable to read .deploykey, mainnet wont work', e) } - module.exports = { /** * Networks define how you connect to your ethereum client and let you set the @@ -101,30 +104,42 @@ module.exports = { }, mainnet: { - provider: () => new HDWalletProvider(mnemonicOrKeys, 'wss://mainnet.infura.io/ws/v3/3d22938fd7dd41b7af4197752f83e8a1'), + provider: () => + new HDWalletProvider( + mnemonicOrKeys, + 'wss://mainnet.infura.io/ws/v3/3d22938fd7dd41b7af4197752f83e8a1' + ), network_id: 1, gasPrice: 95e9, // in gwei - gasLimit: 2000000, + gasLimit: 2000000 }, goerli: { - provider: () => new HDWalletProvider(mnemonicOrKeys, 'wss://goerli.infura.io/ws/v3/3d22938fd7dd41b7af4197752f83e8a1'), + provider: () => + new HDWalletProvider( + mnemonicOrKeys, + 'wss://goerli.infura.io/ws/v3/3d22938fd7dd41b7af4197752f83e8a1' + ), network_id: 5, - gasPrice: 5e9, + gasPrice: 5e9 }, polygon: { - provider: () => new HDWalletProvider(mnemonicOrKeys, 'https://rpc-mainnet.maticvigil.com/v1/a5ab110a213caf96d58376b2ab55f37e9b61eb64'), + provider: () => + new HDWalletProvider( + mnemonicOrKeys, + 'https://rpc-mainnet.maticvigil.com/v1/a5ab110a213caf96d58376b2ab55f37e9b61eb64' + ), network_id: 137, gasLimit: 2000000, - gasPrice: 110e9, + gasPrice: 110e9 }, bsc: { provider: () => new HDWalletProvider(mnemonicOrKeys, 'https://bsc-dataseed1.binance.org'), network_id: 56, - gasPrice: 5e9, - }, + gasPrice: 5e9 + } }, // Set default mocha options here, use special reporters etc.