Merge pull request #2562 from ethereum/receiveF

Receive bug and more tests
pull/5370/head
yann300 5 years ago committed by GitHub
commit 5de17f6f0a
  1. 37
      src/app/ui/universal-dapp-ui.js
  2. 5
      src/lib/helper.js
  3. 92
      test-browser/tests/specialFunctions.js

@ -133,7 +133,7 @@ UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address
<label class="pt-2 border-top d-flex justify-content-start flex-grow-1"> <label class="pt-2 border-top d-flex justify-content-start flex-grow-1">
Low level interactions with contract Low level interactions with contract
</label> </label>
<a href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function" class="" title="the link to documentation" target="_blank"> <a href="https://solidity.readthedocs.io/en/v0.6.2/contracts.html#receive-ether-function" title="the link to documentation" target="_blank">
<i aria-hidden="true" class="fas fa-info text-info my-2 mr-2"></i> <i aria-hidden="true" class="fas fa-info text-info my-2 mr-2"></i>
</a> </a>
</div> </div>
@ -151,42 +151,55 @@ UniversalDAppUI.prototype.renderInstanceFromABI = function (contractABI, address
` `
function sendData () { function sendData () {
let error = false
function setLLIError (text) { function setLLIError (text) {
llIError.innerText = text llIError.innerText = text
if (text !== '') error = true
} }
setLLIError('') setLLIError('')
const fallback = self.udapp.getFallbackInterface(contractABI) const fallback = self.udapp.getFallbackInterface(contractABI)
const receive = self.udapp.getReceiveInterface(contractABI) const receive = self.udapp.getReceiveInterface(contractABI)
const args = { const args = {
funABI: fallback, funABI: fallback || receive,
address: address, address: address,
contractName: contractName, contractName: contractName,
contractABI: contractABI contractABI: contractABI
} }
let calldata = calldataInput.value
const amount = document.querySelector('#value').value const amount = document.querySelector('#value').value
if (amount !== '0') { if (amount !== '0') {
// check for numeric and receive/fallback // check for numeric and receive/fallback
if (!helper.isNumeric(amount)) { if (!helper.isNumeric(amount)) {
setLLIError('Value to send should be a number') return setLLIError('Value to send should be a number')
} else if (!receive && !(fallback && fallback.stateMutability === 'payable')) { } else if (!receive && !(fallback && fallback.stateMutability === 'payable')) {
setLLIError("In order to receive Ether transfer the contract should have either 'receive' or payable 'fallback' function") return setLLIError("In order to receive Ether transfer the contract should have either 'receive' or payable 'fallback' function")
} }
} }
let calldata = calldataInput.value
if (calldata) { if (calldata) {
if (calldata.length > 3 && calldata.substr(0, 2) === '0x') { if (calldata.length < 2 || calldata.length < 4 && helper.is0XPrefixed(calldata)) {
if (!helper.isHexadecimal(calldata.substr(2, calldata.length))) { return setLLIError('the calldata should be a valid hexadecimal value with size of at least one byte.')
setLLIError('the calldata should be a valid hexadecimal value.') } else {
if (helper.is0XPrefixed(calldata)) {
calldata = calldata.substr(2, calldata.length)
}
if (!helper.isHexadecimal(calldata)) {
return setLLIError('the calldata should be a valid hexadecimal value with size of at least one byte.')
} }
} }
if (!fallback) { if (!fallback) {
setLLIError("'fallback' function is not defined") return setLLIError("'Fallback' function is not defined")
} }
} }
if ((calldata || amount !== '0') && !error) self.runTransaction(false, args, null, calldata, null)
if (!receive && !fallback) return setLLIError(`Both 'receive' and 'fallback' functions are not defined`)
// we have to put the right function ABI:
// if receive is defined and that there is no calldata => receive function is called
// if fallback is defined => fallback function is called
if (receive && !calldata) args.funABI = receive
else if (fallback) args.funABI = fallback
if (!args.funABI) return setLLIError(`Please define a 'Fallback' function to send calldata and a either 'Receive' or payable 'Fallback' to send ethers`)
self.runTransaction(false, args, null, calldataInput.value, null)
} }
contractActionsWrapper.appendChild(lowLevelInteracions) contractActionsWrapper.appendChild(lowLevelInteracions)

@ -45,7 +45,10 @@ module.exports = {
return name.match(/[:*?"<>\\'|]/) != null return name.match(/[:*?"<>\\'|]/) != null
}, },
isHexadecimal (value) { isHexadecimal (value) {
return /^[0-9a-fA-F]+$/.test(value) return /^[0-9a-fA-F]+$/.test(value) && (value.length % 2 === 0)
},
is0XPrefixed (value) {
return value.substr(0, 2) === '0x'
}, },
isNumeric (value) { isNumeric (value) {
return /^\+?(0|[1-9]\d*)$/.test(value) return /^\+?(0|[1-9]\d*)$/.test(value)

@ -2,15 +2,6 @@
var init = require('../helpers/init') var init = require('../helpers/init')
var sauce = require('./sauce') var sauce = require('./sauce')
/**
* both are declared, sending data
* both are declared - receive called, sending wei
* both are declared - fallback should fail cause not payable, sending data and wei
* receive is declared, failing, fallback is not declared, sending data
* receive is not declared, fallback is payable, sending wei
* receive is not declared, fallback is payable, sending data and wei
* both are not declared, sending data and wei, should fail
*/
module.exports = { module.exports = {
before: function (browser, done) { before: function (browser, done) {
init(browser, done) init(browser, done)
@ -36,7 +27,19 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/follback - both are declared - receive called, sending wei': function (browser) { 'Use special functions receive/fallback - both are declared, failing sending data < 1 byte': function (browser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => {
browser.sendLowLevelTx(address, '0', '0xa')
.pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)
.assert.containsText(`#instance${address} label[id="deployAndRunLLTxError"]`, `the calldata should be a valid hexadecimal value with size of at least one byte.`)
.perform(done)
})
})
},
'Use special functions receive/fallback - both are declared - receive called, sending wei': function (browser) {
// don't need to redeploy it, same contract // don't need to redeploy it, same contract
browser.perform((done) => { browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => { browser.getAddressAtPosition(0, (address) => {
@ -49,7 +52,7 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/follback - both are declared - fallback should fail cause not payable, sending data and wei': function (browser) { 'Use special functions receive/fallback - both are declared - fallback should fail cause not payable, sending data and wei': function (browser) {
// don't need to redeploy it, same contract // don't need to redeploy it, same contract
browser.perform((done) => { browser.perform((done) => {
browser.getAddressAtPosition(0, (address) => { browser.getAddressAtPosition(0, (address) => {
@ -61,7 +64,7 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/follback - receive is declared, failing, fallback is not declared, sending data': function (browser) { 'Use special functions receive/fallback - only receive is declared, sending wei': function (browser) {
browser.waitForElementVisible('#icon-panel', 10000) browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('receiveOnly.sol', sources[1]['browser/receiveOnly.sol'], ['CheckSpecials']) .testContracts('receiveOnly.sol', sources[1]['browser/receiveOnly.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
@ -69,16 +72,29 @@ module.exports = {
.createContract('') .createContract('')
.clickInstance(1) .clickInstance(1)
.perform((done) => { .perform((done) => {
browser.getAddressAtPosition(1, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.journalLastChildIncludes('to:CheckSpecials.(receive)')
.journalLastChildIncludes('value:1 wei')
.journalLastChildIncludes('data:0x')
.perform(done)
})
})
},
'Use special functions receive/fallback - only receive is declared, failing, fallback is not declared, sending data': function (browser) {
// don't need to redeploy it, same contract
browser.perform((done) => {
browser.getAddressAtPosition(1, (address) => { browser.getAddressAtPosition(1, (address) => {
browser.sendLowLevelTx(address, '0', '0xaa') browser.sendLowLevelTx(address, '0', '0xaa')
.pause(1000) .pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`) .waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)
.assert.containsText(`#instance${address} label[id="deployAndRunLLTxError"]`, `'fallback' function is not defined`) .assert.containsText(`#instance${address} label[id="deployAndRunLLTxError"]`, `'Fallback' function is not defined`)
.perform(done) .perform(done)
}) })
}) })
}, },
'Use special functions receive/fallback - receive is not declared, fallback is payable, sending wei': function (browser) { 'Use special functions receive/fallback - only fallback declared and is payable, sending wei': function (browser) {
browser.waitForElementVisible('#icon-panel', 10000) browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('fallbackOnlyPayable.sol', sources[2]['browser/fallbackOnlyPayable.sol'], ['CheckSpecials']) .testContracts('fallbackOnlyPayable.sol', sources[2]['browser/fallbackOnlyPayable.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
@ -96,7 +112,7 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/follback - receive is not declared, fallback is payable, sending data and wei': function (browser) { 'Use special functions receive/fallback - only fallback is diclared and is payable, sending data and wei': function (browser) {
// don't need to redeploy it, same contract // don't need to redeploy it, same contract
browser.perform((done) => { browser.perform((done) => {
browser.getAddressAtPosition(2, (address) => { browser.getAddressAtPosition(2, (address) => {
@ -109,7 +125,7 @@ module.exports = {
}) })
}) })
}, },
'Use special functions receive/fallback - receive is not declared, fallback should fail cause not payable, sending wei': function (browser) { 'Use special functions receive/fallback - only fallback is declared, fallback should fail cause not payable, sending wei': function (browser) {
browser.waitForElementVisible('#icon-panel', 10000) browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('fallbackOnlyNotPayable.sol', sources[3]['browser/fallbackOnlyNotPayable.sol'], ['CheckSpecials']) .testContracts('fallbackOnlyNotPayable.sol', sources[3]['browser/fallbackOnlyNotPayable.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
@ -136,7 +152,7 @@ module.exports = {
.setValue('#value', 0) .setValue('#value', 0)
.createContract('') .createContract('')
.clickInstance(4) .clickInstance(4)
.pause(10000) .pause(1000)
.perform((done) => { .perform((done) => {
browser.getAddressAtPosition(4, (address) => { browser.getAddressAtPosition(4, (address) => {
browser.sendLowLevelTx(address, '1', '0xaa') browser.sendLowLevelTx(address, '1', '0xaa')
@ -147,6 +163,39 @@ module.exports = {
.perform(done) .perform(done)
}) })
}) })
},
'Use special functions receive/fallback - receive and fallback are declared and payable, sending wei': function (browser) {
browser.perform((done) => {
browser.getAddressAtPosition(4, (address) => {
browser.sendLowLevelTx(address, '1', '')
.pause(1000)
.journalLastChildIncludes('to:CheckSpecials.(receive)')
.journalLastChildIncludes('value:1 wei')
.journalLastChildIncludes('data:0x')
.perform(done)
})
})
},
'Use special functions receive/fallback - receive and fallback are not declared, sending nothing': function (browser) {
browser.waitForElementVisible('#icon-panel', 10000)
.testContracts('notSpecial.sol', sources[5]['browser/notSpecial.sol'], ['CheckSpecials'])
.clickLaunchIcon('udapp')
.selectContract('CheckSpecials')
.waitForElementVisible('#value')
.clearValue('#value')
.setValue('#value', 0)
.createContract('')
.clickInstance(5)
.pause(1000)
.perform((done) => {
browser.getAddressAtPosition(5, (address) => {
browser.sendLowLevelTx(address, '0', '')
.pause(1000)
.waitForElementVisible(`#instance${address} label[id="deployAndRunLLTxError"]`)
.assert.containsText(`#instance${address} label[id="deployAndRunLLTxError"]`, `Both 'receive' and 'fallback' functions are not defined`)
.perform(done)
})
})
.end() .end()
}, },
tearDown: sauce tearDown: sauce
@ -199,5 +248,14 @@ var sources = [
} }
` `
} }
},
{
'browser/notSpecial.sol': {
content: `
contract CheckSpecials {
function otherFallback() payable external {}
}
`
}
} }
] ]

Loading…
Cancel
Save