fix: reduce escrow creation gas cost by 50K (#390)
* fix: reduce createTransaction gas cost * fix: reducing arbitrable gas cost * fix: reducing gas cost of calling MetadataStore from escrow
This commit is contained in:
parent
e81e0fa662
commit
bbaa9b613a
|
@ -47,7 +47,7 @@ contract Arbitrable {
|
|||
* @notice Get arbitrator of an escrow
|
||||
* @return address Arbitrator address
|
||||
*/
|
||||
function getArbitrator(uint _escrowId) public view returns(address);
|
||||
function _getArbitrator(uint _escrowId) internal view returns(address);
|
||||
|
||||
/**
|
||||
* @notice Determine if a dispute exists/existed for an escrow
|
||||
|
@ -55,6 +55,10 @@ contract Arbitrable {
|
|||
* @return bool result
|
||||
*/
|
||||
function isDisputed(uint _escrowId) public view returns (bool) {
|
||||
return _isDisputed(_escrowId);
|
||||
}
|
||||
|
||||
function _isDisputed(uint _escrowId) internal view returns (bool) {
|
||||
return arbitrationCases[_escrowId].open || arbitrationCases[_escrowId].result != ArbitrationResult.UNSOLVED;
|
||||
}
|
||||
|
||||
|
@ -91,7 +95,7 @@ contract Arbitrable {
|
|||
require(arbitrationCases[_escrowId].result == ArbitrationResult.UNSOLVED && !arbitrationCases[_escrowId].open,
|
||||
"Arbitration already solved or has been opened before");
|
||||
|
||||
address arbitratorAddress = getArbitrator(_escrowId);
|
||||
address arbitratorAddress = _getArbitrator(_escrowId);
|
||||
|
||||
require(arbitratorAddress != address(0), "Arbitrator is required");
|
||||
|
||||
|
|
|
@ -140,19 +140,20 @@ contract Escrow is IEscrow, Pausable, MessageSigned, Fees, Arbitrable {
|
|||
require(!deleted, "Offer is not valid");
|
||||
require(sellerLicenses.isLicenseOwner(seller), "Must be a valid seller to create escrow transactions");
|
||||
require(seller != _buyer, "Seller and Buyer must be different");
|
||||
require(arbitrator != _buyer, "Cannot buy offers where buyer is arbitrator");
|
||||
require(arbitrator != _buyer && arbitrator != address(0), "Cannot buy offers where buyer is arbitrator");
|
||||
require(_tokenAmount != 0 && _assetPrice != 0, "Trade amounts cannot be 0");
|
||||
require(arbitrator != address(0), "Arbitrator is required");
|
||||
|
||||
escrowId = transactions.length++;
|
||||
|
||||
transactions[escrowId].offerId = _offerId;
|
||||
transactions[escrowId].token = token;
|
||||
transactions[escrowId].buyer = _buyer;
|
||||
transactions[escrowId].seller = seller;
|
||||
transactions[escrowId].arbitrator = arbitrator;
|
||||
transactions[escrowId].tokenAmount = _tokenAmount;
|
||||
transactions[escrowId].assetPrice = _assetPrice;
|
||||
EscrowTransaction storage trx = transactions[escrowId];
|
||||
|
||||
trx.offerId = _offerId;
|
||||
trx.token = token;
|
||||
trx.buyer = _buyer;
|
||||
trx.seller = seller;
|
||||
trx.arbitrator = arbitrator;
|
||||
trx.tokenAmount = _tokenAmount;
|
||||
trx.assetPrice = _assetPrice;
|
||||
|
||||
emit Created(_offerId, seller, _buyer, escrowId);
|
||||
}
|
||||
|
@ -349,7 +350,7 @@ contract Escrow is IEscrow, Pausable, MessageSigned, Fees, Arbitrable {
|
|||
EscrowStatus mStatus = transactions[_escrowId].status;
|
||||
require(transactions[_escrowId].seller == msg.sender, "Only the seller can invoke this function");
|
||||
require(mStatus == EscrowStatus.PAID || mStatus == EscrowStatus.FUNDED, "Invalid transaction status");
|
||||
require(!isDisputed(_escrowId), "Can't release a transaction that has an arbitration process");
|
||||
require(!_isDisputed(_escrowId), "Can't release a transaction that has an arbitration process");
|
||||
_release(_escrowId, transactions[_escrowId], false);
|
||||
}
|
||||
|
||||
|
@ -531,7 +532,7 @@ contract Escrow is IEscrow, Pausable, MessageSigned, Fees, Arbitrable {
|
|||
* @param _escrowId Id of the escrow
|
||||
* @return Arbitrator address
|
||||
*/
|
||||
function getArbitrator(uint _escrowId) public view returns(address) {
|
||||
function _getArbitrator(uint _escrowId) internal view returns(address) {
|
||||
return transactions[_escrowId].arbitrator;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@ contract IEscrow {
|
|||
uint256 expirationTime;
|
||||
uint256 rating;
|
||||
uint256 assetPrice;
|
||||
EscrowStatus status;
|
||||
address payable buyer;
|
||||
address payable seller;
|
||||
address payable arbitrator;
|
||||
EscrowStatus status;
|
||||
}
|
||||
|
||||
function createEscrow(
|
||||
|
|
|
@ -32,9 +32,7 @@ contract MetadataStore is MessageSigned {
|
|||
License public sellingLicenses;
|
||||
ArbitrationLicense public arbitrationLicenses;
|
||||
|
||||
User[] public users;
|
||||
mapping(address => bool) public userWhitelist;
|
||||
mapping(address => uint256) public addressToUser;
|
||||
mapping(address => User) public users;
|
||||
mapping(address => uint) public user_nonce;
|
||||
|
||||
Offer[] public offers;
|
||||
|
@ -57,8 +55,6 @@ contract MetadataStore is MessageSigned {
|
|||
|
||||
event OfferRemoved(address owner, uint256 offerId);
|
||||
|
||||
event UserUpdated(address owner, bytes statusContactCode, string location, string username);
|
||||
|
||||
/**
|
||||
* @param _sellingLicenses Sellers licenses contract address
|
||||
* @param _arbitrationLicenses Arbitrators licenses contract address
|
||||
|
@ -82,8 +78,6 @@ contract MetadataStore is MessageSigned {
|
|||
|
||||
sellingLicenses = License(_sellingLicenses);
|
||||
arbitrationLicenses = ArbitrationLicense(_arbitrationLicenses);
|
||||
|
||||
users.length++;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,17 +149,10 @@ contract MetadataStore is MessageSigned {
|
|||
string memory _location,
|
||||
string memory _username
|
||||
) internal {
|
||||
if (!userWhitelist[_user]) {
|
||||
User memory user = User(_statusContactCode, _location, _username);
|
||||
uint256 userId = users.push(user) - 1;
|
||||
addressToUser[_user] = userId;
|
||||
userWhitelist[_user] = true;
|
||||
} else {
|
||||
User storage tmpUser = users[addressToUser[_user]];
|
||||
tmpUser.statusContactCode = _statusContactCode;
|
||||
tmpUser.location = _location;
|
||||
tmpUser.username = _username;
|
||||
}
|
||||
User storage u = users[_user];
|
||||
u.statusContactCode = _statusContactCode;
|
||||
u.location = _location;
|
||||
u.username = _username;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -247,30 +234,12 @@ contract MetadataStore is MessageSigned {
|
|||
emit OfferAdded(msg.sender, offerId, _asset, _statusContactCode, _location, _currency, _username, _paymentMethods, _margin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Update the user information
|
||||
* @param _statusContactCode Status contact code
|
||||
* @param _location Location on earth
|
||||
* @param _username Username of the user
|
||||
*/
|
||||
function updateUser(bytes calldata _statusContactCode, string calldata _location, string calldata _username) external {
|
||||
require(userWhitelist[msg.sender], "User does not exist");
|
||||
|
||||
User storage tmpUser = users[addressToUser[msg.sender]];
|
||||
tmpUser.statusContactCode = _statusContactCode;
|
||||
tmpUser.location = _location;
|
||||
tmpUser.username = _username;
|
||||
|
||||
emit UserUpdated(msg.sender, _statusContactCode, _location, _username);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Remove user offer
|
||||
* @dev Removed offers are marked as deleted instead of being deleted
|
||||
* @param _offerId Id of the offer to remove
|
||||
*/
|
||||
function removeOffer(uint256 _offerId) external {
|
||||
require(userWhitelist[msg.sender], "User does not exist");
|
||||
require(offerWhitelist[msg.sender][_offerId], "Offer does not exist");
|
||||
|
||||
offers[_offerId].deleted = true;
|
||||
|
@ -293,20 +262,22 @@ contract MetadataStore is MessageSigned {
|
|||
address payable arbitrator,
|
||||
bool deleted
|
||||
) {
|
||||
Offer memory theOffer = offers[_id];
|
||||
|
||||
// In case arbitrator rejects the seller
|
||||
address payable offerArbitrator = offers[_id].arbitrator;
|
||||
if(!arbitrationLicenses.isAllowed(offers[_id].owner, offerArbitrator)){
|
||||
address payable offerArbitrator = theOffer.arbitrator;
|
||||
if(!arbitrationLicenses.isAllowed(theOffer.owner, offerArbitrator)){
|
||||
offerArbitrator = address(0);
|
||||
}
|
||||
|
||||
return (
|
||||
offers[_id].asset,
|
||||
offers[_id].currency,
|
||||
offers[_id].margin,
|
||||
offers[_id].paymentMethods,
|
||||
offers[_id].owner,
|
||||
theOffer.asset,
|
||||
theOffer.currency,
|
||||
theOffer.margin,
|
||||
theOffer.paymentMethods,
|
||||
theOffer.owner,
|
||||
offerArbitrator,
|
||||
offers[_id].deleted
|
||||
theOffer.deleted
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -340,14 +311,6 @@ contract MetadataStore is MessageSigned {
|
|||
return (offers[_id].arbitrator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the size of the users
|
||||
* @return Number of users stored in the contract
|
||||
*/
|
||||
function usersSize() external view returns (uint256) {
|
||||
return users.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Get the size of the offers
|
||||
* @return Number of offers stored in the contract
|
||||
|
|
|
@ -172,10 +172,8 @@ export function *doLoadEscrows({address}) {
|
|||
const escrow = yield Escrow.methods.transactions(ev.returnValues.escrowId).call();
|
||||
escrow.escrowId = ev.returnValues.escrowId;
|
||||
escrow.offer = yield MetadataStore.methods.offer(escrow.offerId).call();
|
||||
const sellerId = yield MetadataStore.methods.addressToUser(escrow.offer.owner).call();
|
||||
escrow.seller = yield MetadataStore.methods.users(sellerId).call();
|
||||
const buyerId = yield MetadataStore.methods.addressToUser(escrow.buyer).call();
|
||||
escrow.buyerInfo = yield MetadataStore.methods.users(buyerId).call();
|
||||
escrow.seller = yield MetadataStore.methods.users(escrow.offer.owner).call();
|
||||
escrow.buyerInfo = yield MetadataStore.methods.users(escrow.buyer).call();
|
||||
return escrow;
|
||||
}));
|
||||
|
||||
|
@ -195,12 +193,9 @@ export function *doGetEscrow({escrowId}) {
|
|||
const escrow = yield Escrow.methods.transactions(escrowId).call();
|
||||
escrow.escrowId = escrowId;
|
||||
escrow.offer = yield MetadataStore.methods.offer(escrow.offerId).call();
|
||||
const sellerId = yield MetadataStore.methods.addressToUser(escrow.offer.owner).call();
|
||||
escrow.seller = yield MetadataStore.methods.users(sellerId).call();
|
||||
const buyerId = yield MetadataStore.methods.addressToUser(escrow.buyer).call();
|
||||
escrow.buyerInfo = yield MetadataStore.methods.users(buyerId).call();
|
||||
const arbitratorId = yield MetadataStore.methods.addressToUser(escrow.arbitrator).call();
|
||||
escrow.arbitratorInfo = yield MetadataStore.methods.users(arbitratorId).call();
|
||||
escrow.seller = yield MetadataStore.methods.users(escrow.offer.owner).call();
|
||||
escrow.buyerInfo = yield MetadataStore.methods.users(escrow.buyer).call();
|
||||
escrow.arbitratorInfo = yield MetadataStore.methods.users(escrow.arbitrator).call();
|
||||
yield put({type: GET_ESCROW_SUCCEEDED, escrow, escrowId});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
|
|
@ -30,22 +30,20 @@ export function *loadUser({address}) {
|
|||
try {
|
||||
const isArbitrator = yield ArbitrationLicense.methods.isLicenseOwner(address).call();
|
||||
const isSeller = yield SellerLicense.methods.isLicenseOwner(address).call();
|
||||
const isUser = yield MetadataStore.methods.userWhitelist(address).call();
|
||||
|
||||
let user = {
|
||||
let userLicenses = {
|
||||
isArbitrator,
|
||||
isSeller
|
||||
};
|
||||
|
||||
if (!isUser){
|
||||
const user = Object.assign(userLicenses, yield MetadataStore.methods.users(address).call());
|
||||
if(!user.statusContactCode){
|
||||
if(isArbitrator || isSeller) {
|
||||
yield put({type: LOAD_USER_SUCCEEDED, user, address});
|
||||
yield put({type: LOAD_USER_SUCCEEDED, user: userLicenses, address});
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
const id = yield MetadataStore.methods.addressToUser(address).call();
|
||||
user = Object.assign(user, yield MetadataStore.methods.users(id).call());
|
||||
|
||||
if (user.location) {
|
||||
yield put({type: LOAD_USER_LOCATION, user, address});
|
||||
|
@ -100,8 +98,7 @@ export function *loadOffers({address}) {
|
|||
const offer = yield MetadataStore.methods.offer(id).call();
|
||||
|
||||
if(!addressCompare(offer.arbitrator, zeroAddress)){
|
||||
const id = yield MetadataStore.methods.addressToUser(offer.arbitrator).call();
|
||||
offer.arbitratorData = yield MetadataStore.methods.users(id).call();
|
||||
offer.arbitratorData = yield MetadataStore.methods.users(offer.arbitrator).call();
|
||||
}
|
||||
|
||||
if (!loadedUsers.includes(offer.owner)) {
|
||||
|
|
|
@ -73,10 +73,10 @@ contract("MetadataStore", function () {
|
|||
|
||||
it("should not allow to add new user when not license owner", async function () {
|
||||
try {
|
||||
await MetadataStore.methods.addOffer(SNT.address, signature, SellerLicense.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
||||
} catch(error) {
|
||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||
assert.strictEqual(usersSize, '1');
|
||||
await MetadataStore.methods.addOffer(SNT.address, SellerLicense.address, "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
||||
assert.fail('should have reverted before');
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Not a license owner");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -84,34 +84,35 @@ contract("MetadataStore", function () {
|
|||
const encodedCall = SellerLicense.methods.buy().encodeABI();
|
||||
await SNT.methods.approveAndCall(SellerLicense.options.address, 10, encodedCall).send();
|
||||
const receipt = await MetadataStore.methods.addOffer(SNT.address, "0x00", "London", "USD", "Iuri", [0], 1, accounts[9]).send();
|
||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||
assert.strictEqual(usersSize, '2');
|
||||
|
||||
const offersSize = await MetadataStore.methods.offersSize().call();
|
||||
assert.strictEqual(offersSize, '1');
|
||||
|
||||
const userInfo = await MetadataStore.methods.users(accounts[0]).call();
|
||||
assert.strictEqual(userInfo.username, "Iuri");
|
||||
});
|
||||
|
||||
it("should allow to add new offer only when already a user", async function () {
|
||||
await MetadataStore.methods.addOffer(SNT.address, "0x00", "London", "EUR", "Iuri", [0], 1, accounts[9]).send();
|
||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||
assert.strictEqual(usersSize, '2');
|
||||
const offersSize = await MetadataStore.methods.offersSize().call();
|
||||
assert.strictEqual(offersSize, '2');
|
||||
|
||||
const offerIds = await MetadataStore.methods.getOfferIds(accounts[0]).call();
|
||||
assert.strictEqual(offerIds.length, 2);
|
||||
});
|
||||
|
||||
it("should not allow to add new offer when margin is more than 100", async function () {
|
||||
try {
|
||||
await MetadataStore.methods.addOffer(SNT.address, "0x00", "London", "USD", "Iuri", [0], 101, accounts[9]).send();
|
||||
} catch(error) {
|
||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||
assert.strictEqual(usersSize, '2');
|
||||
assert.fail('should have reverted before');
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, "VM Exception while processing transaction: revert Margin too high");
|
||||
}
|
||||
});
|
||||
|
||||
it("should allow to update a user", async function () {
|
||||
await MetadataStore.methods.updateUser(SNT.address, "Montreal", "Anthony").send();
|
||||
const usersSize = await MetadataStore.methods.usersSize().call();
|
||||
assert.strictEqual(usersSize, '2');
|
||||
const user = await MetadataStore.methods.users(1).call();
|
||||
await MetadataStore.methods.addOrUpdateUser(SNT.address, "Montreal", "Anthony").send();
|
||||
const user = await MetadataStore.methods.users(accounts[0]).call();
|
||||
assert.strictEqual(user.location, 'Montreal');
|
||||
assert.strictEqual(user.username, 'Anthony');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue