Skip to content
This repository has been archived by the owner on Jul 9, 2021. It is now read-only.

Implement MultiAssetProxy #1224

Merged
merged 10 commits into from
Nov 28, 2018
Merged

Conversation

abandeali1
Copy link
Member

@abandeali1 abandeali1 commented Nov 7, 2018

Description

Implements 0xProject/ZEIPs#23

TODO: add combinatorial tests
TODO: use custom ABI encoder and update assetDataUtils
TODO: determine if we can safely remove sanity checks

Testing instructions

Types of changes

Checklist:

  • Prefix PR title with [WIP] if necessary.
  • Prefix PR title with bracketed package name(s) corresponding to the changed package(s). For example: [sol-cov] Fixed bug.
  • Add tests to cover changes as needed.
  • Update documentation as needed.
  • Add new entries to the relevant CHANGELOG.jsons.

@coveralls
Copy link

coveralls commented Nov 7, 2018

Coverage Status

Coverage decreased (-0.009%) to 85.276% when pulling 708f4e9 on feature/contracts/multiAssetProxy into 47a87e5 on development.

Copy link
Contributor

@recmo recmo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All those nested offsets. Hurts my brain :)

How are we going to create confidence that this code is correct?


// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(0, and(caller, 0xffffffffffffffffffffffffffffffffffffffff))
Copy link
Contributor

@recmo recmo Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and is unnecessary, caller will already have the high bits set to zero.

}

// `transferFrom`.
// The function is marked `external`, so no abi decodeding is done for
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'decodeding' -> 'decoding'


// Load number of elements in `amounts`
// We must add 4 (function selector) + 128 (4 params * 32) + 32 (assetData len) + 4 (assetProxyId) + 32 (amounts len) to the amounts offset
let amountsContentsStart := add(amountsOffset, 200)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This takes into account the offset in the inner data (amountsOffset) but ignores the outer offset (assetDataOffset) and assumes it is always fixed (zero I assume).

We should take all offsets into account: add(assetDataOffset, add(amountsOffset, 4 + 4 + 32)).

I tried using absolute addresses for all offsets, it doesn't make the code much more readable.

let amountsLen := calldataload(sub(amountsContentsStart, 32))

// Load number of elements in `nestedAssetData`
let nestedAssetDataContentsStart := add(nestedAssetDataOffset, 200)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here : add(assetDataOffset, add(nestedAssetDataOffset, 4 + 4 + 32)).

mstore(64, 0x0000000f4c454e4754485f4d49534d4154434800000000000000000000000000)
mstore(96, 0)
revert(0, 100)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We assume without checking that the (nested) assetDatas are correctly formatted (follow ABI2 spec, no out of bounds errors, etc.). We don't check for that. We can similarly argue here that it is on the user to supply correct data. But I thing this check makes sense.

let nestedAssetDataElementOffset := calldataload(add(nestedAssetDataContentsStart, i))

// Load length of `nestedAssetData[i]`
let nestedAssetDataElementContentsStart := add(nestedAssetDataElementOffset, 264)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:= add(assetDataOffset, add(nestedAssetDataElementOffset, 4 + 4 + 32)). (I think)


// To lookup a value in a mapping, we load from the storage location keccak256(k, p),
// where k is the key left padded to 32 bytes and p is the storage slot
mstore(132, assetProxyId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

132 is where nestedAssetDataElementLen should be stored for our outgoing calldata. assetProxyId would starting from 164.

Edit: doesn't matter, we overwrite anyway in the big calldatacopy. It does seem worth re-using these 4 bytes.

// Copy `nestedAssetData[i]` from calldata to memory
calldatacopy(
132, // memory slot after `amounts[i]`
nestedAssetDataElementOffset, // location of `nestedAssetData[i]` in calldata
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not take offset from outer assetData into account, nor the selectors. Should be add(assetDataOffset, add(nestedAssetDataElementOffset, 4 + 4)) or sub(nestedAssetDataElementContentsStart, 32).

0, // pointer to start of input
add(164, nestedAssetDataElementLen), // length of input
100, // write output over memory that won't be reused
512 // reserve 512 bytes for output
Copy link
Contributor

@recmo recmo Nov 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes or proxies will never return more then 512 bytes. Reasonable assumption, but why not use returndatacopy and leave both of these zero?

)

if iszero(success) {
revert(100, returndatasize())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returndatacopy(0, 0, returndatasize())
revert(0, returndatasize())

@dekz dekz mentioned this pull request Nov 9, 2018
12 tasks
@abandeali1 abandeali1 force-pushed the feature/contracts/multiAssetProxy branch from 13c5300 to 2174209 Compare November 12, 2018 04:09
@abandeali1 abandeali1 force-pushed the feature/contracts/multiAssetProxy branch 2 times, most recently from 9b6f8ec to 551efd1 Compare November 13, 2018 01:18
@abandeali1 abandeali1 changed the title [WIP] Implement MultiAssetProxy Implement MultiAssetProxy Nov 13, 2018
@abandeali1 abandeali1 requested a review from hysz November 13, 2018 01:21
@abandeali1 abandeali1 removed the WIP label Nov 13, 2018
Copy link
Contributor

@albrow albrow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added myself as a code owner for the contracts tests to specifically check for race conditions and potential issues with Geth. As far as that goes, this one LGTM.

0, // pointer to start of input
add(164, nestedAssetDataElementLen), // length of input
0, // write output over memory that won't be reused
0 // reserve 512 bytes for output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// reserve 512 bytes for output - do we want to explicitly reserve 512 bytes here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, outdated comment

// where k is the key left padded to 32 bytes and p is the storage slot
mstore(132, assetProxyId)
mstore(164, assetProxies_slot)
let assetProxy := sload(keccak256(132, 64))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One possible optimization: If assetProxyId is the same as the previous iteration then we could skip this check. Clients could then optimize their calldata by grouping-by-proxy.

});
it('should have an id of 0x94cfcdd7', async () => {
const proxyId = await multiAssetProxy.getProxyId.callAsync();
const expectedProxyId = '0x94cfcdd7';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be good to add a note about how this was derived.

@hysz
Copy link
Contributor

hysz commented Nov 27, 2018

🔥 🔥 🔥

@abandeali1 abandeali1 force-pushed the feature/contracts/multiAssetProxy branch from 53bb98a to 0e36f4c Compare November 27, 2018 01:53
@abandeali1 abandeali1 force-pushed the feature/contracts/multiAssetProxy branch from 0e36f4c to 708f4e9 Compare November 28, 2018 00:10
@abandeali1 abandeali1 merged commit 1eb19ca into development Nov 28, 2018
@abandeali1 abandeali1 deleted the feature/contracts/multiAssetProxy branch January 11, 2019 21:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants