diff --git a/contracts/ExtendedJurisdiction.sol b/contracts/ExtendedJurisdiction.sol index cc58c21..46ad732 100644 --- a/contracts/ExtendedJurisdiction.sol +++ b/contracts/ExtendedJurisdiction.sol @@ -690,30 +690,29 @@ contract ExtendedJurisdiction is Ownable, Pausable, AttributeRegistryInterface, _recoverableFunds = _recoverableFunds.add(stake.sub(transactionCost)); } + // emit an event for the payment of the transaction rebate + emit TransactionRebatePaid( + tx.origin, + refundAddress, + attributeTypeID, + transactionCost + ); + // refund the cost of the transaction to the trasaction submitter - if (tx.origin.send(transactionCost)) { - emit TransactionRebatePaid( - tx.origin, - refundAddress, - attributeTypeID, - transactionCost - ); - } else { - _recoverableFunds = _recoverableFunds.add(transactionCost); - } + tx.origin.transfer(transactionCost); // otherwise, allocate entire stake to partially refunding the transaction - } else if (stake > 0 && address(this).balance >= stake) { - if (tx.origin.send(stake)) { - emit TransactionRebatePaid( - tx.origin, - refundAddress, - attributeTypeID, - stake - ); - } else { - _recoverableFunds = _recoverableFunds.add(stake); - } + } else { + // emit an event for the payment of the partial transaction rebate + emit TransactionRebatePaid( + tx.origin, + refundAddress, + attributeTypeID, + stake + ); + + // refund the partial cost of the transaction to trasaction submitter + tx.origin.transfer(stake); } } } diff --git a/contracts/mock/test/PaymentRejector.sol b/contracts/mock/test/PaymentRejector.sol index e176cf0..acceffa 100644 --- a/contracts/mock/test/PaymentRejector.sol +++ b/contracts/mock/test/PaymentRejector.sol @@ -20,4 +20,30 @@ contract PaymentRejector { function setValidatorSigningKey(address newKey) public { _jurisdiction.setValidatorSigningKey(newKey); } + + function addAttributeFor( + address account, + uint256 attributeTypeID, + uint256 value, + uint256 validatorFee, + bytes signature + ) public payable { + _jurisdiction.addAttributeFor.value(msg.value)( + account, + attributeTypeID, + value, + validatorFee, + signature + ); + } + + function removeAttributeFor( + address account, + uint256 attributeTypeID + ) public { + _jurisdiction.removeAttributeFor( + account, + attributeTypeID + ); + } } \ No newline at end of file diff --git a/scripts/test/testExtended.js b/scripts/test/testExtended.js index 0662408..4b59104 100644 --- a/scripts/test/testExtended.js +++ b/scripts/test/testExtended.js @@ -249,7 +249,19 @@ module.exports = {test: async function (provider, testingContext) { ) passed++ }) - + + await Jurisdiction.methods.recoverableTokens(TPLToken.options.address).call({ + from: address, + gas: 5000000, + gasPrice: 10 ** 1 + }).then(tokens => { + assert.strictEqual(tokens, '0') + console.log( + ' ✓ - recoverable token balance of registry is initially zero' + ) + passed++ + }) + await TPLToken.methods.balanceOf(address).call({ from: address, gas: 5000000, @@ -271,6 +283,21 @@ module.exports = {test: async function (provider, testingContext) { passed++ }) + await Jurisdiction.methods.recoverTokens( + TPLToken.options.address, + inattributedAddress, + 0 + ).call({ + from: address, + gas: 5000000, + gasPrice: 10 ** 1 + }).catch(error => { + console.log( + ' ✓ - tokens cannot be recovered before attribute is assigned' + ) + passed++ + }) + // create stub objects that will be used for setting and comparing values const validator = { address: validatorAddress, @@ -891,6 +918,21 @@ module.exports = {test: async function (provider, testingContext) { failed++ }) + await Jurisdiction.methods.recoverTokens( + TPLToken.options.address, + attributedAddress, + 0 + ).call({ + from: address, + gas: 5000000, + gasPrice: 10 ** 1 + }).then(receipt => { + console.log( + ' ✓ - tokens can be "recovered" once attribute is assigned' + ) + passed++ + }) + await Jurisdiction.methods.issueAttribute( attributedAddress, attribute.attributeId, diff --git a/scripts/test/testExtendedPayments.js b/scripts/test/testExtendedPayments.js index 1897a5f..3bfbae2 100644 --- a/scripts/test/testExtendedPayments.js +++ b/scripts/test/testExtendedPayments.js @@ -33,7 +33,7 @@ module.exports = {test: async function (provider, testingContext) { from: from, value: value, gas: gas, - gasPrice:gasPrice + gasPrice: gasPrice }).catch(error => { succeeded = false }) @@ -818,7 +818,7 @@ module.exports = {test: async function (provider, testingContext) { attributeValue ) await runTest( - 'operators can issue signed attribute that requires a stake', + 'operators can issue signed attribute that requires a stake (1)', Jurisdiction, 'addAttributeFor', 'send', @@ -856,6 +856,194 @@ module.exports = {test: async function (provider, testingContext) { minimumRequiredStake ) + await runTest( + 'jurisdiction owner can then revoke the attribute (2)', + Jurisdiction, + 'revokeAttribute', + 'send', + [attributedAddress, attributeId] + ) + + signature = await signValidation( + validatorAddress, + Jurisdiction.options.address, + attributedAddress, + attributedAddress, // operator + minimumRequiredStake + 1, // stake + jurisdiction fee + validator fee + 0, + attributeId, + attributeValue + ) + await runTest( + 'operators can issue signed attribute that requires a stake (2)', + Jurisdiction, + 'addAttributeFor', + 'send', + [ + attributedAddress, + attributeId, + attributeValue, + 0, + signature + ], + true, + value => { + assert.strictEqual( + value.events.StakeAllocated.returnValues.staker, + attributedAddress + ) + assert.strictEqual( + value.events.AttributeAdded.returnValues.validator, + validatorAddress + ) + assert.strictEqual( + value.events.AttributeAdded.returnValues.attributee, + attributedAddress + ) + assert.strictEqual( + value.events.AttributeAdded.returnValues.attributeTypeID, + attributeId.toString() + ) + assert.strictEqual( + value.events.AttributeAdded.returnValues.attributeValue, + attributeValue.toString() + ) + }, + attributedAddress, + minimumRequiredStake + 1 + ) + + await runTest( + 'attribute operator can revoke the attribute (1)', + Jurisdiction, + 'removeAttributeFor', + 'send', + [attributedAddress, attributeId], + true, + value => { + assert.strictEqual( + value.events.AttributeRemoved.returnValues.attributeTypeID, + attributeId.toString() + ) + }, + attributedAddress + ) + + signature = await signValidation( + validatorAddress, + Jurisdiction.options.address, + attributedAddress, + PaymentRejector.options.address, // operator + minimumRequiredStake, // stake + jurisdiction fee + validator fee + 0, + attributeId, + attributeValue + ) + await runTest( + 'operators can issue signed attribute that requires a stake (3)', + PaymentRejector, + 'addAttributeFor', + 'send', + [ + attributedAddress, + attributeId, + attributeValue, + 0, + signature + ], + true, + value => {}, + attributedAddress, + minimumRequiredStake + ) + + await runTest( + 'attribute operator can revoke the attribute (2)', + PaymentRejector, + 'removeAttributeFor', + 'send', + [attributedAddress, attributeId], + true, + value => {}, + attributedAddress + ) + + signature = await signValidation( + validatorAddress, + Jurisdiction.options.address, + attributedAddress, + PaymentRejector.options.address, // operator + minimumRequiredStake + 1, // stake + jurisdiction fee + validator fee + 0, + attributeId, + attributeValue + ) + await runTest( + 'operators can issue signed attribute that requires a stake (4)', + PaymentRejector, + 'addAttributeFor', + 'send', + [ + attributedAddress, + attributeId, + attributeValue, + 0, + signature + ], + true, + value => {}, + attributedAddress, + minimumRequiredStake + 1 + ) + + await runTest( + 'attribute holder can revoke the attribute (5)', + Jurisdiction, + 'removeAttribute', + 'send', + [attributeId], + true, + value => {}, + attributedAddress + ) + + // stake > tx rebate + signature = await signValidation( + validatorAddress, + Jurisdiction.options.address, + attributedAddress, + PaymentRejector.options.address, // operator + 377001, + 0, + attributeId, + attributeValue + ) + await runTest( + 'operators can issue signed attribute that requires a stake (5)', + PaymentRejector, + 'addAttributeFor', + 'send', + [ + attributedAddress, + attributeId, + attributeValue, + 0, + signature + ], + true, + value => {}, + attributedAddress, + 377001 + ) + + await runTest( + 'jurisdiction owner can then revoke the attribute (3)', + Jurisdiction, + 'revokeAttribute', + 'send', + [attributedAddress, attributeId] + ) + console.log( `completed ${passed + failed} tests with ${failed} ` + `failure${failed === 1 ? '' : 's'}.`