Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexkroeger/f29fd11120b0fd50f5ab780732e1c5e8 to your computer and use it in GitHub Desktop.
Save alexkroeger/f29fd11120b0fd50f5ab780732e1c5e8 to your computer and use it in GitHub Desktop.
diff --git a/contracts/zero-ex/contracts/src/errors/LibNativeOrdersRichErrors.sol b/contracts/zero-ex/contracts/src/errors/LibNativeOrdersRichErrors.sol
index e339caac4..a12ab1428 100644
--- a/contracts/zero-ex/contracts/src/errors/LibNativeOrdersRichErrors.sol
+++ b/contracts/zero-ex/contracts/src/errors/LibNativeOrdersRichErrors.sol
@@ -88,6 +88,21 @@ library LibNativeOrdersRichErrors {
);
}
+ function InvalidSignerError(
+ address maker,
+ address signer
+ )
+ internal
+ pure
+ returns (bytes memory)
+ {
+ return abi.encodeWithSelector(
+ bytes4(keccak256("InvalidSignerError(address,address)")),
+ maker,
+ signer
+ );
+ }
+
function OrderNotFillableBySenderError(
bytes32 orderHash,
address sender,
diff --git a/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol b/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol
index 93684b4da..100e3ebe2 100644
--- a/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol
+++ b/contracts/zero-ex/contracts/src/features/NativeOrdersFeature.sol
@@ -74,9 +74,13 @@ contract NativeOrdersFeature is
_registerFeatureFunction(this.batchCancelLimitOrders.selector);
_registerFeatureFunction(this.batchCancelRfqOrders.selector);
_registerFeatureFunction(this.cancelPairLimitOrders.selector);
+ _registerFeatureFunction(this.cancelPairLimitOrdersWithSigner.selector);
_registerFeatureFunction(this.batchCancelPairLimitOrders.selector);
+ _registerFeatureFunction(this.batchCancelPairLimitOrdersWithSigner.selector);
_registerFeatureFunction(this.cancelPairRfqOrders.selector);
+ _registerFeatureFunction(this.cancelPairRfqOrdersWithSigner.selector);
_registerFeatureFunction(this.batchCancelPairRfqOrders.selector);
+ _registerFeatureFunction(this.batchCancelPairRfqOrdersWithSigner.selector);
_registerFeatureFunction(this.getLimitOrderInfo.selector);
_registerFeatureFunction(this.getRfqOrderInfo.selector);
_registerFeatureFunction(this.getLimitOrderHash.selector);
@@ -87,6 +91,8 @@ contract NativeOrdersFeature is
_registerFeatureFunction(this.getRfqOrderRelevantState.selector);
_registerFeatureFunction(this.batchGetLimitOrderRelevantStates.selector);
_registerFeatureFunction(this.batchGetRfqOrderRelevantStates.selector);
+ _registerFeatureFunction(this.registerAllowedOrderSigner.selector);
+ _registerFeatureFunction(this.isValidOrderSigner.selector);
return LibMigrate.MIGRATE_SUCCESS;
}
}
diff --git a/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersEvents.sol b/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersEvents.sol
index d055f1705..ff7c7810b 100644
--- a/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersEvents.sol
+++ b/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersEvents.sol
@@ -113,4 +113,14 @@ interface INativeOrdersEvents {
address[] addrs,
bool allowed
);
+
+ /// @dev Emitted when new order signers are registered
+ /// @param maker The maker address that is registering a designated signer.
+ /// @param signer The address that will sign on behalf of maker.
+ /// @param allowed Indicates whether the address should be allowed.
+ event OrderSignerRegistered(
+ address maker,
+ address signer,
+ bool allowed
+ );
}
diff --git a/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersFeature.sol b/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersFeature.sol
index 9ddb5306b..b482674cf 100644
--- a/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersFeature.sol
+++ b/contracts/zero-ex/contracts/src/features/interfaces/INativeOrdersFeature.sol
@@ -183,7 +183,23 @@ interface INativeOrdersFeature is
external;
/// @dev Cancel all limit orders for a given maker and pair with a salt less
- /// than the value provided. The caller must be the maker. Subsequent
+ /// than the value provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same maker and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker The maker for which to cancel.
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function cancelPairLimitOrdersWithSigner(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ external;
+
+ /// @dev Cancel all limit orders for a given maker and pairs with salts less
+ /// than the values provided. The caller must be the maker. Subsequent
/// calls to this function with the same caller and pair require the
/// new salt to be >= the old salt.
/// @param makerTokens The maker tokens.
@@ -196,6 +212,22 @@ interface INativeOrdersFeature is
)
external;
+ /// @dev Cancel all limit orders for a given maker and pairs with salts less
+ /// than the values provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same maker and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker The maker for which to cancel.
+ /// @param makerTokens The maker tokens.
+ /// @param takerTokens The taker tokens.
+ /// @param minValidSalts The new minimum valid salts.
+ function batchCancelPairLimitOrdersWithSigner(
+ address maker,
+ IERC20TokenV06[] memory makerTokens,
+ IERC20TokenV06[] memory takerTokens,
+ uint256[] memory minValidSalts
+ )
+ external;
+
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
/// than the value provided. The caller must be the maker. Subsequent
/// calls to this function with the same caller and pair require the
@@ -211,7 +243,23 @@ interface INativeOrdersFeature is
external;
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
- /// than the value provided. The caller must be the maker. Subsequent
+ /// than the value provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same maker and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker The maker for which to cancel.
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function cancelPairRfqOrdersWithSigner(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ external;
+
+ /// @dev Cancel all RFQ orders for a given maker and pairs with salts less
+ /// than the values provided. The caller must be the maker. Subsequent
/// calls to this function with the same caller and pair require the
/// new salt to be >= the old salt.
/// @param makerTokens The maker tokens.
@@ -224,6 +272,22 @@ interface INativeOrdersFeature is
)
external;
+ /// @dev Cancel all RFQ orders for a given maker and pairs with salts less
+ /// than the values provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same maker and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker The maker for which to cancel.
+ /// @param makerTokens The maker tokens.
+ /// @param takerTokens The taker tokens.
+ /// @param minValidSalts The new minimum valid salts.
+ function batchCancelPairRfqOrdersWithSigner(
+ address maker,
+ IERC20TokenV06[] memory makerTokens,
+ IERC20TokenV06[] memory takerTokens,
+ uint256[] memory minValidSalts
+ )
+ external;
+
/// @dev Get the order info for a limit order.
/// @param order The limit order.
/// @return orderInfo Info about the order.
@@ -345,4 +409,25 @@ interface INativeOrdersFeature is
uint128[] memory actualFillableTakerTokenAmounts,
bool[] memory isSignatureValids
);
+
+ /// @dev Register a signer who can sign on behalf of msg.sender
+ /// This allows one to sign on behalf of a contract that calls this function
+ /// @param signer The address from which you plan to generate signatures
+ /// @param allowed True to register, false to unregister.
+ function registerAllowedOrderSigner(
+ address signer,
+ bool allowed
+ )
+ external;
+
+ /// @dev checks if a given address is registered to sign on behalf of a maker address
+ /// @param maker The maker address encoded in an order (can be a contract)
+ /// @param signer The address that is providing a signature
+ function isValidOrderSigner(
+ address maker,
+ address signer
+ )
+ external
+ view
+ returns (bool isAllowed);
}
diff --git a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersCancellation.sol b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersCancellation.sol
index b90f0a9c9..00a34e4be 100644
--- a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersCancellation.sol
+++ b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersCancellation.sol
@@ -55,7 +55,7 @@ abstract contract NativeOrdersCancellation is
public
{
bytes32 orderHash = getLimitOrderHash(order);
- if (msg.sender != order.maker) {
+ if (msg.sender != order.maker && !isValidOrderSigner(order.maker, msg.sender)) {
LibNativeOrdersRichErrors.OnlyOrderMakerAllowed(
orderHash,
msg.sender,
@@ -72,7 +72,7 @@ abstract contract NativeOrdersCancellation is
public
{
bytes32 orderHash = getRfqOrderHash(order);
- if (msg.sender != order.maker) {
+ if (msg.sender != order.maker && !isValidOrderSigner(order.maker, msg.sender)) {
LibNativeOrdersRichErrors.OnlyOrderMakerAllowed(
orderHash,
msg.sender,
@@ -118,33 +118,34 @@ abstract contract NativeOrdersCancellation is
)
public
{
- LibNativeOrdersStorage.Storage storage stor =
- LibNativeOrdersStorage.getStorage();
-
- uint256 oldMinValidSalt =
- stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
- [msg.sender]
- [address(makerToken)]
- [address(takerToken)];
+ _cancelPairLimitOrders(msg.sender, makerToken, takerToken, minValidSalt);
+ }
- // New min salt must >= the old one.
- if (oldMinValidSalt > minValidSalt) {
- LibNativeOrdersRichErrors.
- CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
- .rrevert();
+ /// @dev Cancel all limit orders for a given maker and pair with a salt less
+ /// than the value provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same caller and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker the maker for whom the msg.sender is the signer.
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function cancelPairLimitOrdersWithSigner(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ public
+ {
+ // verify that the signer is authorized for the maker
+ if (!isValidOrderSigner(maker, msg.sender)) {
+ LibNativeOrdersRichErrors.InvalidSignerError(
+ maker,
+ msg.sender
+ ).rrevert();
}
- stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
- [msg.sender]
- [address(makerToken)]
- [address(takerToken)] = minValidSalt;
-
- emit PairCancelledLimitOrders(
- msg.sender,
- address(makerToken),
- address(takerToken),
- minValidSalt
- );
+ _cancelPairLimitOrders(maker, makerToken, takerToken, minValidSalt);
}
/// @dev Cancel all limit orders for a given maker and pair with a salt less
@@ -168,7 +169,47 @@ abstract contract NativeOrdersCancellation is
);
for (uint256 i = 0; i < makerTokens.length; ++i) {
- cancelPairLimitOrders(
+ _cancelPairLimitOrders(
+ msg.sender,
+ makerTokens[i],
+ takerTokens[i],
+ minValidSalts[i]
+ );
+ }
+ }
+
+ /// @dev Cancel all limit orders for a given maker and pair with a salt less
+ /// than the value provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same caller and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker the maker for whom the msg.sender is the signer.
+ /// @param makerTokens The maker tokens.
+ /// @param takerTokens The taker tokens.
+ /// @param minValidSalts The new minimum valid salts.
+ function batchCancelPairLimitOrdersWithSigner(
+ address maker,
+ IERC20TokenV06[] memory makerTokens,
+ IERC20TokenV06[] memory takerTokens,
+ uint256[] memory minValidSalts
+ )
+ public
+ {
+ require(
+ makerTokens.length == takerTokens.length &&
+ makerTokens.length == minValidSalts.length,
+ "NativeOrdersFeature/MISMATCHED_PAIR_ORDERS_ARRAY_LENGTHS"
+ );
+
+ if (!isValidOrderSigner(maker, msg.sender)) {
+ LibNativeOrdersRichErrors.InvalidSignerError(
+ maker,
+ msg.sender
+ ).rrevert();
+ }
+
+ for (uint256 i = 0; i < makerTokens.length; ++i) {
+ _cancelPairLimitOrders(
+ maker,
makerTokens[i],
takerTokens[i],
minValidSalts[i]
@@ -190,33 +231,33 @@ abstract contract NativeOrdersCancellation is
)
public
{
- LibNativeOrdersStorage.Storage storage stor =
- LibNativeOrdersStorage.getStorage();
-
- uint256 oldMinValidSalt =
- stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
- [msg.sender]
- [address(makerToken)]
- [address(takerToken)];
+ _cancelPairRfqOrders(msg.sender, makerToken, takerToken, minValidSalt);
+ }
- // New min salt must >= the old one.
- if (oldMinValidSalt > minValidSalt) {
- LibNativeOrdersRichErrors.
- CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
- .rrevert();
+ /// @dev Cancel all RFQ orders for a given maker and pair with a salt less
+ /// than the value provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same caller and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker the maker for whom the msg.sender is the signer.
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function cancelPairRfqOrdersWithSigner(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ public
+ {
+ if (!isValidOrderSigner(maker, msg.sender)) {
+ LibNativeOrdersRichErrors.InvalidSignerError(
+ maker,
+ msg.sender
+ ).rrevert();
}
- stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
- [msg.sender]
- [address(makerToken)]
- [address(takerToken)] = minValidSalt;
-
- emit PairCancelledRfqOrders(
- msg.sender,
- address(makerToken),
- address(takerToken),
- minValidSalt
- );
+ _cancelPairRfqOrders(maker, makerToken, takerToken, minValidSalt);
}
/// @dev Cancel all RFQ orders for a given maker and pair with a salt less
@@ -240,7 +281,47 @@ abstract contract NativeOrdersCancellation is
);
for (uint256 i = 0; i < makerTokens.length; ++i) {
- cancelPairRfqOrders(
+ _cancelPairRfqOrders(
+ msg.sender,
+ makerTokens[i],
+ takerTokens[i],
+ minValidSalts[i]
+ );
+ }
+ }
+
+ /// @dev Cancel all RFQ orders for a given maker and pairs with salts less
+ /// than the values provided. The caller must be a signer registered to the maker.
+ /// Subsequent calls to this function with the same caller and pair require the
+ /// new salt to be >= the old salt.
+ /// @param maker the maker for whom the msg.sender is the signer.
+ /// @param makerTokens The maker tokens.
+ /// @param takerTokens The taker tokens.
+ /// @param minValidSalts The new minimum valid salts.
+ function batchCancelPairRfqOrdersWithSigner(
+ address maker,
+ IERC20TokenV06[] memory makerTokens,
+ IERC20TokenV06[] memory takerTokens,
+ uint256[] memory minValidSalts
+ )
+ public
+ {
+ require(
+ makerTokens.length == takerTokens.length &&
+ makerTokens.length == minValidSalts.length,
+ "NativeOrdersFeature/MISMATCHED_PAIR_ORDERS_ARRAY_LENGTHS"
+ );
+
+ if (!isValidOrderSigner(maker, msg.sender)) {
+ LibNativeOrdersRichErrors.InvalidSignerError(
+ maker,
+ msg.sender
+ ).rrevert();
+ }
+
+ for (uint256 i = 0; i < makerTokens.length; ++i) {
+ _cancelPairRfqOrders(
+ maker,
makerTokens[i],
takerTokens[i],
minValidSalts[i]
@@ -262,4 +343,90 @@ abstract contract NativeOrdersCancellation is
emit OrderCancelled(orderHash, maker);
}
+
+ /// @dev Cancel all RFQ orders for a given maker and pair with a salt less
+ /// than the value provided.
+ /// @param maker The target maker address
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function _cancelPairRfqOrders(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ private
+ {
+ LibNativeOrdersStorage.Storage storage stor =
+ LibNativeOrdersStorage.getStorage();
+
+ uint256 oldMinValidSalt =
+ stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
+ [maker]
+ [address(makerToken)]
+ [address(takerToken)];
+
+ // New min salt must >= the old one.
+ if (oldMinValidSalt > minValidSalt) {
+ LibNativeOrdersRichErrors.
+ CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
+ .rrevert();
+ }
+
+ stor.rfqOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
+ [maker]
+ [address(makerToken)]
+ [address(takerToken)] = minValidSalt;
+
+ emit PairCancelledRfqOrders(
+ maker,
+ address(makerToken),
+ address(takerToken),
+ minValidSalt
+ );
+ }
+
+ /// @dev Cancel all limit orders for a given maker and pair with a salt less
+ /// than the value provided.
+ /// @param maker The target maker address
+ /// @param makerToken The maker token.
+ /// @param takerToken The taker token.
+ /// @param minValidSalt The new minimum valid salt.
+ function _cancelPairLimitOrders(
+ address maker,
+ IERC20TokenV06 makerToken,
+ IERC20TokenV06 takerToken,
+ uint256 minValidSalt
+ )
+ private
+ {
+ LibNativeOrdersStorage.Storage storage stor =
+ LibNativeOrdersStorage.getStorage();
+
+ uint256 oldMinValidSalt =
+ stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
+ [maker]
+ [address(makerToken)]
+ [address(takerToken)];
+
+ // New min salt must >= the old one.
+ if (oldMinValidSalt > minValidSalt) {
+ LibNativeOrdersRichErrors.
+ CancelSaltTooLowError(minValidSalt, oldMinValidSalt)
+ .rrevert();
+ }
+
+ stor.limitOrdersMakerToMakerTokenToTakerTokenToMinValidOrderSalt
+ [maker]
+ [address(makerToken)]
+ [address(takerToken)] = minValidSalt;
+
+ emit PairCancelledLimitOrders(
+ maker,
+ address(makerToken),
+ address(takerToken),
+ minValidSalt
+ );
+ }
}
diff --git a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersInfo.sol b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersInfo.sol
index 47d6fde3b..16ea926c8 100644
--- a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersInfo.sol
+++ b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersInfo.sol
@@ -168,8 +168,10 @@ abstract contract NativeOrdersInfo is
orderInfo: orderInfo
})
);
- isSignatureValid = order.maker ==
- LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
+ address signerOfHash = LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
+ isSignatureValid =
+ (order.maker == signerOfHash) ||
+ isValidOrderSigner(order.maker, signerOfHash);
}
/// @dev Get order info, fillable amount, and signature validity for an RFQ order.
@@ -202,8 +204,10 @@ abstract contract NativeOrdersInfo is
orderInfo: orderInfo
})
);
- isSignatureValid = order.maker ==
- LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
+ address signerOfHash = LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
+ isSignatureValid =
+ (order.maker == signerOfHash) ||
+ isValidOrderSigner(order.maker, signerOfHash);
}
/// @dev Batch version of `getLimitOrderRelevantState()`, without reverting.
@@ -389,4 +393,22 @@ abstract contract NativeOrdersInfo is
uint256(params.orderTakerAmount)
).safeDowncastToUint128();
}
+
+ /// @dev checks if a given address is registered to sign on behalf of a maker address
+ /// @param maker The maker address encoded in an order (can be a contract)
+ /// @param signer The address that is providing a signature
+ function isValidOrderSigner(
+ address maker,
+ address signer
+ )
+ public
+ view
+ returns (bool isValid)
+ {
+ // returns false if it the mapping doesn't exist
+ return LibNativeOrdersStorage.getStorage()
+ .orderSignerRegistry
+ [maker]
+ [signer];
+ }
}
diff --git a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersSettlement.sol b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersSettlement.sol
index 7c030e184..ea7e832a4 100644
--- a/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersSettlement.sol
+++ b/contracts/zero-ex/contracts/src/features/native_orders/NativeOrdersSettlement.sol
@@ -370,7 +370,7 @@ abstract contract NativeOrdersSettlement is
orderInfo.orderHash,
params.signature
);
- if (signer != params.order.maker) {
+ if (signer != params.order.maker && !isValidOrderSigner(params.order.maker, signer)) {
LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
orderInfo.orderHash,
signer,
@@ -478,7 +478,7 @@ abstract contract NativeOrdersSettlement is
// Signature must be valid for the order.
{
address signer = LibSignature.getSignerOfHash(orderInfo.orderHash, signature);
- if (signer != order.maker) {
+ if (signer != order.maker && !isValidOrderSigner(order.maker, signer)) {
LibNativeOrdersRichErrors.OrderNotSignedByMakerError(
orderInfo.orderHash,
signer,
@@ -565,4 +565,21 @@ abstract contract NativeOrdersSettlement is
makerTokenFilledAmount
);
}
+
+ /// @dev register a signer who can sign on behalf of msg.sender
+ /// @param signer The address from which you plan to generate signatures
+ /// @param allowed True to register, false to unregister.
+ function registerAllowedOrderSigner(
+ address signer,
+ bool allowed
+ )
+ external
+ {
+ LibNativeOrdersStorage.Storage storage stor =
+ LibNativeOrdersStorage.getStorage();
+
+ stor.orderSignerRegistry[msg.sender][signer] = allowed;
+
+ emit OrderSignerRegistered(msg.sender, signer, allowed);
+ }
}
diff --git a/contracts/zero-ex/contracts/src/storage/LibNativeOrdersStorage.sol b/contracts/zero-ex/contracts/src/storage/LibNativeOrdersStorage.sol
index a4adf413c..ceb899281 100644
--- a/contracts/zero-ex/contracts/src/storage/LibNativeOrdersStorage.sol
+++ b/contracts/zero-ex/contracts/src/storage/LibNativeOrdersStorage.sol
@@ -43,6 +43,9 @@ library LibNativeOrdersStorage {
// For a given order origin, which tx.origin addresses are allowed to
// fill the order.
mapping(address => mapping(address => bool)) originRegistry;
+ // For a given maker address, which addresses are allowed to
+ // sign on its behalf.
+ mapping(address => mapping(address => bool)) orderSignerRegistry;
}
/// @dev Get the storage bucket for this contract.
diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol
index 8db42204d..590d4f1fa 100644
--- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol
+++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeAdapter.sol
@@ -30,6 +30,7 @@ import "./mixins/MixinCryptoCom.sol";
import "./mixins/MixinDodo.sol";
import "./mixins/MixinDodoV2.sol";
import "./mixins/MixinKyber.sol";
+import "./mixins/MixinMakerPSM.sol";
import "./mixins/MixinMooniswap.sol";
import "./mixins/MixinMStable.sol";
import "./mixins/MixinNerve.sol";
@@ -49,6 +50,7 @@ contract BridgeAdapter is
MixinDodo,
MixinDodoV2,
MixinKyber,
+ MixinMakerPSM,
MixinMooniswap,
MixinMStable,
MixinNerve,
@@ -68,6 +70,7 @@ contract BridgeAdapter is
MixinDodo()
MixinDodoV2()
MixinKyber(weth)
+ MixinMakerPSM()
MixinMooniswap(weth)
MixinMStable()
MixinNerve()
@@ -123,6 +126,13 @@ contract BridgeAdapter is
sellAmount,
order.bridgeData
);
+ } else if (protocolId == BridgeProtocols.MAKERPSM) {
+ boughtAmount = _tradeMakerPsm(
+ sellToken,
+ buyToken,
+ sellAmount,
+ order.bridgeData
+ );
} else if (protocolId == BridgeProtocols.MOONISWAP) {
boughtAmount = _tradeMooniswap(
sellToken,
diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol
index baebf8ac0..60630fa7c 100644
--- a/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol
+++ b/contracts/zero-ex/contracts/src/transformers/bridges/BridgeProtocols.sol
@@ -43,4 +43,5 @@ library BridgeProtocols {
uint128 internal constant BANCOR = 13;
uint128 internal constant COFIX = 14;
uint128 internal constant NERVE = 15;
+ uint128 internal constant MAKERPSM = 16;
}
diff --git a/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol
new file mode 100644
index 000000000..283e9873f
--- /dev/null
+++ b/contracts/zero-ex/contracts/src/transformers/bridges/mixins/MixinMakerPSM.sol
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+
+ Copyright 2021 ZeroEx Intl.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+*/
+
+pragma solidity ^0.6.5;
+pragma experimental ABIEncoderV2;
+
+import "@0x/contracts-erc20/contracts/src/v06/LibERC20TokenV06.sol";
+import "@0x/contracts-erc20/contracts/src/v06/IERC20TokenV06.sol";
+import "@0x/contracts-utils/contracts/src/v06/LibSafeMathV06.sol";
+
+interface IPSM {
+ // @dev Get the fee for selling USDC to DAI in PSM
+ // @return tin toll in [wad]
+ function tin() external view returns (uint256);
+ // @dev Get the fee for selling DAI to USDC in PSM
+ // @return tout toll out [wad]
+ function tout() external view returns (uint256);
+
+ // @dev Get the address of the PSM state Vat
+ // @return address of the Vat
+ function vat() external view returns (address);
+
+ // @dev Get the address of the underlying vault powering PSM
+ // @return address of gemJoin contract
+ function gemJoin() external view returns (address);
+
+ // @dev Sell USDC for DAI
+ // @param usr The address of the account trading USDC for DAI.
+ // @param gemAmt The amount of USDC to sell in USDC base units
+ function sellGem(
+ address usr,
+ uint256 gemAmt
+ ) external;
+ // @dev Buy USDC for DAI
+ // @param usr The address of the account trading DAI for USDC
+ // @param gemAmt The amount of USDC to buy in USDC base units
+ function buyGem(
+ address usr,
+ uint256 gemAmt
+ ) external;
+}
+
+contract MixinMakerPSM {
+
+ using LibERC20TokenV06 for IERC20TokenV06;
+ using LibSafeMathV06 for uint256;
+
+ struct MakerPsmBridgeData {
+ address psmAddress;
+ address gemTokenAddres;
+ }
+
+ // Maker units
+ // wad: fixed point decimal with 18 decimals (for basic quantities, e.g. balances)
+ uint256 constant private WAD = 10 ** 18;
+ // ray: fixed point decimal with 27 decimals (for precise quantites, e.g. ratios)
+ uint256 constant private RAY = 10 ** 27;
+ // rad: fixed point decimal with 45 decimals (result of integer multiplication with a wad and a ray)
+ uint256 constant private RAD = 10 ** 45;
+ // See https://github.com/makerdao/dss/blob/master/DEVELOPING.md
+
+ function _tradeMakerPsm(
+ IERC20TokenV06 sellToken,
+ IERC20TokenV06 buyToken,
+ uint256 sellAmount,
+ bytes memory bridgeData
+ )
+ internal
+ returns (uint256 boughtAmount)
+ {
+ // Decode the bridge data.
+ MakerPsmBridgeData memory data = abi.decode(bridgeData, (MakerPsmBridgeData));
+ uint256 beforeBalance = buyToken.balanceOf(address(this));
+
+ IPSM psm = IPSM(data.psmAddress);
+
+ if (address(sellToken) == data.gemTokenAddres) {
+ sellToken.approveIfBelow(
+ psm.gemJoin(),
+ sellAmount
+ );
+
+ psm.sellGem(address(this), sellAmount);
+ } else if (address(buyToken) == data.gemTokenAddres) {
+ uint256 feeDivisor = WAD.safeAdd(psm.tout()); // eg. 1.001 * 10 ** 18 with 0.1% fee [tout is in wad];
+ uint256 buyTokenBaseUnit = uint256(10) ** uint256(buyToken.decimals());
+ uint256 gemAmount = sellAmount.safeMul(buyTokenBaseUnit).safeDiv(feeDivisor);
+
+ sellToken.approveIfBelow(
+ data.psmAddress,
+ sellAmount
+ );
+ psm.buyGem(address(this), gemAmount);
+ }
+
+ return buyToken.balanceOf(address(this)).safeSub(beforeBalance);
+ }
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment