Merge pull request #2591 from 0xProject/feat/asset-swapper/exchange-proxy-support
asset-swapper: Exchange Proxy support
This commit is contained in:
@@ -77,7 +77,7 @@ jobs:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- repo-{{ .Environment.CIRCLE_SHA1 }}
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler @0x/contracts-zero-ex
|
||||
- run: yarn wsrun test:circleci @0x/contracts-multisig @0x/contracts-utils @0x/contracts-exchange-libs @0x/contracts-erc20 @0x/contracts-erc721 @0x/contracts-erc1155 @0x/contracts-asset-proxy @0x/contracts-exchange-forwarder @0x/contracts-coordinator @0x/contracts-erc20-bridge-sampler @0x/contracts-broker @0x/contracts-zero-ex
|
||||
test-publish:
|
||||
resource_class: medium+
|
||||
docker:
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "1.1.5",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Fix broken tests.",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"timestamp": 1583220306,
|
||||
"version": "1.1.4",
|
||||
|
@@ -44,13 +44,13 @@ blockchainTests.resets('GodsUnchainedValidator unit tests', env => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto.plus(1), quality).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('PROTO_MISMATCH');
|
||||
expect(tx).to.revertWith('GodsUnchainedValidator/PROTO_MISMATCH');
|
||||
});
|
||||
it("reverts if assetData quality doesn't match proeprtyData", async () => {
|
||||
const tokenId = getRandomInteger(0, constants.MAX_UINT256);
|
||||
await godsUnchained.setTokenProperties(tokenId, proto, quality.plus(1)).awaitTransactionSuccessAsync();
|
||||
const tx = validator.checkBrokerAsset(tokenId, propertyData).callAsync();
|
||||
expect(tx).to.revertWith('QUALITY_MISMATCH');
|
||||
expect(tx).to.revertWith('GodsUnchainedValidator/QUALITY_MISMATCH');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -69,6 +69,13 @@ export function encodeFillQuoteTransformerData(data: FillQuoteTransformerData):
|
||||
return fillQuoteTransformerDataEncoder.encode([data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI-decode a `FillQuoteTransformer.TransformData` type.
|
||||
*/
|
||||
export function decodeFillQuoteTransformerData(encoded: string): FillQuoteTransformerData {
|
||||
return fillQuoteTransformerDataEncoder.decode(encoded).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI encoder for `WethTransformer.TransformData`
|
||||
*/
|
||||
@@ -95,6 +102,13 @@ export function encodeWethTransformerData(data: WethTransformerData): string {
|
||||
return wethTransformerDataEncoder.encode([data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI-decode a `WethTransformer.TransformData` type.
|
||||
*/
|
||||
export function decodeWethTransformerData(encoded: string): WethTransformerData {
|
||||
return wethTransformerDataEncoder.decode(encoded).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI encoder for `PayTakerTransformer.TransformData`
|
||||
*/
|
||||
@@ -121,6 +135,13 @@ export function encodePayTakerTransformerData(data: PayTakerTransformerData): st
|
||||
return payTakerTransformerDataEncoder.encode([data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI-decode a `PayTakerTransformer.TransformData` type.
|
||||
*/
|
||||
export function decodePayTakerTransformerData(encoded: string): PayTakerTransformerData {
|
||||
return payTakerTransformerDataEncoder.decode(encoded).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI encoder for `PayTakerTransformer.TransformData`
|
||||
*/
|
||||
@@ -157,3 +178,10 @@ export interface AffiliateFeeTransformerData {
|
||||
export function encodeAffiliateFeeTransformerData(data: AffiliateFeeTransformerData): string {
|
||||
return affiliateFeeTransformerDataEncoder.encode(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* ABI-decode a `AffiliateFeeTransformer.TransformData` type.
|
||||
*/
|
||||
export function decodeAffiliateFeeTransformerData(encoded: string): AffiliateFeeTransformerData {
|
||||
return affiliateFeeTransformerDataEncoder.decode(encoded).data;
|
||||
}
|
||||
|
@@ -1,4 +1,13 @@
|
||||
[
|
||||
{
|
||||
"version": "5.3.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Allow identifiers with leading underscores in python wrappers",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "5.2.2",
|
||||
"changes": [
|
||||
|
@@ -146,7 +146,16 @@ if (args.language === 'TypeScript') {
|
||||
registerPartials();
|
||||
|
||||
function makeLanguageSpecificName(methodName: string): string {
|
||||
return args.language === 'Python' ? changeCase.snake(methodName) : methodName;
|
||||
if (args.language === 'Python') {
|
||||
let snakeCased = changeCase.snake(methodName);
|
||||
// Move leading underscores to the end.
|
||||
const m = /^(_*).+?(_*)$/.exec(methodName);
|
||||
if (m) {
|
||||
snakeCased = `${snakeCased}${m[1] || m[2]}`;
|
||||
}
|
||||
return snakeCased;
|
||||
}
|
||||
return methodName;
|
||||
}
|
||||
|
||||
if (_.isEmpty(abiFileNames)) {
|
||||
|
@@ -153,10 +153,15 @@ export function registerPythonHelpers(): void {
|
||||
}
|
||||
return '';
|
||||
});
|
||||
Handlebars.registerHelper(
|
||||
'toPythonClassname',
|
||||
(sourceName: string) => new Handlebars.SafeString(changeCase.pascal(sourceName)),
|
||||
);
|
||||
Handlebars.registerHelper('toPythonClassname', (sourceName: string) => {
|
||||
let pascalCased = changeCase.pascal(sourceName);
|
||||
// Retain trailing underscores.
|
||||
const m = /^.+?(_*)$/.exec(sourceName);
|
||||
if (m) {
|
||||
pascalCased = `${pascalCased}${m[1]}`;
|
||||
}
|
||||
return new Handlebars.SafeString(pascalCased);
|
||||
});
|
||||
Handlebars.registerHelper(
|
||||
'makeOutputsValue',
|
||||
/**
|
||||
|
@@ -331,13 +331,14 @@ export const utils = {
|
||||
'max',
|
||||
'round',
|
||||
];
|
||||
if (
|
||||
pythonReservedWords.includes(snakeCased) ||
|
||||
pythonBuiltins.includes(snakeCased) ||
|
||||
/*changeCase strips leading underscores :(*/ input[0] === '_'
|
||||
) {
|
||||
if (pythonReservedWords.includes(snakeCased) || pythonBuiltins.includes(snakeCased)) {
|
||||
snakeCased = `_${snakeCased}`;
|
||||
}
|
||||
// Retain trailing underscores.
|
||||
const m = /^.+?(_*)$/.exec(input);
|
||||
if (m) {
|
||||
snakeCased = `${snakeCased}${m[1]}`;
|
||||
}
|
||||
return snakeCased;
|
||||
},
|
||||
/**
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
class {{toPythonClassname this.languageSpecificName}}Method(ContractMethod):
|
||||
class {{toPythonClassname this.languageSpecificName}}Method(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the {{this.name}} method."""
|
||||
|
||||
def __init__(self, web3_or_provider: Union[Web3, BaseProvider], contract_address: str, contract_function: ContractFunction{{#if inputs}}, validator: Validator=None{{/if}}):
|
||||
|
@@ -178,7 +178,9 @@ class AbiGenDummyNestedStruct(TypedDict):
|
||||
description: str
|
||||
|
||||
|
||||
class AcceptsAnArrayOfBytesMethod(ContractMethod):
|
||||
class AcceptsAnArrayOfBytesMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the acceptsAnArrayOfBytes method."""
|
||||
|
||||
def __init__(
|
||||
@@ -225,7 +227,7 @@ class AcceptsAnArrayOfBytesMethod(ContractMethod):
|
||||
return self._underlying_method(a).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class AcceptsBytesMethod(ContractMethod):
|
||||
class AcceptsBytesMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the acceptsBytes method."""
|
||||
|
||||
def __init__(
|
||||
@@ -267,7 +269,9 @@ class AcceptsBytesMethod(ContractMethod):
|
||||
return self._underlying_method(a).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class ComplexInputComplexOutputMethod(ContractMethod):
|
||||
class ComplexInputComplexOutputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the complexInputComplexOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -329,7 +333,7 @@ class ComplexInputComplexOutputMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class EcrecoverFnMethod(ContractMethod):
|
||||
class EcrecoverFnMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the ecrecoverFn method."""
|
||||
|
||||
def __init__(
|
||||
@@ -414,7 +418,7 @@ class EcrecoverFnMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class EmitSimpleEventMethod(ContractMethod):
|
||||
class EmitSimpleEventMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the emitSimpleEvent method."""
|
||||
|
||||
def __init__(
|
||||
@@ -457,7 +461,9 @@ class EmitSimpleEventMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class MethodAcceptingArrayOfArrayOfStructsMethod(ContractMethod):
|
||||
class MethodAcceptingArrayOfArrayOfStructsMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the methodAcceptingArrayOfArrayOfStructs method."""
|
||||
|
||||
def __init__(
|
||||
@@ -509,7 +515,9 @@ class MethodAcceptingArrayOfArrayOfStructsMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class MethodAcceptingArrayOfStructsMethod(ContractMethod):
|
||||
class MethodAcceptingArrayOfStructsMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the methodAcceptingArrayOfStructs method."""
|
||||
|
||||
def __init__(
|
||||
@@ -559,7 +567,9 @@ class MethodAcceptingArrayOfStructsMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class MethodReturningArrayOfStructsMethod(ContractMethod):
|
||||
class MethodReturningArrayOfStructsMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the methodReturningArrayOfStructs method."""
|
||||
|
||||
def __init__(
|
||||
@@ -598,7 +608,9 @@ class MethodReturningArrayOfStructsMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class MethodReturningMultipleValuesMethod(ContractMethod):
|
||||
class MethodReturningMultipleValuesMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the methodReturningMultipleValues method."""
|
||||
|
||||
def __init__(
|
||||
@@ -632,7 +644,7 @@ class MethodReturningMultipleValuesMethod(ContractMethod):
|
||||
|
||||
class MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod(
|
||||
ContractMethod
|
||||
):
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the methodUsingNestedStructWithInnerStructNotUsedElsewhere method."""
|
||||
|
||||
def __init__(
|
||||
@@ -665,7 +677,9 @@ class MethodUsingNestedStructWithInnerStructNotUsedElsewhereMethod(
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class MultiInputMultiOutputMethod(ContractMethod):
|
||||
class MultiInputMultiOutputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the multiInputMultiOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -747,7 +761,7 @@ class MultiInputMultiOutputMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class NestedStructInputMethod(ContractMethod):
|
||||
class NestedStructInputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the nestedStructInput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -791,7 +805,7 @@ class NestedStructInputMethod(ContractMethod):
|
||||
return self._underlying_method(n).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class NestedStructOutputMethod(ContractMethod):
|
||||
class NestedStructOutputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the nestedStructOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -824,7 +838,7 @@ class NestedStructOutputMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class NoInputNoOutputMethod(ContractMethod):
|
||||
class NoInputNoOutputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the noInputNoOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -854,7 +868,9 @@ class NoInputNoOutputMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class NoInputSimpleOutputMethod(ContractMethod):
|
||||
class NoInputSimpleOutputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the noInputSimpleOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -885,7 +901,7 @@ class NoInputSimpleOutputMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class NonPureMethodMethod(ContractMethod):
|
||||
class NonPureMethodMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the nonPureMethod method."""
|
||||
|
||||
def __init__(
|
||||
@@ -929,7 +945,9 @@ class NonPureMethodMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class NonPureMethodThatReturnsNothingMethod(ContractMethod):
|
||||
class NonPureMethodThatReturnsNothingMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the nonPureMethodThatReturnsNothing method."""
|
||||
|
||||
def __init__(
|
||||
@@ -972,7 +990,7 @@ class NonPureMethodThatReturnsNothingMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class OverloadedMethod2Method(ContractMethod):
|
||||
class OverloadedMethod2Method(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the overloadedMethod method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1014,7 +1032,7 @@ class OverloadedMethod2Method(ContractMethod):
|
||||
return self._underlying_method(a).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class OverloadedMethod1Method(ContractMethod):
|
||||
class OverloadedMethod1Method(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the overloadedMethod method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1056,7 +1074,9 @@ class OverloadedMethod1Method(ContractMethod):
|
||||
return self._underlying_method(a).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class PureFunctionWithConstantMethod(ContractMethod):
|
||||
class PureFunctionWithConstantMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the pureFunctionWithConstant method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1085,7 +1105,9 @@ class PureFunctionWithConstantMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class RequireWithConstantMethod(ContractMethod):
|
||||
class RequireWithConstantMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the requireWithConstant method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1113,7 +1135,7 @@ class RequireWithConstantMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class RevertWithConstantMethod(ContractMethod):
|
||||
class RevertWithConstantMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the revertWithConstant method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1141,7 +1163,9 @@ class RevertWithConstantMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class SimpleInputNoOutputMethod(ContractMethod):
|
||||
class SimpleInputNoOutputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simpleInputNoOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1189,7 +1213,9 @@ class SimpleInputNoOutputMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class SimpleInputSimpleOutputMethod(ContractMethod):
|
||||
class SimpleInputSimpleOutputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simpleInputSimpleOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1238,7 +1264,7 @@ class SimpleInputSimpleOutputMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class SimplePureFunctionMethod(ContractMethod):
|
||||
class SimplePureFunctionMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simplePureFunction method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1267,7 +1293,9 @@ class SimplePureFunctionMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class SimplePureFunctionWithInputMethod(ContractMethod):
|
||||
class SimplePureFunctionWithInputMethod(
|
||||
ContractMethod
|
||||
): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simplePureFunctionWithInput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1312,7 +1340,7 @@ class SimplePureFunctionWithInputMethod(ContractMethod):
|
||||
return self._underlying_method(x).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class SimpleRequireMethod(ContractMethod):
|
||||
class SimpleRequireMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simpleRequire method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1340,7 +1368,7 @@ class SimpleRequireMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class SimpleRevertMethod(ContractMethod):
|
||||
class SimpleRevertMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the simpleRevert method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1368,7 +1396,7 @@ class SimpleRevertMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class StructInputMethod(ContractMethod):
|
||||
class StructInputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the structInput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1410,7 +1438,7 @@ class StructInputMethod(ContractMethod):
|
||||
return self._underlying_method(s).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class StructOutputMethod(ContractMethod):
|
||||
class StructOutputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the structOutput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1446,7 +1474,7 @@ class StructOutputMethod(ContractMethod):
|
||||
return self._underlying_method().estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class WithAddressInputMethod(ContractMethod):
|
||||
class WithAddressInputMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the withAddressInput method."""
|
||||
|
||||
def __init__(
|
||||
@@ -1537,7 +1565,7 @@ class WithAddressInputMethod(ContractMethod):
|
||||
)
|
||||
|
||||
|
||||
class WithdrawMethod(ContractMethod):
|
||||
class WithdrawMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the withdraw method."""
|
||||
|
||||
def __init__(
|
||||
|
@@ -90,7 +90,7 @@ class LibDummy:
|
||||
try:
|
||||
for middleware in MIDDLEWARE:
|
||||
web3.middleware_onion.inject(
|
||||
middleware["function"], layer=middleware["layer"]
|
||||
middleware["function"], layer=middleware["layer"],
|
||||
)
|
||||
except ValueError as value_error:
|
||||
if value_error.args == (
|
||||
|
@@ -46,7 +46,7 @@ except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class PublicAddConstantMethod(ContractMethod):
|
||||
class PublicAddConstantMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the publicAddConstant method."""
|
||||
|
||||
def __init__(
|
||||
@@ -91,7 +91,7 @@ class PublicAddConstantMethod(ContractMethod):
|
||||
return self._underlying_method(x).estimateGas(tx_params.as_dict())
|
||||
|
||||
|
||||
class PublicAddOneMethod(ContractMethod):
|
||||
class PublicAddOneMethod(ContractMethod): # pylint: disable=invalid-name
|
||||
"""Various interfaces to the publicAddOne method."""
|
||||
|
||||
def __init__(
|
||||
|
@@ -89,6 +89,10 @@
|
||||
{
|
||||
"note": "Fix Uniswap V2 path ordering",
|
||||
"pr": 2601
|
||||
},
|
||||
{
|
||||
"note": "Add exchange proxy support",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -49,6 +49,7 @@
|
||||
"@0x/assert": "^3.0.7",
|
||||
"@0x/contract-addresses": "^4.9.0",
|
||||
"@0x/contract-wrappers": "^13.6.3",
|
||||
"@0x/contracts-zero-ex": "^0.1.0",
|
||||
"@0x/json-schemas": "^5.0.7",
|
||||
"@0x/order-utils": "^10.2.4",
|
||||
"@0x/orderbook": "^2.2.5",
|
||||
@@ -56,6 +57,7 @@
|
||||
"@0x/web3-wrapper": "^7.0.7",
|
||||
"axios": "^0.19.2",
|
||||
"axios-mock-adapter": "^1.18.1",
|
||||
"ethereumjs-util": "^5.1.1",
|
||||
"heartbeats": "^5.0.1",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
|
@@ -60,6 +60,7 @@ export {
|
||||
SwapQuoteConsumerError,
|
||||
SignedOrderWithFillableAmounts,
|
||||
SwapQuoteOrdersBreakdown,
|
||||
ExchangeProxyContractOpts,
|
||||
} from './types';
|
||||
export {
|
||||
ERC20BridgeSource,
|
||||
|
@@ -0,0 +1,211 @@
|
||||
import { ContractAddresses } from '@0x/contract-addresses';
|
||||
import { ITransformERC20Contract } from '@0x/contract-wrappers';
|
||||
import {
|
||||
encodeFillQuoteTransformerData,
|
||||
encodePayTakerTransformerData,
|
||||
encodeWethTransformerData,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
FillQuoteTransformerSide,
|
||||
} from '@0x/contracts-zero-ex';
|
||||
import { assetDataUtils, ERC20AssetData } from '@0x/order-utils';
|
||||
import { AssetProxyId } from '@0x/types';
|
||||
import { BigNumber, providerUtils } from '@0x/utils';
|
||||
import { SupportedProvider, ZeroExProvider } from '@0x/web3-wrapper';
|
||||
import * as ethjs from 'ethereumjs-util';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { constants } from '../constants';
|
||||
import {
|
||||
CalldataInfo,
|
||||
MarketBuySwapQuote,
|
||||
MarketOperation,
|
||||
MarketSellSwapQuote,
|
||||
SwapQuote,
|
||||
SwapQuoteConsumerBase,
|
||||
SwapQuoteConsumerOpts,
|
||||
SwapQuoteExecutionOpts,
|
||||
SwapQuoteGetOutputOpts,
|
||||
} from '../types';
|
||||
import { assert } from '../utils/assert';
|
||||
|
||||
// tslint:disable-next-line:custom-no-magic-numbers
|
||||
const MAX_UINT256 = new BigNumber(2).pow(256).minus(1);
|
||||
const { NULL_ADDRESS } = constants;
|
||||
const MAX_NONCE_GUESSES = 2048;
|
||||
|
||||
export class ExchangeProxySwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
public readonly provider: ZeroExProvider;
|
||||
public readonly chainId: number;
|
||||
public readonly transformerNonces: {
|
||||
wethTransformer: number;
|
||||
payTakerTransformer: number;
|
||||
fillQuoteTransformer: number;
|
||||
};
|
||||
|
||||
private readonly _transformFeature: ITransformERC20Contract;
|
||||
|
||||
constructor(
|
||||
supportedProvider: SupportedProvider,
|
||||
public readonly contractAddresses: ContractAddresses,
|
||||
options: Partial<SwapQuoteConsumerOpts> = {},
|
||||
) {
|
||||
const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||
assert.isNumber('chainId', chainId);
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
this.provider = provider;
|
||||
this.chainId = chainId;
|
||||
this.contractAddresses = contractAddresses;
|
||||
this._transformFeature = new ITransformERC20Contract(contractAddresses.exchangeProxy, supportedProvider);
|
||||
this.transformerNonces = {
|
||||
wethTransformer: findTransformerNonce(
|
||||
contractAddresses.transformers.wethTransformer,
|
||||
contractAddresses.exchangeProxyTransformerDeployer,
|
||||
),
|
||||
payTakerTransformer: findTransformerNonce(
|
||||
contractAddresses.transformers.payTakerTransformer,
|
||||
contractAddresses.exchangeProxyTransformerDeployer,
|
||||
),
|
||||
fillQuoteTransformer: findTransformerNonce(
|
||||
contractAddresses.transformers.fillQuoteTransformer,
|
||||
contractAddresses.exchangeProxyTransformerDeployer,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
public async getCalldataOrThrowAsync(
|
||||
quote: MarketBuySwapQuote | MarketSellSwapQuote,
|
||||
opts: Partial<SwapQuoteGetOutputOpts> = {},
|
||||
): Promise<CalldataInfo> {
|
||||
assert.isValidSwapQuote('quote', quote);
|
||||
const { isFromETH, isToETH } = {
|
||||
...constants.DEFAULT_FORWARDER_SWAP_QUOTE_GET_OPTS,
|
||||
extensionContractOpts: {
|
||||
isFromETH: false,
|
||||
isToETH: false,
|
||||
},
|
||||
...opts,
|
||||
}.extensionContractOpts;
|
||||
|
||||
const sellToken = getTokenFromAssetData(quote.takerAssetData);
|
||||
const buyToken = getTokenFromAssetData(quote.makerAssetData);
|
||||
|
||||
// Build up the transforms.
|
||||
const transforms = [];
|
||||
if (isFromETH) {
|
||||
// Create a WETH wrapper if coming from ETH.
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.wethTransformer,
|
||||
data: encodeWethTransformerData({
|
||||
token: ETH_TOKEN_ADDRESS,
|
||||
amount: quote.worstCaseQuoteInfo.totalTakerAssetAmount,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// This transformer will fill the quote.
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.fillQuoteTransformer,
|
||||
data: encodeFillQuoteTransformerData({
|
||||
sellToken,
|
||||
buyToken,
|
||||
side: isBuyQuote(quote) ? FillQuoteTransformerSide.Buy : FillQuoteTransformerSide.Sell,
|
||||
fillAmount: isBuyQuote(quote) ? quote.makerAssetFillAmount : quote.takerAssetFillAmount,
|
||||
maxOrderFillAmounts: [],
|
||||
orders: quote.orders,
|
||||
signatures: quote.orders.map(o => o.signature),
|
||||
}),
|
||||
});
|
||||
|
||||
if (isToETH) {
|
||||
// Create a WETH unwrapper if going to ETH.
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.wethTransformer,
|
||||
data: encodeWethTransformerData({
|
||||
token: this.contractAddresses.etherToken,
|
||||
amount: MAX_UINT256,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// The final transformer will send all funds to the taker.
|
||||
transforms.push({
|
||||
deploymentNonce: this.transformerNonces.payTakerTransformer,
|
||||
data: encodePayTakerTransformerData({
|
||||
tokens: [sellToken, buyToken, ETH_TOKEN_ADDRESS],
|
||||
amounts: [],
|
||||
}),
|
||||
});
|
||||
|
||||
const calldataHexString = this._transformFeature
|
||||
.transformERC20(
|
||||
isFromETH ? ETH_TOKEN_ADDRESS : sellToken,
|
||||
isToETH ? ETH_TOKEN_ADDRESS : buyToken,
|
||||
quote.worstCaseQuoteInfo.totalTakerAssetAmount,
|
||||
quote.worstCaseQuoteInfo.makerAssetAmount,
|
||||
transforms,
|
||||
)
|
||||
.getABIEncodedTransactionData();
|
||||
|
||||
let ethAmount = quote.worstCaseQuoteInfo.protocolFeeInWeiAmount;
|
||||
if (isFromETH) {
|
||||
ethAmount = ethAmount.plus(quote.worstCaseQuoteInfo.takerAssetAmount);
|
||||
}
|
||||
|
||||
return {
|
||||
calldataHexString,
|
||||
ethAmount,
|
||||
toAddress: this._transformFeature.address,
|
||||
allowanceTarget: this.contractAddresses.exchangeProxyAllowanceTarget,
|
||||
};
|
||||
}
|
||||
|
||||
// tslint:disable-next-line:prefer-function-over-method
|
||||
public async executeSwapQuoteOrThrowAsync(
|
||||
_quote: SwapQuote,
|
||||
_opts: Partial<SwapQuoteExecutionOpts>,
|
||||
): Promise<string> {
|
||||
throw new Error('Execution not supported for Exchange Proxy quotes');
|
||||
}
|
||||
}
|
||||
|
||||
function isBuyQuote(quote: SwapQuote): quote is MarketBuySwapQuote {
|
||||
return quote.type === MarketOperation.Buy;
|
||||
}
|
||||
|
||||
function getTokenFromAssetData(assetData: string): string {
|
||||
const data = assetDataUtils.decodeAssetDataOrThrow(assetData);
|
||||
if (data.assetProxyId !== AssetProxyId.ERC20) {
|
||||
throw new Error(`Unsupported exchange proxy quote asset type: ${data.assetProxyId}`);
|
||||
}
|
||||
// tslint:disable-next-line:no-unnecessary-type-assertion
|
||||
return (data as ERC20AssetData).tokenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the nonce for a transformer given its deployer.
|
||||
* If `deployer` is the null address, zero will always be returned.
|
||||
*/
|
||||
export function findTransformerNonce(transformer: string, deployer: string = NULL_ADDRESS): number {
|
||||
if (deployer === NULL_ADDRESS) {
|
||||
return 0;
|
||||
}
|
||||
const lowercaseTransformer = transformer.toLowerCase();
|
||||
// Try to guess the nonce.
|
||||
for (let nonce = 0; nonce < MAX_NONCE_GUESSES; ++nonce) {
|
||||
const deployedAddress = getTransformerAddress(deployer, nonce);
|
||||
if (deployedAddress === lowercaseTransformer) {
|
||||
return nonce;
|
||||
}
|
||||
}
|
||||
throw new Error(`${deployer} did not deploy ${transformer}!`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the deployed address for a transformer given a deployer and nonce.
|
||||
*/
|
||||
export function getTransformerAddress(deployer: string, nonce: number): string {
|
||||
return ethjs.bufferToHex(
|
||||
// tslint:disable-next-line: custom-no-magic-numbers
|
||||
ethjs.rlphash([deployer, nonce] as any).slice(12),
|
||||
);
|
||||
}
|
@@ -25,7 +25,7 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
|
||||
constructor(
|
||||
supportedProvider: SupportedProvider,
|
||||
contractAddresses: ContractAddresses,
|
||||
public readonly contractAddresses: ContractAddresses,
|
||||
options: Partial<SwapQuoteConsumerOpts> = {},
|
||||
) {
|
||||
const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||
@@ -59,6 +59,7 @@ export class ExchangeSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
calldataHexString,
|
||||
ethAmount: quote.worstCaseQuoteInfo.protocolFeeInWeiAmount,
|
||||
toAddress: this._exchangeContract.address,
|
||||
allowanceTarget: this.contractAddresses.erc20Proxy,
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -19,16 +19,17 @@ import { affiliateFeeUtils } from '../utils/affiliate_fee_utils';
|
||||
import { assert } from '../utils/assert';
|
||||
import { swapQuoteConsumerUtils } from '../utils/swap_quote_consumer_utils';
|
||||
|
||||
const { NULL_ADDRESS } = constants;
|
||||
|
||||
export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
public readonly provider: ZeroExProvider;
|
||||
public readonly chainId: number;
|
||||
|
||||
private readonly _contractAddresses: ContractAddresses;
|
||||
private readonly _forwarder: ForwarderContract;
|
||||
|
||||
constructor(
|
||||
supportedProvider: SupportedProvider,
|
||||
contractAddresses: ContractAddresses,
|
||||
public readonly contractAddresses: ContractAddresses,
|
||||
options: Partial<SwapQuoteConsumerOpts> = {},
|
||||
) {
|
||||
const { chainId } = _.merge({}, constants.DEFAULT_SWAP_QUOTER_OPTS, options);
|
||||
@@ -36,7 +37,6 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
this.provider = provider;
|
||||
this.chainId = chainId;
|
||||
this._contractAddresses = contractAddresses;
|
||||
this._forwarder = new ForwarderContract(contractAddresses.forwarder, supportedProvider);
|
||||
}
|
||||
|
||||
@@ -90,6 +90,7 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
calldataHexString,
|
||||
toAddress: this._forwarder.address,
|
||||
ethAmount: ethAmountWithFees,
|
||||
allowanceTarget: NULL_ADDRESS,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,6 +161,6 @@ export class ForwarderSwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
}
|
||||
|
||||
private _getEtherTokenAssetDataOrThrow(): string {
|
||||
return assetDataUtils.encodeERC20AssetData(this._contractAddresses.etherToken);
|
||||
return assetDataUtils.encodeERC20AssetData(this.contractAddresses.etherToken);
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import {
|
||||
import { assert } from '../utils/assert';
|
||||
import { swapQuoteConsumerUtils } from '../utils/swap_quote_consumer_utils';
|
||||
|
||||
import { ExchangeProxySwapQuoteConsumer } from './exchange_proxy_swap_quote_consumer';
|
||||
import { ExchangeSwapQuoteConsumer } from './exchange_swap_quote_consumer';
|
||||
import { ForwarderSwapQuoteConsumer } from './forwarder_swap_quote_consumer';
|
||||
|
||||
@@ -27,6 +28,7 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
private readonly _exchangeConsumer: ExchangeSwapQuoteConsumer;
|
||||
private readonly _forwarderConsumer: ForwarderSwapQuoteConsumer;
|
||||
private readonly _contractAddresses: ContractAddresses;
|
||||
private readonly _exchangeProxyConsumer: ExchangeProxySwapQuoteConsumer;
|
||||
|
||||
public static getSwapQuoteConsumer(
|
||||
supportedProvider: SupportedProvider,
|
||||
@@ -45,6 +47,11 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
this._contractAddresses = options.contractAddresses || getContractAddressesForChainOrThrow(chainId);
|
||||
this._exchangeConsumer = new ExchangeSwapQuoteConsumer(supportedProvider, this._contractAddresses, options);
|
||||
this._forwarderConsumer = new ForwarderSwapQuoteConsumer(supportedProvider, this._contractAddresses, options);
|
||||
this._exchangeProxyConsumer = new ExchangeProxySwapQuoteConsumer(
|
||||
supportedProvider,
|
||||
this._contractAddresses,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,9 +100,13 @@ export class SwapQuoteConsumer implements SwapQuoteConsumerBase {
|
||||
}
|
||||
|
||||
private async _getConsumerForSwapQuoteAsync(opts: Partial<SwapQuoteGetOutputOpts>): Promise<SwapQuoteConsumerBase> {
|
||||
if (opts.useExtensionContract === ExtensionContractType.Forwarder) {
|
||||
switch (opts.useExtensionContract) {
|
||||
case ExtensionContractType.Forwarder:
|
||||
return this._forwarderConsumer;
|
||||
}
|
||||
case ExtensionContractType.ExchangeProxy:
|
||||
return this._exchangeProxyConsumer;
|
||||
default:
|
||||
return this._exchangeConsumer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,19 +50,22 @@ export interface SignedOrderWithFillableAmounts extends SignedOrder {
|
||||
* calldataHexString: The hexstring of the calldata.
|
||||
* toAddress: The contract address to call.
|
||||
* ethAmount: The eth amount in wei to send with the smart contract call.
|
||||
* allowanceTarget: The address the taker should grant an allowance to.
|
||||
*/
|
||||
export interface CalldataInfo {
|
||||
calldataHexString: string;
|
||||
toAddress: string;
|
||||
ethAmount: BigNumber;
|
||||
allowanceTarget: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the varying smart contracts that can consume a valid swap quote
|
||||
*/
|
||||
export enum ExtensionContractType {
|
||||
Forwarder = 'FORWARDER',
|
||||
None = 'NONE',
|
||||
Forwarder = 'FORWARDER',
|
||||
ExchangeProxy = 'EXCHANGE_PROXY',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +100,7 @@ export interface SwapQuoteConsumerOpts {
|
||||
*/
|
||||
export interface SwapQuoteGetOutputOpts {
|
||||
useExtensionContract: ExtensionContractType;
|
||||
extensionContractOpts?: ForwarderExtensionContractOpts | any;
|
||||
extensionContractOpts?: ForwarderExtensionContractOpts | ExchangeProxyContractOpts | any;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +115,6 @@ export interface SwapQuoteExecutionOpts extends SwapQuoteGetOutputOpts {
|
||||
}
|
||||
|
||||
/**
|
||||
* ethAmount: The amount of eth (in Wei) sent to the forwarder contract.
|
||||
* feePercentage: percentage (up to 5%) of the taker asset paid to feeRecipient
|
||||
* feeRecipient: address of the receiver of the feePercentage of taker asset
|
||||
*/
|
||||
@@ -121,6 +123,15 @@ export interface ForwarderExtensionContractOpts {
|
||||
feeRecipient: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isFromETH Whether the input token is ETH.
|
||||
* @param isToETH Whether the output token is ETH.
|
||||
*/
|
||||
export interface ExchangeProxyContractOpts {
|
||||
isFromETH: boolean;
|
||||
isToETH: boolean;
|
||||
}
|
||||
|
||||
export type SwapQuote = MarketBuySwapQuote | MarketSellSwapQuote;
|
||||
|
||||
export interface GetExtensionContractTypeOpts {
|
||||
|
@@ -0,0 +1,268 @@
|
||||
import { getContractAddressesForChainOrThrow } from '@0x/contract-addresses';
|
||||
import { constants as contractConstants, getRandomInteger, Numberish, randomAddress } from '@0x/contracts-test-utils';
|
||||
import {
|
||||
decodeFillQuoteTransformerData,
|
||||
decodePayTakerTransformerData,
|
||||
decodeWethTransformerData,
|
||||
ETH_TOKEN_ADDRESS,
|
||||
FillQuoteTransformerSide,
|
||||
} from '@0x/contracts-zero-ex';
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { Order } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber, hexUtils } from '@0x/utils';
|
||||
import * as chai from 'chai';
|
||||
import * as _ from 'lodash';
|
||||
import 'mocha';
|
||||
|
||||
import { constants } from '../src/constants';
|
||||
import {
|
||||
ExchangeProxySwapQuoteConsumer,
|
||||
getTransformerAddress,
|
||||
} from '../src/quote_consumers/exchange_proxy_swap_quote_consumer';
|
||||
import { MarketBuySwapQuote, MarketOperation, MarketSellSwapQuote } from '../src/types';
|
||||
import { OptimizedMarketOrder } from '../src/utils/market_operation_utils/types';
|
||||
|
||||
import { chaiSetup } from './utils/chai_setup';
|
||||
|
||||
chaiSetup.configure();
|
||||
const expect = chai.expect;
|
||||
|
||||
const { NULL_ADDRESS } = constants;
|
||||
const { MAX_UINT256 } = contractConstants;
|
||||
|
||||
// tslint:disable: custom-no-magic-numbers
|
||||
|
||||
describe('ExchangeProxySwapQuoteConsumer', () => {
|
||||
const CHAIN_ID = 1;
|
||||
const TAKER_TOKEN = randomAddress();
|
||||
const MAKER_TOKEN = randomAddress();
|
||||
const TRANSFORMER_DEPLOYER = randomAddress();
|
||||
const contractAddresses = {
|
||||
...getContractAddressesForChainOrThrow(CHAIN_ID),
|
||||
exchangeProxy: randomAddress(),
|
||||
exchangeProxyAllowanceTarget: randomAddress(),
|
||||
exchangeProxyTransformerDeployer: TRANSFORMER_DEPLOYER,
|
||||
transformers: {
|
||||
wethTransformer: getTransformerAddress(TRANSFORMER_DEPLOYER, 1),
|
||||
payTakerTransformer: getTransformerAddress(TRANSFORMER_DEPLOYER, 2),
|
||||
fillQuoteTransformer: getTransformerAddress(TRANSFORMER_DEPLOYER, 3),
|
||||
},
|
||||
};
|
||||
let consumer: ExchangeProxySwapQuoteConsumer;
|
||||
|
||||
before(async () => {
|
||||
const fakeProvider = {
|
||||
async sendAsync(): Promise<void> {
|
||||
/* noop */
|
||||
},
|
||||
};
|
||||
consumer = new ExchangeProxySwapQuoteConsumer(fakeProvider, contractAddresses, { chainId: CHAIN_ID });
|
||||
});
|
||||
|
||||
function getRandomAmount(maxAmount: Numberish = '1e18'): BigNumber {
|
||||
return getRandomInteger(1, maxAmount);
|
||||
}
|
||||
|
||||
function createAssetData(token?: string): string {
|
||||
return assetDataUtils.encodeERC20AssetData(token || randomAddress());
|
||||
}
|
||||
|
||||
function getRandomOrder(): OptimizedMarketOrder {
|
||||
return {
|
||||
fillableMakerAssetAmount: getRandomAmount(),
|
||||
fillableTakerFeeAmount: getRandomAmount(),
|
||||
fillableTakerAssetAmount: getRandomAmount(),
|
||||
fills: [],
|
||||
chainId: CHAIN_ID,
|
||||
exchangeAddress: contractAddresses.exchange,
|
||||
expirationTimeSeconds: getRandomInteger(1, 2e9),
|
||||
feeRecipientAddress: randomAddress(),
|
||||
makerAddress: randomAddress(),
|
||||
makerAssetAmount: getRandomAmount(),
|
||||
takerAssetAmount: getRandomAmount(),
|
||||
makerFee: getRandomAmount(),
|
||||
takerFee: getRandomAmount(),
|
||||
salt: getRandomAmount(2e9),
|
||||
signature: hexUtils.random(66),
|
||||
senderAddress: NULL_ADDRESS,
|
||||
takerAddress: NULL_ADDRESS,
|
||||
makerAssetData: createAssetData(MAKER_TOKEN),
|
||||
takerAssetData: createAssetData(TAKER_TOKEN),
|
||||
makerFeeAssetData: createAssetData(),
|
||||
takerFeeAssetData: createAssetData(),
|
||||
};
|
||||
}
|
||||
|
||||
function getRandomQuote(side: MarketOperation): MarketBuySwapQuote | MarketSellSwapQuote {
|
||||
return {
|
||||
gasPrice: getRandomInteger(1, 1e9),
|
||||
type: side,
|
||||
makerAssetData: createAssetData(MAKER_TOKEN),
|
||||
takerAssetData: createAssetData(TAKER_TOKEN),
|
||||
orders: [getRandomOrder()],
|
||||
bestCaseQuoteInfo: {
|
||||
feeTakerAssetAmount: getRandomAmount(),
|
||||
makerAssetAmount: getRandomAmount(),
|
||||
gas: Math.floor(Math.random() * 8e6),
|
||||
protocolFeeInWeiAmount: getRandomAmount(),
|
||||
takerAssetAmount: getRandomAmount(),
|
||||
totalTakerAssetAmount: getRandomAmount(),
|
||||
},
|
||||
worstCaseQuoteInfo: {
|
||||
feeTakerAssetAmount: getRandomAmount(),
|
||||
makerAssetAmount: getRandomAmount(),
|
||||
gas: Math.floor(Math.random() * 8e6),
|
||||
protocolFeeInWeiAmount: getRandomAmount(),
|
||||
takerAssetAmount: getRandomAmount(),
|
||||
totalTakerAssetAmount: getRandomAmount(),
|
||||
},
|
||||
...(side === MarketOperation.Buy
|
||||
? { makerAssetFillAmount: getRandomAmount() }
|
||||
: { takerAssetFillAmount: getRandomAmount() }),
|
||||
} as any;
|
||||
}
|
||||
|
||||
function getRandomSellQuote(): MarketSellSwapQuote {
|
||||
return getRandomQuote(MarketOperation.Sell) as MarketSellSwapQuote;
|
||||
}
|
||||
|
||||
function getRandomBuyQuote(): MarketBuySwapQuote {
|
||||
return getRandomQuote(MarketOperation.Buy) as MarketBuySwapQuote;
|
||||
}
|
||||
|
||||
type PlainOrder = Exclude<Order, ['chainId', 'exchangeAddress']>;
|
||||
|
||||
function cleanOrders(orders: OptimizedMarketOrder[]): PlainOrder[] {
|
||||
return orders.map(
|
||||
o =>
|
||||
_.omit(o, [
|
||||
'chainId',
|
||||
'exchangeAddress',
|
||||
'fillableMakerAssetAmount',
|
||||
'fillableTakerAssetAmount',
|
||||
'fillableTakerFeeAmount',
|
||||
'fills',
|
||||
'signature',
|
||||
]) as PlainOrder,
|
||||
);
|
||||
}
|
||||
|
||||
const callDataEncoder = AbiEncoder.createMethod('transformERC20', [
|
||||
{ type: 'address', name: 'inputToken' },
|
||||
{ type: 'address', name: 'outputToken' },
|
||||
{ type: 'uint256', name: 'inputTokenAmount' },
|
||||
{ type: 'uint256', name: 'minOutputTokenAmount' },
|
||||
{
|
||||
type: 'tuple[]',
|
||||
name: 'transformations',
|
||||
components: [{ type: 'uint32', name: 'deploymentNonce' }, { type: 'bytes', name: 'data' }],
|
||||
},
|
||||
]);
|
||||
|
||||
interface CallArgs {
|
||||
inputToken: string;
|
||||
outputToken: string;
|
||||
inputTokenAmount: BigNumber;
|
||||
minOutputTokenAmount: BigNumber;
|
||||
transformations: Array<{
|
||||
deploymentNonce: BigNumber;
|
||||
data: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
describe('getCalldataOrThrow()', () => {
|
||||
it('can produce a sell quote', async () => {
|
||||
const quote = getRandomSellQuote();
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
||||
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
||||
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||
expect(callArgs.minOutputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.makerAssetAmount);
|
||||
expect(callArgs.transformations).to.be.length(2);
|
||||
expect(
|
||||
callArgs.transformations[0].deploymentNonce.toNumber() ===
|
||||
consumer.transformerNonces.fillQuoteTransformer,
|
||||
);
|
||||
expect(
|
||||
callArgs.transformations[1].deploymentNonce.toNumber() ===
|
||||
consumer.transformerNonces.payTakerTransformer,
|
||||
);
|
||||
const fillQuoteTransformerData = decodeFillQuoteTransformerData(callArgs.transformations[0].data);
|
||||
expect(fillQuoteTransformerData.side).to.eq(FillQuoteTransformerSide.Sell);
|
||||
expect(fillQuoteTransformerData.fillAmount).to.bignumber.eq(quote.takerAssetFillAmount);
|
||||
expect(fillQuoteTransformerData.orders).to.deep.eq(cleanOrders(quote.orders));
|
||||
expect(fillQuoteTransformerData.signatures).to.deep.eq(quote.orders.map(o => o.signature));
|
||||
expect(fillQuoteTransformerData.sellToken).to.eq(TAKER_TOKEN);
|
||||
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
|
||||
it('can produce a buy quote', async () => {
|
||||
const quote = getRandomBuyQuote();
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
||||
expect(callArgs.inputToken).to.eq(TAKER_TOKEN);
|
||||
expect(callArgs.outputToken).to.eq(MAKER_TOKEN);
|
||||
expect(callArgs.inputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||
expect(callArgs.minOutputTokenAmount).to.bignumber.eq(quote.worstCaseQuoteInfo.makerAssetAmount);
|
||||
expect(callArgs.transformations).to.be.length(2);
|
||||
expect(
|
||||
callArgs.transformations[0].deploymentNonce.toNumber() ===
|
||||
consumer.transformerNonces.fillQuoteTransformer,
|
||||
);
|
||||
expect(
|
||||
callArgs.transformations[1].deploymentNonce.toNumber() ===
|
||||
consumer.transformerNonces.payTakerTransformer,
|
||||
);
|
||||
const fillQuoteTransformerData = decodeFillQuoteTransformerData(callArgs.transformations[0].data);
|
||||
expect(fillQuoteTransformerData.side).to.eq(FillQuoteTransformerSide.Buy);
|
||||
expect(fillQuoteTransformerData.fillAmount).to.bignumber.eq(quote.makerAssetFillAmount);
|
||||
expect(fillQuoteTransformerData.orders).to.deep.eq(cleanOrders(quote.orders));
|
||||
expect(fillQuoteTransformerData.signatures).to.deep.eq(quote.orders.map(o => o.signature));
|
||||
expect(fillQuoteTransformerData.sellToken).to.eq(TAKER_TOKEN);
|
||||
expect(fillQuoteTransformerData.buyToken).to.eq(MAKER_TOKEN);
|
||||
const payTakerTransformerData = decodePayTakerTransformerData(callArgs.transformations[1].data);
|
||||
expect(payTakerTransformerData.amounts).to.deep.eq([]);
|
||||
expect(payTakerTransformerData.tokens).to.deep.eq([TAKER_TOKEN, MAKER_TOKEN, ETH_TOKEN_ADDRESS]);
|
||||
});
|
||||
|
||||
it('ERC20 -> ERC20 does not have a WETH transformer', async () => {
|
||||
const quote = getRandomSellQuote();
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote);
|
||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
||||
const nonces = callArgs.transformations.map(t => t.deploymentNonce);
|
||||
expect(nonces).to.not.include(consumer.transformerNonces.wethTransformer);
|
||||
});
|
||||
|
||||
it('ETH -> ERC20 has a WETH transformer before the fill', async () => {
|
||||
const quote = getRandomSellQuote();
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
extensionContractOpts: { isFromETH: true },
|
||||
});
|
||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
||||
expect(callArgs.transformations[0].deploymentNonce.toNumber()).to.eq(
|
||||
consumer.transformerNonces.wethTransformer,
|
||||
);
|
||||
const wethTransformerData = decodeWethTransformerData(callArgs.transformations[0].data);
|
||||
expect(wethTransformerData.amount).to.bignumber.eq(quote.worstCaseQuoteInfo.totalTakerAssetAmount);
|
||||
expect(wethTransformerData.token).to.eq(ETH_TOKEN_ADDRESS);
|
||||
});
|
||||
|
||||
it('ERC20 -> ETH has a WETH transformer after the fill', async () => {
|
||||
const quote = getRandomSellQuote();
|
||||
const callInfo = await consumer.getCalldataOrThrowAsync(quote, {
|
||||
extensionContractOpts: { isToETH: true },
|
||||
});
|
||||
const callArgs = callDataEncoder.decode(callInfo.calldataHexString) as CallArgs;
|
||||
expect(callArgs.transformations[1].deploymentNonce.toNumber()).to.eq(
|
||||
consumer.transformerNonces.wethTransformer,
|
||||
);
|
||||
const wethTransformerData = decodeWethTransformerData(callArgs.transformations[1].data);
|
||||
expect(wethTransformerData.amount).to.bignumber.eq(MAX_UINT256);
|
||||
expect(wethTransformerData.token).to.eq(contractAddresses.etherToken);
|
||||
});
|
||||
});
|
||||
});
|
@@ -65,6 +65,10 @@
|
||||
{
|
||||
"note": "Add UniswapV2Bridge address on Mainnet (new field)",
|
||||
"pr": 2599
|
||||
},
|
||||
{
|
||||
"note": "Add Exchange Proxy addresses",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -32,7 +32,16 @@
|
||||
"curveBridge": "0x6dc7950423ada9f56fb2c93a23edb787f1e29088",
|
||||
"maximumGasPrice": "0xe2bfd35306495d11e3c9db0d8de390cda24563cf",
|
||||
"dexForwarderBridge": "0x5591360f8c7640fea5771c9682d6b5ecb776e1f8",
|
||||
"multiBridge": "0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1"
|
||||
"multiBridge": "0xc03117a8c9bde203f70aa911cb64a7a0df5ba1e1",
|
||||
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x80a36559ab9a497fb658325ed771a584eb0f13da",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x7bab5f7299e1ca123bb44eb71e6c89be7e558cc8",
|
||||
"payTakerTransformer": "0xe8c07a119452b55eee2f999478aab97f3656d841",
|
||||
"fillQuoteTransformer": "0x9b81a08ef144e7aa4925f7fd77da1e1b3990e59a"
|
||||
}
|
||||
},
|
||||
"3": {
|
||||
"erc20Proxy": "0xb1408f4c245a23c31b98d2c626777d4c0d766caa",
|
||||
@@ -67,7 +76,16 @@
|
||||
"curveBridge": "0x0000000000000000000000000000000000000000",
|
||||
"maximumGasPrice": "0x407b4128e9ecad8769b2332312a9f655cb9f5f3a",
|
||||
"dexForwarderBridge": "0x3be8e59038d8c4e8d8776ca40ef2f024bad95ad1",
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000"
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000",
|
||||
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x80a36559ab9a497fb658325ed771a584eb0f13da",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x7bab5f7299e1ca123bb44eb71e6c89be7e558cc8",
|
||||
"payTakerTransformer": "0xe8c07a119452b55eee2f999478aab97f3656d841",
|
||||
"fillQuoteTransformer": "0x9b81a08ef144e7aa4925f7fd77da1e1b3990e59a"
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"exchangeV2": "0xbff9493f92a3df4b0429b6d00743b3cfb4c85831",
|
||||
@@ -102,7 +120,16 @@
|
||||
"curveBridge": "0x0000000000000000000000000000000000000000",
|
||||
"maximumGasPrice": "0x47697b44bd89051e93b4d5857ba8e024800a74ac",
|
||||
"dexForwarderBridge": "0x0000000000000000000000000000000000000000",
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000"
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000",
|
||||
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x80a36559ab9a497fb658325ed771a584eb0f13da",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x7bab5f7299e1ca123bb44eb71e6c89be7e558cc8",
|
||||
"payTakerTransformer": "0xe8c07a119452b55eee2f999478aab97f3656d841",
|
||||
"fillQuoteTransformer": "0x9b81a08ef144e7aa4925f7fd77da1e1b3990e59a"
|
||||
}
|
||||
},
|
||||
"42": {
|
||||
"erc20Proxy": "0xf1ec01d6236d3cd881a0bf0130ea25fe4234003e",
|
||||
@@ -137,7 +164,16 @@
|
||||
"curveBridge": "0x90c62c91a9f655f4f739e6cee85c84f9ccf47323",
|
||||
"maximumGasPrice": "0x67a094cf028221ffdd93fc658f963151d05e2a74",
|
||||
"dexForwarderBridge": "0x6cce442a48ab07635462a40594054f34f44195ff",
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000"
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000",
|
||||
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x80a36559ab9a497fb658325ed771a584eb0f13da",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x7bab5f7299e1ca123bb44eb71e6c89be7e558cc8",
|
||||
"payTakerTransformer": "0xe8c07a119452b55eee2f999478aab97f3656d841",
|
||||
"fillQuoteTransformer": "0x9b81a08ef144e7aa4925f7fd77da1e1b3990e59a"
|
||||
}
|
||||
},
|
||||
"1337": {
|
||||
"erc20Proxy": "0x1dc4c1cefef38a777b15aa20260a54e584b16c48",
|
||||
@@ -172,6 +208,15 @@
|
||||
"curveBridge": "0x0000000000000000000000000000000000000000",
|
||||
"maximumGasPrice": "0x0000000000000000000000000000000000000000",
|
||||
"dexForwarderBridge": "0x0000000000000000000000000000000000000000",
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000"
|
||||
"multiBridge": "0x0000000000000000000000000000000000000000",
|
||||
"exchangeProxyGovernor": "0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e",
|
||||
"exchangeProxy": "0xdef1c0ded9bec7f1a1670819833240f027b25eff",
|
||||
"exchangeProxyAllowanceTarget": "0xf740b67da229f2f10bcbd38a7979992fcc71b8eb",
|
||||
"exchangeProxyTransformerDeployer": "0x80a36559ab9a497fb658325ed771a584eb0f13da",
|
||||
"transformers": {
|
||||
"wethTransformer": "0x7bab5f7299e1ca123bb44eb71e6c89be7e558cc8",
|
||||
"payTakerTransformer": "0xe8c07a119452b55eee2f999478aab97f3656d841",
|
||||
"fillQuoteTransformer": "0x9b81a08ef144e7aa4925f7fd77da1e1b3990e59a"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,6 +34,15 @@ export interface ContractAddresses {
|
||||
maximumGasPrice: string;
|
||||
dexForwarderBridge: string;
|
||||
multiBridge: string;
|
||||
exchangeProxyGovernor: string;
|
||||
exchangeProxy: string;
|
||||
exchangeProxyAllowanceTarget: string;
|
||||
exchangeProxyTransformerDeployer: string;
|
||||
transformers: {
|
||||
wethTransformer: string;
|
||||
payTakerTransformer: string;
|
||||
fillQuoteTransformer: string;
|
||||
};
|
||||
}
|
||||
|
||||
export enum ChainId {
|
||||
|
@@ -29,6 +29,10 @@
|
||||
{
|
||||
"note": "Added `ERC20BridgeSampler.sampleSellsFromMultiBridge",
|
||||
"pr": 2593
|
||||
},
|
||||
{
|
||||
"note": "Added `ITransformERC20`",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
171
packages/contract-artifacts/artifacts/ITransformERC20.json
generated
Normal file
171
packages/contract-artifacts/artifacts/ITransformERC20.json
generated
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"schemaVersion": "2.0.0",
|
||||
"contractName": "ITransformERC20",
|
||||
"compilerOutput": {
|
||||
"abi": [
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": true, "internalType": "address", "name": "taker", "type": "address" },
|
||||
{ "indexed": false, "internalType": "address", "name": "inputToken", "type": "address" },
|
||||
{ "indexed": false, "internalType": "address", "name": "outputToken", "type": "address" },
|
||||
{ "indexed": false, "internalType": "uint256", "name": "inputTokenAmount", "type": "uint256" },
|
||||
{ "indexed": false, "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }
|
||||
],
|
||||
"name": "TransformedERC20",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"anonymous": false,
|
||||
"inputs": [
|
||||
{ "indexed": false, "internalType": "address", "name": "transformerDeployer", "type": "address" }
|
||||
],
|
||||
"name": "TransformerDeployerUpdated",
|
||||
"type": "event"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "bytes32", "name": "callDataHash", "type": "bytes32" },
|
||||
{ "internalType": "address payable", "name": "taker", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "inputTokenAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minOutputTokenAmount", "type": "uint256" },
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20.Transformation[]",
|
||||
"name": "transformations",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"name": "_transformERC20",
|
||||
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "createTransformWallet",
|
||||
"outputs": [{ "internalType": "contract IFlashWallet", "name": "wallet", "type": "address" }],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "getTransformWallet",
|
||||
"outputs": [{ "internalType": "contract IFlashWallet", "name": "wallet", "type": "address" }],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [],
|
||||
"name": "getTransformerDeployer",
|
||||
"outputs": [{ "internalType": "address", "name": "deployer", "type": "address" }],
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [{ "internalType": "address", "name": "transformerDeployer", "type": "address" }],
|
||||
"name": "setTransformerDeployer",
|
||||
"outputs": [],
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"inputs": [
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "inputToken", "type": "address" },
|
||||
{ "internalType": "contract IERC20TokenV06", "name": "outputToken", "type": "address" },
|
||||
{ "internalType": "uint256", "name": "inputTokenAmount", "type": "uint256" },
|
||||
{ "internalType": "uint256", "name": "minOutputTokenAmount", "type": "uint256" },
|
||||
{
|
||||
"components": [
|
||||
{ "internalType": "uint32", "name": "deploymentNonce", "type": "uint32" },
|
||||
{ "internalType": "bytes", "name": "data", "type": "bytes" }
|
||||
],
|
||||
"internalType": "struct ITransformERC20.Transformation[]",
|
||||
"name": "transformations",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"name": "transformERC20",
|
||||
"outputs": [{ "internalType": "uint256", "name": "outputTokenAmount", "type": "uint256" }],
|
||||
"stateMutability": "payable",
|
||||
"type": "function"
|
||||
}
|
||||
],
|
||||
"devdoc": {
|
||||
"details": "Feature to composably transform between ERC20 tokens.",
|
||||
"methods": {
|
||||
"_transformERC20(bytes32,address,address,address,uint256,uint256,(uint32,bytes)[])": {
|
||||
"details": "Internal version of `transformERC20()`. Only callable from within.",
|
||||
"params": {
|
||||
"callDataHash": "Hash of the ingress calldata.",
|
||||
"inputToken": "The token being provided by the taker. If `0xeee...`, ETH is implied and should be provided with the call.`",
|
||||
"inputTokenAmount": "The amount of `inputToken` to take from the taker.",
|
||||
"minOutputTokenAmount": "The minimum amount of `outputToken` the taker must receive for the entire transformation to succeed.",
|
||||
"outputToken": "The token to be acquired by the taker. `0xeee...` implies ETH.",
|
||||
"taker": "The taker address.",
|
||||
"transformations": "The transformations to execute on the token balance(s) in sequence."
|
||||
},
|
||||
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the taker." }
|
||||
},
|
||||
"createTransformWallet()": {
|
||||
"details": "Deploy a new flash wallet instance and replace the current one with it. Useful if we somehow break the current wallet instance. Anyone can call this.",
|
||||
"returns": { "wallet": "The new wallet instance." }
|
||||
},
|
||||
"getTransformWallet()": {
|
||||
"details": "Return the current wallet instance that will serve as the execution context for transformations.",
|
||||
"returns": { "wallet": "The wallet instance." }
|
||||
},
|
||||
"getTransformerDeployer()": {
|
||||
"details": "Return the allowed deployer for transformers.",
|
||||
"returns": { "deployer": "The transform deployer address." }
|
||||
},
|
||||
"setTransformerDeployer(address)": {
|
||||
"details": "Replace the allowed deployer for transformers. Only callable by the owner.",
|
||||
"params": { "transformerDeployer": "The address of the trusted deployer for transformers." }
|
||||
},
|
||||
"transformERC20(address,address,uint256,uint256,(uint32,bytes)[])": {
|
||||
"details": "Executes a series of transformations to convert an ERC20 `inputToken` to an ERC20 `outputToken`.",
|
||||
"params": {
|
||||
"inputToken": "The token being provided by the sender. If `0xeee...`, ETH is implied and should be provided with the call.`",
|
||||
"inputTokenAmount": "The amount of `inputToken` to take from the sender.",
|
||||
"minOutputTokenAmount": "The minimum amount of `outputToken` the sender must receive for the entire transformation to succeed.",
|
||||
"outputToken": "The token to be acquired by the sender. `0xeee...` implies ETH.",
|
||||
"transformations": "The transformations to execute on the token balance(s) in sequence."
|
||||
},
|
||||
"returns": { "outputTokenAmount": "The amount of `outputToken` received by the sender." }
|
||||
}
|
||||
}
|
||||
},
|
||||
"evm": { "bytecode": { "object": "0x" }, "deployedBytecode": { "immutableReferences": {}, "object": "0x" } }
|
||||
},
|
||||
"compiler": {
|
||||
"name": "solc",
|
||||
"version": "0.6.9+commit.3e3065ac",
|
||||
"settings": {
|
||||
"optimizer": {
|
||||
"enabled": true,
|
||||
"runs": 1000000,
|
||||
"details": { "yul": true, "deduplicate": true, "cse": true, "constantOptimizer": true }
|
||||
},
|
||||
"outputSelection": {
|
||||
"*": {
|
||||
"*": [
|
||||
"abi",
|
||||
"devdoc",
|
||||
"evm.bytecode.object",
|
||||
"evm.bytecode.sourceMap",
|
||||
"evm.deployedBytecode.object",
|
||||
"evm.deployedBytecode.sourceMap"
|
||||
]
|
||||
}
|
||||
},
|
||||
"evmVersion": "istanbul"
|
||||
}
|
||||
},
|
||||
"chains": {}
|
||||
}
|
@@ -26,6 +26,7 @@ import * as ZRXToken from '../artifacts/ZRXToken.json';
|
||||
import * as ERC20BridgeProxy from '../artifacts/ERC20BridgeProxy.json';
|
||||
import * as ZrxVault from '../artifacts/ZrxVault.json';
|
||||
import * as IERC20BridgeSampler from '../artifacts/IERC20BridgeSampler.json';
|
||||
import * as ITransformERC20 from '../artifacts/ITransformERC20.json';
|
||||
|
||||
export {
|
||||
AssetProxyOwner,
|
||||
@@ -56,4 +57,5 @@ export {
|
||||
StakingProxy,
|
||||
ZrxVault,
|
||||
IERC20BridgeSampler,
|
||||
ITransformERC20,
|
||||
};
|
||||
|
@@ -36,6 +36,7 @@
|
||||
"./artifacts/StakingProxy.json",
|
||||
"./artifacts/ZrxVault.json",
|
||||
"./artifacts/ERC20BridgeProxy.json",
|
||||
"./artifacts/IERC20BridgeSampler.json"
|
||||
"./artifacts/IERC20BridgeSampler.json",
|
||||
"./artifacts/ITransformERC20.json"
|
||||
]
|
||||
}
|
||||
|
@@ -33,6 +33,10 @@
|
||||
{
|
||||
"note": "Added `ERC20BridgeSampler.sampleSellsFromMultiBridge",
|
||||
"pr": 2593
|
||||
},
|
||||
{
|
||||
"note": "Add `ITransformERC20`",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -32,7 +32,7 @@
|
||||
"wrappers:generate": "abi-gen --abis ${npm_package_config_abis} --output src/generated-wrappers --backend ethers"
|
||||
},
|
||||
"config": {
|
||||
"abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|ERC20BridgeSampler|GodsUnchainedValidator|Broker|ILiquidityProvider|ILiquidityProviderRegistry|MaximumGasPrice).json"
|
||||
"abis": "../contract-artifacts/artifacts/@(DevUtils|ERC20Token|ERC721Token|Exchange|Forwarder|IAssetData|LibTransactionDecoder|WETH9|Coordinator|Staking|StakingProxy|IERC20BridgeSampler|ERC20BridgeSampler|GodsUnchainedValidator|Broker|ILiquidityProvider|ILiquidityProviderRegistry|MaximumGasPrice|ITransformERC20).json"
|
||||
},
|
||||
"gitpkg": {
|
||||
"registry": "git@github.com:0xProject/gitpkg-registry.git"
|
||||
|
910
packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts
generated
Normal file
910
packages/contract-wrappers/src/generated-wrappers/i_transform_erc20.ts
generated
Normal file
@@ -0,0 +1,910 @@
|
||||
// tslint:disable:no-consecutive-blank-lines ordered-imports align trailing-comma enum-naming
|
||||
// tslint:disable:whitespace no-unbound-method no-trailing-whitespace
|
||||
// tslint:disable:no-unused-variable
|
||||
import {
|
||||
AwaitTransactionSuccessOpts,
|
||||
ContractFunctionObj,
|
||||
ContractTxFunctionObj,
|
||||
SendTransactionOpts,
|
||||
BaseContract,
|
||||
SubscriptionManager,
|
||||
PromiseWithTransactionHash,
|
||||
methodAbiToFunctionSignature,
|
||||
linkLibrariesInBytecode,
|
||||
} from '@0x/base-contract';
|
||||
import { schemas } from '@0x/json-schemas';
|
||||
import {
|
||||
BlockParam,
|
||||
BlockParamLiteral,
|
||||
BlockRange,
|
||||
CallData,
|
||||
ContractAbi,
|
||||
ContractArtifact,
|
||||
DecodedLogArgs,
|
||||
LogWithDecodedArgs,
|
||||
MethodAbi,
|
||||
TransactionReceiptWithDecodedLogs,
|
||||
TxData,
|
||||
TxDataPayable,
|
||||
SupportedProvider,
|
||||
} from 'ethereum-types';
|
||||
import { BigNumber, classUtils, hexUtils, logUtils, providerUtils } from '@0x/utils';
|
||||
import { EventCallback, IndexedFilterValues, SimpleContractArtifact } from '@0x/types';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { assert } from '@0x/assert';
|
||||
import * as ethers from 'ethers';
|
||||
// tslint:enable:no-unused-variable
|
||||
|
||||
export type ITransformERC20EventArgs =
|
||||
| ITransformERC20TransformedERC20EventArgs
|
||||
| ITransformERC20TransformerDeployerUpdatedEventArgs;
|
||||
|
||||
export enum ITransformERC20Events {
|
||||
TransformedERC20 = 'TransformedERC20',
|
||||
TransformerDeployerUpdated = 'TransformerDeployerUpdated',
|
||||
}
|
||||
|
||||
export interface ITransformERC20TransformedERC20EventArgs extends DecodedLogArgs {
|
||||
taker: string;
|
||||
inputToken: string;
|
||||
outputToken: string;
|
||||
inputTokenAmount: BigNumber;
|
||||
outputTokenAmount: BigNumber;
|
||||
}
|
||||
|
||||
export interface ITransformERC20TransformerDeployerUpdatedEventArgs extends DecodedLogArgs {
|
||||
transformerDeployer: string;
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
// tslint:disable:array-type
|
||||
// tslint:disable:no-parameter-reassignment
|
||||
// tslint:disable-next-line:class-name
|
||||
export class ITransformERC20Contract extends BaseContract {
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
public static deployedBytecode: string | undefined;
|
||||
public static contractName = 'ITransformERC20';
|
||||
private readonly _methodABIIndex: { [name: string]: number } = {};
|
||||
private readonly _subscriptionManager: SubscriptionManager<ITransformERC20EventArgs, ITransformERC20Events>;
|
||||
public static async deployFrom0xArtifactAsync(
|
||||
artifact: ContractArtifact | SimpleContractArtifact,
|
||||
supportedProvider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact },
|
||||
): Promise<ITransformERC20Contract> {
|
||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
||||
schemas.addressSchema,
|
||||
schemas.numberSchema,
|
||||
schemas.jsNumber,
|
||||
]);
|
||||
if (artifact.compilerOutput === undefined) {
|
||||
throw new Error('Compiler output not found in the artifact file');
|
||||
}
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
const bytecode = artifact.compilerOutput.evm.bytecode.object;
|
||||
const abi = artifact.compilerOutput.abi;
|
||||
const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {};
|
||||
if (Object.keys(logDecodeDependencies) !== undefined) {
|
||||
for (const key of Object.keys(logDecodeDependencies)) {
|
||||
logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi;
|
||||
}
|
||||
}
|
||||
return ITransformERC20Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly);
|
||||
}
|
||||
|
||||
public static async deployWithLibrariesFrom0xArtifactAsync(
|
||||
artifact: ContractArtifact,
|
||||
libraryArtifacts: { [libraryName: string]: ContractArtifact },
|
||||
supportedProvider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
logDecodeDependencies: { [contractName: string]: ContractArtifact | SimpleContractArtifact },
|
||||
): Promise<ITransformERC20Contract> {
|
||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
||||
schemas.addressSchema,
|
||||
schemas.numberSchema,
|
||||
schemas.jsNumber,
|
||||
]);
|
||||
if (artifact.compilerOutput === undefined) {
|
||||
throw new Error('Compiler output not found in the artifact file');
|
||||
}
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
const abi = artifact.compilerOutput.abi;
|
||||
const logDecodeDependenciesAbiOnly: { [contractName: string]: ContractAbi } = {};
|
||||
if (Object.keys(logDecodeDependencies) !== undefined) {
|
||||
for (const key of Object.keys(logDecodeDependencies)) {
|
||||
logDecodeDependenciesAbiOnly[key] = logDecodeDependencies[key].compilerOutput.abi;
|
||||
}
|
||||
}
|
||||
const libraryAddresses = await ITransformERC20Contract._deployLibrariesAsync(
|
||||
artifact,
|
||||
libraryArtifacts,
|
||||
new Web3Wrapper(provider),
|
||||
txDefaults,
|
||||
);
|
||||
const bytecode = linkLibrariesInBytecode(artifact, libraryAddresses);
|
||||
return ITransformERC20Contract.deployAsync(bytecode, abi, provider, txDefaults, logDecodeDependenciesAbiOnly);
|
||||
}
|
||||
|
||||
public static async deployAsync(
|
||||
bytecode: string,
|
||||
abi: ContractAbi,
|
||||
supportedProvider: SupportedProvider,
|
||||
txDefaults: Partial<TxData>,
|
||||
logDecodeDependencies: { [contractName: string]: ContractAbi },
|
||||
): Promise<ITransformERC20Contract> {
|
||||
assert.isHexString('bytecode', bytecode);
|
||||
assert.doesConformToSchema('txDefaults', txDefaults, schemas.txDataSchema, [
|
||||
schemas.addressSchema,
|
||||
schemas.numberSchema,
|
||||
schemas.jsNumber,
|
||||
]);
|
||||
const provider = providerUtils.standardizeOrThrow(supportedProvider);
|
||||
const constructorAbi = BaseContract._lookupConstructorAbi(abi);
|
||||
[] = BaseContract._formatABIDataItemList(constructorAbi.inputs, [], BaseContract._bigNumberToString);
|
||||
const iface = new ethers.utils.Interface(abi);
|
||||
const deployInfo = iface.deployFunction;
|
||||
const txData = deployInfo.encode(bytecode, []);
|
||||
const web3Wrapper = new Web3Wrapper(provider);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync(
|
||||
{
|
||||
data: txData,
|
||||
...txDefaults,
|
||||
},
|
||||
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
|
||||
);
|
||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
logUtils.log(`transactionHash: ${txHash}`);
|
||||
const txReceipt = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
logUtils.log(`ITransformERC20 successfully deployed at ${txReceipt.contractAddress}`);
|
||||
const contractInstance = new ITransformERC20Contract(
|
||||
txReceipt.contractAddress as string,
|
||||
provider,
|
||||
txDefaults,
|
||||
logDecodeDependencies,
|
||||
);
|
||||
contractInstance.constructorArgs = [];
|
||||
return contractInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The contract ABI
|
||||
*/
|
||||
public static ABI(): ContractAbi {
|
||||
const abi = [
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
name: 'taker',
|
||||
type: 'address',
|
||||
indexed: true,
|
||||
},
|
||||
{
|
||||
name: 'inputToken',
|
||||
type: 'address',
|
||||
indexed: false,
|
||||
},
|
||||
{
|
||||
name: 'outputToken',
|
||||
type: 'address',
|
||||
indexed: false,
|
||||
},
|
||||
{
|
||||
name: 'inputTokenAmount',
|
||||
type: 'uint256',
|
||||
indexed: false,
|
||||
},
|
||||
{
|
||||
name: 'outputTokenAmount',
|
||||
type: 'uint256',
|
||||
indexed: false,
|
||||
},
|
||||
],
|
||||
name: 'TransformedERC20',
|
||||
outputs: [],
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
name: 'transformerDeployer',
|
||||
type: 'address',
|
||||
indexed: false,
|
||||
},
|
||||
],
|
||||
name: 'TransformerDeployerUpdated',
|
||||
outputs: [],
|
||||
type: 'event',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
name: 'callDataHash',
|
||||
type: 'bytes32',
|
||||
},
|
||||
{
|
||||
name: 'taker',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'inputToken',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'outputToken',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'inputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
name: 'minOutputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
name: 'transformations',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{
|
||||
name: 'deploymentNonce',
|
||||
type: 'uint32',
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
type: 'bytes',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
name: '_transformERC20',
|
||||
outputs: [
|
||||
{
|
||||
name: 'outputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
stateMutability: 'payable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'createTransformWallet',
|
||||
outputs: [
|
||||
{
|
||||
name: 'wallet',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'getTransformWallet',
|
||||
outputs: [
|
||||
{
|
||||
name: 'wallet',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: 'getTransformerDeployer',
|
||||
outputs: [
|
||||
{
|
||||
name: 'deployer',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
stateMutability: 'view',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
name: 'transformerDeployer',
|
||||
type: 'address',
|
||||
},
|
||||
],
|
||||
name: 'setTransformerDeployer',
|
||||
outputs: [],
|
||||
stateMutability: 'nonpayable',
|
||||
type: 'function',
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
name: 'inputToken',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'outputToken',
|
||||
type: 'address',
|
||||
},
|
||||
{
|
||||
name: 'inputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
name: 'minOutputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
{
|
||||
name: 'transformations',
|
||||
type: 'tuple[]',
|
||||
components: [
|
||||
{
|
||||
name: 'deploymentNonce',
|
||||
type: 'uint32',
|
||||
},
|
||||
{
|
||||
name: 'data',
|
||||
type: 'bytes',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
name: 'transformERC20',
|
||||
outputs: [
|
||||
{
|
||||
name: 'outputTokenAmount',
|
||||
type: 'uint256',
|
||||
},
|
||||
],
|
||||
stateMutability: 'payable',
|
||||
type: 'function',
|
||||
},
|
||||
] as ContractAbi;
|
||||
return abi;
|
||||
}
|
||||
|
||||
protected static async _deployLibrariesAsync(
|
||||
artifact: ContractArtifact,
|
||||
libraryArtifacts: { [libraryName: string]: ContractArtifact },
|
||||
web3Wrapper: Web3Wrapper,
|
||||
txDefaults: Partial<TxData>,
|
||||
libraryAddresses: { [libraryName: string]: string } = {},
|
||||
): Promise<{ [libraryName: string]: string }> {
|
||||
const links = artifact.compilerOutput.evm.bytecode.linkReferences;
|
||||
// Go through all linked libraries, recursively deploying them if necessary.
|
||||
for (const link of Object.values(links)) {
|
||||
for (const libraryName of Object.keys(link)) {
|
||||
if (!libraryAddresses[libraryName]) {
|
||||
// Library not yet deployed.
|
||||
const libraryArtifact = libraryArtifacts[libraryName];
|
||||
if (!libraryArtifact) {
|
||||
throw new Error(`Missing artifact for linked library "${libraryName}"`);
|
||||
}
|
||||
// Deploy any dependent libraries used by this library.
|
||||
await ITransformERC20Contract._deployLibrariesAsync(
|
||||
libraryArtifact,
|
||||
libraryArtifacts,
|
||||
web3Wrapper,
|
||||
txDefaults,
|
||||
libraryAddresses,
|
||||
);
|
||||
// Deploy this library.
|
||||
const linkedLibraryBytecode = linkLibrariesInBytecode(libraryArtifact, libraryAddresses);
|
||||
const txDataWithDefaults = await BaseContract._applyDefaultsToContractTxDataAsync(
|
||||
{
|
||||
data: linkedLibraryBytecode,
|
||||
...txDefaults,
|
||||
},
|
||||
web3Wrapper.estimateGasAsync.bind(web3Wrapper),
|
||||
);
|
||||
const txHash = await web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
logUtils.log(`transactionHash: ${txHash}`);
|
||||
const { contractAddress } = await web3Wrapper.awaitTransactionSuccessAsync(txHash);
|
||||
logUtils.log(`${libraryArtifact.contractName} successfully deployed at ${contractAddress}`);
|
||||
libraryAddresses[libraryArtifact.contractName] = contractAddress as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
return libraryAddresses;
|
||||
}
|
||||
|
||||
public getFunctionSignature(methodName: string): string {
|
||||
const index = this._methodABIIndex[methodName];
|
||||
const methodAbi = ITransformERC20Contract.ABI()[index] as MethodAbi; // tslint:disable-line:no-unnecessary-type-assertion
|
||||
const functionSignature = methodAbiToFunctionSignature(methodAbi);
|
||||
return functionSignature;
|
||||
}
|
||||
|
||||
public getABIDecodedTransactionData<T>(methodName: string, callData: string): T {
|
||||
const functionSignature = this.getFunctionSignature(methodName);
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
const abiDecodedCallData = abiEncoder.strictDecode<T>(callData);
|
||||
return abiDecodedCallData;
|
||||
}
|
||||
|
||||
public getABIDecodedReturnData<T>(methodName: string, callData: string): T {
|
||||
const functionSignature = this.getFunctionSignature(methodName);
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
const abiDecodedCallData = abiEncoder.strictDecodeReturnValue<T>(callData);
|
||||
return abiDecodedCallData;
|
||||
}
|
||||
|
||||
public getSelector(methodName: string): string {
|
||||
const functionSignature = this.getFunctionSignature(methodName);
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
return abiEncoder.getSelector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal version of `transformERC20()`. Only callable from within.
|
||||
* @param callDataHash Hash of the ingress calldata.
|
||||
* @param taker The taker address.
|
||||
* @param inputToken The token being provided by the taker. If
|
||||
* `0xeee...`, ETH is implied and should be provided with the call.`
|
||||
* @param outputToken The token to be acquired by the taker. `0xeee...`
|
||||
* implies ETH.
|
||||
* @param inputTokenAmount The amount of `inputToken` to take from the taker.
|
||||
* @param minOutputTokenAmount The minimum amount of `outputToken` the taker
|
||||
* must receive for the entire transformation to succeed.
|
||||
* @param transformations The transformations to execute on the token
|
||||
* balance(s) in sequence.
|
||||
*/
|
||||
public _transformERC20(
|
||||
callDataHash: string,
|
||||
taker: string,
|
||||
inputToken: string,
|
||||
outputToken: string,
|
||||
inputTokenAmount: BigNumber,
|
||||
minOutputTokenAmount: BigNumber,
|
||||
transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>,
|
||||
): ContractTxFunctionObj<BigNumber> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
assert.isString('callDataHash', callDataHash);
|
||||
assert.isString('taker', taker);
|
||||
assert.isString('inputToken', inputToken);
|
||||
assert.isString('outputToken', outputToken);
|
||||
assert.isBigNumber('inputTokenAmount', inputTokenAmount);
|
||||
assert.isBigNumber('minOutputTokenAmount', minOutputTokenAmount);
|
||||
assert.isArray('transformations', transformations);
|
||||
const functionSignature = '_transformERC20(bytes32,address,address,address,uint256,uint256,(uint32,bytes)[])';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, [
|
||||
callDataHash,
|
||||
taker.toLowerCase(),
|
||||
inputToken.toLowerCase(),
|
||||
outputToken.toLowerCase(),
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations,
|
||||
]);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Deploy a new flash wallet instance and replace the current one with it.
|
||||
* Useful if we somehow break the current wallet instance.
|
||||
* Anyone can call this.
|
||||
*/
|
||||
public createTransformWallet(): ContractTxFunctionObj<string> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const functionSignature = 'createTransformWallet()';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<string> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, []);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Return the current wallet instance that will serve as the execution
|
||||
* context for transformations.
|
||||
*/
|
||||
public getTransformWallet(): ContractTxFunctionObj<string> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const functionSignature = 'getTransformWallet()';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<string> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, []);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Return the allowed deployer for transformers.
|
||||
*/
|
||||
public getTransformerDeployer(): ContractTxFunctionObj<string> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
const functionSignature = 'getTransformerDeployer()';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<string> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<string>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, []);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Replace the allowed deployer for transformers.
|
||||
* Only callable by the owner.
|
||||
* @param transformerDeployer The address of the trusted deployer for
|
||||
* transformers.
|
||||
*/
|
||||
public setTransformerDeployer(transformerDeployer: string): ContractTxFunctionObj<void> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
assert.isString('transformerDeployer', transformerDeployer);
|
||||
const functionSignature = 'setTransformerDeployer(address)';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<void> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<void>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, [transformerDeployer.toLowerCase()]);
|
||||
},
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Executes a series of transformations to convert an ERC20 `inputToken`
|
||||
* to an ERC20 `outputToken`.
|
||||
* @param inputToken The token being provided by the sender. If
|
||||
* `0xeee...`, ETH is implied and should be provided with the call.`
|
||||
* @param outputToken The token to be acquired by the sender. `0xeee...`
|
||||
* implies ETH.
|
||||
* @param inputTokenAmount The amount of `inputToken` to take from the sender.
|
||||
* @param minOutputTokenAmount The minimum amount of `outputToken` the sender
|
||||
* must receive for the entire transformation to succeed.
|
||||
* @param transformations The transformations to execute on the token
|
||||
* balance(s) in sequence.
|
||||
*/
|
||||
public transformERC20(
|
||||
inputToken: string,
|
||||
outputToken: string,
|
||||
inputTokenAmount: BigNumber,
|
||||
minOutputTokenAmount: BigNumber,
|
||||
transformations: Array<{ deploymentNonce: number | BigNumber; data: string }>,
|
||||
): ContractTxFunctionObj<BigNumber> {
|
||||
const self = (this as any) as ITransformERC20Contract;
|
||||
assert.isString('inputToken', inputToken);
|
||||
assert.isString('outputToken', outputToken);
|
||||
assert.isBigNumber('inputTokenAmount', inputTokenAmount);
|
||||
assert.isBigNumber('minOutputTokenAmount', minOutputTokenAmount);
|
||||
assert.isArray('transformations', transformations);
|
||||
const functionSignature = 'transformERC20(address,address,uint256,uint256,(uint32,bytes)[])';
|
||||
|
||||
return {
|
||||
async sendTransactionAsync(
|
||||
txData?: Partial<TxData> | undefined,
|
||||
opts: SendTransactionOpts = { shouldValidate: true },
|
||||
): Promise<string> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync(
|
||||
{ ...txData, data: this.getABIEncodedTransactionData() },
|
||||
this.estimateGasAsync.bind(this),
|
||||
);
|
||||
if (opts.shouldValidate !== false) {
|
||||
await this.callAsync(txDataWithDefaults);
|
||||
}
|
||||
return self._web3Wrapper.sendTransactionAsync(txDataWithDefaults);
|
||||
},
|
||||
awaitTransactionSuccessAsync(
|
||||
txData?: Partial<TxData>,
|
||||
opts: AwaitTransactionSuccessOpts = { shouldValidate: true },
|
||||
): PromiseWithTransactionHash<TransactionReceiptWithDecodedLogs> {
|
||||
return self._promiseWithTransactionHash(this.sendTransactionAsync(txData, opts), opts);
|
||||
},
|
||||
async estimateGasAsync(txData?: Partial<TxData> | undefined): Promise<number> {
|
||||
const txDataWithDefaults = await self._applyDefaultsToTxDataAsync({
|
||||
...txData,
|
||||
data: this.getABIEncodedTransactionData(),
|
||||
});
|
||||
return self._web3Wrapper.estimateGasAsync(txDataWithDefaults);
|
||||
},
|
||||
async callAsync(callData: Partial<CallData> = {}, defaultBlock?: BlockParam): Promise<BigNumber> {
|
||||
BaseContract._assertCallParams(callData, defaultBlock);
|
||||
const rawCallResult = await self._performCallAsync(
|
||||
{ ...callData, data: this.getABIEncodedTransactionData() },
|
||||
defaultBlock,
|
||||
);
|
||||
const abiEncoder = self._lookupAbiEncoder(functionSignature);
|
||||
BaseContract._throwIfUnexpectedEmptyCallResult(rawCallResult, abiEncoder);
|
||||
return abiEncoder.strictDecodeReturnValue<BigNumber>(rawCallResult);
|
||||
},
|
||||
getABIEncodedTransactionData(): string {
|
||||
return self._strictEncodeArguments(functionSignature, [
|
||||
inputToken.toLowerCase(),
|
||||
outputToken.toLowerCase(),
|
||||
inputTokenAmount,
|
||||
minOutputTokenAmount,
|
||||
transformations,
|
||||
]);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to an event type emitted by the ITransformERC20 contract.
|
||||
* @param eventName The ITransformERC20 contract event you would like to subscribe to.
|
||||
* @param indexFilterValues An object where the keys are indexed args returned by the event and
|
||||
* the value is the value you are interested in. E.g `{maker: aUserAddressHex}`
|
||||
* @param callback Callback that gets called when a log is added/removed
|
||||
* @param isVerbose Enable verbose subscription warnings (e.g recoverable network issues encountered)
|
||||
* @return Subscription token used later to unsubscribe
|
||||
*/
|
||||
public subscribe<ArgsType extends ITransformERC20EventArgs>(
|
||||
eventName: ITransformERC20Events,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
callback: EventCallback<ArgsType>,
|
||||
isVerbose: boolean = false,
|
||||
blockPollingIntervalMs?: number,
|
||||
): string {
|
||||
assert.doesBelongToStringEnum('eventName', eventName, ITransformERC20Events);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
assert.isFunction('callback', callback);
|
||||
const subscriptionToken = this._subscriptionManager.subscribe<ArgsType>(
|
||||
this.address,
|
||||
eventName,
|
||||
indexFilterValues,
|
||||
ITransformERC20Contract.ABI(),
|
||||
callback,
|
||||
isVerbose,
|
||||
blockPollingIntervalMs,
|
||||
);
|
||||
return subscriptionToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a subscription
|
||||
* @param subscriptionToken Subscription token returned by `subscribe()`
|
||||
*/
|
||||
public unsubscribe(subscriptionToken: string): void {
|
||||
this._subscriptionManager.unsubscribe(subscriptionToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all existing subscriptions
|
||||
*/
|
||||
public unsubscribeAll(): void {
|
||||
this._subscriptionManager.unsubscribeAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets historical logs without creating a subscription
|
||||
* @param eventName The ITransformERC20 contract event you would like to subscribe to.
|
||||
* @param blockRange Block range to get logs from.
|
||||
* @param indexFilterValues An object where the keys are indexed args returned by the event and
|
||||
* the value is the value you are interested in. E.g `{_from: aUserAddressHex}`
|
||||
* @return Array of logs that match the parameters
|
||||
*/
|
||||
public async getLogsAsync<ArgsType extends ITransformERC20EventArgs>(
|
||||
eventName: ITransformERC20Events,
|
||||
blockRange: BlockRange,
|
||||
indexFilterValues: IndexedFilterValues,
|
||||
): Promise<Array<LogWithDecodedArgs<ArgsType>>> {
|
||||
assert.doesBelongToStringEnum('eventName', eventName, ITransformERC20Events);
|
||||
assert.doesConformToSchema('blockRange', blockRange, schemas.blockRangeSchema);
|
||||
assert.doesConformToSchema('indexFilterValues', indexFilterValues, schemas.indexFilterValuesSchema);
|
||||
const logs = await this._subscriptionManager.getLogsAsync<ArgsType>(
|
||||
this.address,
|
||||
eventName,
|
||||
blockRange,
|
||||
indexFilterValues,
|
||||
ITransformERC20Contract.ABI(),
|
||||
);
|
||||
return logs;
|
||||
}
|
||||
|
||||
constructor(
|
||||
address: string,
|
||||
supportedProvider: SupportedProvider,
|
||||
txDefaults?: Partial<TxData>,
|
||||
logDecodeDependencies?: { [contractName: string]: ContractAbi },
|
||||
deployedBytecode: string | undefined = ITransformERC20Contract.deployedBytecode,
|
||||
) {
|
||||
super(
|
||||
'ITransformERC20',
|
||||
ITransformERC20Contract.ABI(),
|
||||
address,
|
||||
supportedProvider,
|
||||
txDefaults,
|
||||
logDecodeDependencies,
|
||||
deployedBytecode,
|
||||
);
|
||||
classUtils.bindAll(this, ['_abiEncoderByFunctionSignature', 'address', '_web3Wrapper']);
|
||||
this._subscriptionManager = new SubscriptionManager<ITransformERC20EventArgs, ITransformERC20Events>(
|
||||
ITransformERC20Contract.ABI(),
|
||||
this._web3Wrapper,
|
||||
);
|
||||
ITransformERC20Contract.ABI().forEach((item, index) => {
|
||||
if (item.type === 'function') {
|
||||
const methodAbi = item as MethodAbi;
|
||||
this._methodABIIndex[methodAbi.name] = index;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// tslint:disable:max-file-line-count
|
||||
// tslint:enable:no-unbound-method no-parameter-reassignment no-consecutive-blank-lines ordered-imports align
|
||||
// tslint:enable:trailing-comma whitespace no-trailing-whitespace
|
@@ -83,6 +83,13 @@ export {
|
||||
StakingProxyStakingContractAttachedToProxyEventArgs,
|
||||
StakingProxyStakingContractDetachedFromProxyEventArgs,
|
||||
} from './generated-wrappers/staking_proxy';
|
||||
export {
|
||||
ITransformERC20Contract,
|
||||
ITransformERC20EventArgs,
|
||||
ITransformERC20Events,
|
||||
ITransformERC20TransformerDeployerUpdatedEventArgs,
|
||||
ITransformERC20TransformedERC20EventArgs,
|
||||
} from './generated-wrappers/i_transform_erc20';
|
||||
export {
|
||||
BlockRange,
|
||||
SupportedProvider,
|
||||
|
@@ -13,6 +13,10 @@
|
||||
{
|
||||
"note": "Remove `slippagePercentage` SwapQuoter config.",
|
||||
"pr": 2513
|
||||
},
|
||||
{
|
||||
"note": "Pin `asset-swapper` dependency",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -44,7 +44,7 @@
|
||||
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
|
||||
"dependencies": {
|
||||
"@0x/assert": "^3.0.7",
|
||||
"@0x/asset-swapper": "^4.4.0",
|
||||
"@0x/asset-swapper": "4.4.0",
|
||||
"@0x/contract-wrappers": "^13.6.3",
|
||||
"@0x/json-schemas": "^5.0.7",
|
||||
"@0x/subproviders": "^6.0.8",
|
||||
|
@@ -13,6 +13,10 @@
|
||||
{
|
||||
"note": "Added `UniswapV2Bridge` address on Mainnet",
|
||||
"pr": 2599
|
||||
},
|
||||
{
|
||||
"note": "Return empty Exchange Proxy addresses",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -49,6 +49,8 @@ const allArtifacts = {
|
||||
...erc20BridgeSamplerArtifacts,
|
||||
};
|
||||
|
||||
const { NULL_ADDRESS } = constants;
|
||||
|
||||
/**
|
||||
* Creates and deploys all the contracts that are required for the latest
|
||||
* version of the 0x protocol.
|
||||
@@ -202,8 +204,8 @@ export async function runMigrationsAsync(
|
||||
txDefaults,
|
||||
allArtifacts,
|
||||
exchange.address,
|
||||
constants.NULL_ADDRESS,
|
||||
constants.NULL_ADDRESS,
|
||||
NULL_ADDRESS,
|
||||
NULL_ADDRESS,
|
||||
);
|
||||
|
||||
// tslint:disable-next-line:no-unused-variable
|
||||
@@ -278,7 +280,7 @@ export async function runMigrationsAsync(
|
||||
txDefaults,
|
||||
allArtifacts,
|
||||
exchange.address,
|
||||
exchangeV2Address || constants.NULL_ADDRESS,
|
||||
exchangeV2Address || NULL_ADDRESS,
|
||||
etherToken.address,
|
||||
);
|
||||
|
||||
@@ -297,33 +299,42 @@ export async function runMigrationsAsync(
|
||||
zrxToken: zrxToken.address,
|
||||
etherToken: etherToken.address,
|
||||
exchange: exchange.address,
|
||||
assetProxyOwner: constants.NULL_ADDRESS,
|
||||
assetProxyOwner: NULL_ADDRESS,
|
||||
erc20BridgeProxy: erc20BridgeProxy.address,
|
||||
zeroExGovernor: constants.NULL_ADDRESS,
|
||||
zeroExGovernor: NULL_ADDRESS,
|
||||
forwarder: forwarder.address,
|
||||
coordinatorRegistry: coordinatorRegistry.address,
|
||||
coordinator: coordinator.address,
|
||||
multiAssetProxy: multiAssetProxy.address,
|
||||
staticCallProxy: staticCallProxy.address,
|
||||
devUtils: devUtils.address,
|
||||
exchangeV2: exchangeV2Address || constants.NULL_ADDRESS,
|
||||
exchangeV2: exchangeV2Address || NULL_ADDRESS,
|
||||
zrxVault: zrxVault.address,
|
||||
staking: stakingLogic.address,
|
||||
stakingProxy: stakingProxy.address,
|
||||
uniswapBridge: constants.NULL_ADDRESS,
|
||||
uniswapV2Bridge: constants.NULL_ADDRESS,
|
||||
eth2DaiBridge: constants.NULL_ADDRESS,
|
||||
kyberBridge: constants.NULL_ADDRESS,
|
||||
uniswapBridge: NULL_ADDRESS,
|
||||
eth2DaiBridge: NULL_ADDRESS,
|
||||
kyberBridge: NULL_ADDRESS,
|
||||
erc20BridgeSampler: erc20BridgeSampler.address,
|
||||
chaiBridge: constants.NULL_ADDRESS,
|
||||
dydxBridge: constants.NULL_ADDRESS,
|
||||
curveBridge: constants.NULL_ADDRESS,
|
||||
godsUnchainedValidator: constants.NULL_ADDRESS,
|
||||
broker: constants.NULL_ADDRESS,
|
||||
chainlinkStopLimit: constants.NULL_ADDRESS,
|
||||
maximumGasPrice: constants.NULL_ADDRESS,
|
||||
dexForwarderBridge: constants.NULL_ADDRESS,
|
||||
multiBridge: constants.NULL_ADDRESS,
|
||||
chaiBridge: NULL_ADDRESS,
|
||||
dydxBridge: NULL_ADDRESS,
|
||||
curveBridge: NULL_ADDRESS,
|
||||
uniswapV2Bridge: NULL_ADDRESS,
|
||||
godsUnchainedValidator: NULL_ADDRESS,
|
||||
broker: NULL_ADDRESS,
|
||||
chainlinkStopLimit: NULL_ADDRESS,
|
||||
maximumGasPrice: NULL_ADDRESS,
|
||||
dexForwarderBridge: NULL_ADDRESS,
|
||||
multiBridge: NULL_ADDRESS,
|
||||
exchangeProxyGovernor: NULL_ADDRESS,
|
||||
exchangeProxy: NULL_ADDRESS,
|
||||
exchangeProxyAllowanceTarget: NULL_ADDRESS,
|
||||
exchangeProxyTransformerDeployer: NULL_ADDRESS,
|
||||
transformers: {
|
||||
wethTransformer: NULL_ADDRESS,
|
||||
payTakerTransformer: NULL_ADDRESS,
|
||||
fillQuoteTransformer: NULL_ADDRESS,
|
||||
},
|
||||
};
|
||||
return contractAddresses;
|
||||
}
|
||||
|
@@ -9,6 +9,10 @@
|
||||
{
|
||||
"note": "Filter `receive` functions from 0.6 ABIs",
|
||||
"pr": 2540
|
||||
},
|
||||
{
|
||||
"note": "Fix `CompilerOptions` schema",
|
||||
"pr": 2591
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@@ -3,7 +3,7 @@ export const compilerOptionsSchema = {
|
||||
properties: {
|
||||
contractsDir: { type: 'string' },
|
||||
artifactsDir: { type: 'string' },
|
||||
solcVersion: { type: 'string', pattern: '^\\d+.\\d+.\\d+$' },
|
||||
solcVersion: { type: 'string', pattern: '^\\d+.\\d+.\\d+\\+commit\\.[a-f0-9]{8}$' },
|
||||
compilerSettings: { type: 'object' },
|
||||
contracts: {
|
||||
oneOf: [
|
||||
|
Reference in New Issue
Block a user