Skip to content

Commit

Permalink
feat: improve swap contract and deployment (#1043)
Browse files Browse the repository at this point in the history
  • Loading branch information
leoslr committed Jan 23, 2023
1 parent 0dc67c1 commit bfbe7a0
Show file tree
Hide file tree
Showing 25 changed files with 628 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { ITransactionOverrides } from './transaction-overrides';
import {
getAmountToPay,
getProvider,
getProxyAddress,
getRequestPaymentValues,
getSigner,
validateErc20FeeProxyRequest,
} from './utils';
import { IPreparedTransaction } from './prepared-transaction';
import { Erc20PaymentNetwork } from '@requestnetwork/payment-detection';

/**
* Details required for a token swap:
Expand Down Expand Up @@ -131,10 +133,16 @@ export function encodeSwapToPayErc20FeeRequest(
throw new Error('Request currency network is missing');
}

const feeProxyAddress = getProxyAddress(
request,
Erc20PaymentNetwork.ERC20FeeProxyPaymentDetector.getDeploymentInformation,
);

const swapToPayAddress = erc20FeeProxyArtifact.getAddress(request.currencyInfo.network);
const swapToPayContract = ERC20SwapToPay__factory.connect(swapToPayAddress, signer);

return swapToPayContract.interface.encodeFunctionData('swapTransferWithReference', [
feeProxyAddress,
paymentAddress,
amountToPay,
swapSettings.maxInputAmount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ describe('Payment encoder handles ERC20 Swap Proxy', () => {
);

expect(paymentTransaction).toEqual({
data: '0x8d09fe2b000000000000000000000000f17f52151ebef6c7334fad080c5704d77216b732000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000cc000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef000000000000000000000000000000000000000000000000000000009af4c3db000000000000000000000000000000000000000000000000000000000000000200000000000000000000000038cf23c52bb4b13f051aec09580a2de845a7fa350000000000000000000000009fbda871d559710256a2502a2517b794b482db40000000000000000000000000000000000000000000000000000000000000000886dfbccad783599a000000000000000000000000000000000000000000000000',
data: '0x5f2993bf00000000000000000000000075c35c980c0d37ef46df04d31a140b65503c0eed000000000000000000000000f17f52151ebef6c7334fad080c5704d77216b732000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000cc000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef000000000000000000000000000000000000000000000000000000009af4c3db000000000000000000000000000000000000000000000000000000000000000200000000000000000000000038cf23c52bb4b13f051aec09580a2de845a7fa350000000000000000000000009fbda871d559710256a2502a2517b794b482db40000000000000000000000000000000000000000000000000000000000000000886dfbccad783599a000000000000000000000000000000000000000000000000',
to: proxyAddress,
value: 0,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const validRequest: ClientTypes.IRequestData = {
paymentAddress,
salt: 'salt',
},
version: '1.0',
version: '0.1.0',
},
},
extensionsData: [],
Expand Down Expand Up @@ -146,15 +146,15 @@ describe('swap-erc20-fee-proxy', () => {
wallet,
{
deadline: 2599732187000, // This test will fail in 2052
maxInputAmount: 204,
maxInputAmount: 206,
path: [alphaErc20Address, erc20ContractAddress],
},
{
overrides: { gasPrice: '20000000000' },
},
);
expect(spy).toHaveBeenCalledWith({
data: '0x8d09fe2b000000000000000000000000f17f52151ebef6c7334fad080c5704d77216b732000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000cc000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef000000000000000000000000000000000000000000000000000000009af4c3db000000000000000000000000000000000000000000000000000000000000000200000000000000000000000038cf23c52bb4b13f051aec09580a2de845a7fa350000000000000000000000009fbda871d559710256a2502a2517b794b482db40000000000000000000000000000000000000000000000000000000000000000886dfbccad783599a000000000000000000000000000000000000000000000000',
data: '0x5f2993bf00000000000000000000000075c35c980c0d37ef46df04d31a140b65503c0eed000000000000000000000000f17f52151ebef6c7334fad080c5704d77216b732000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000000ce000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c5fdf4076b8f3a5357c5e395ab970b5b54098fef000000000000000000000000000000000000000000000000000000009af4c3db000000000000000000000000000000000000000000000000000000000000000200000000000000000000000038cf23c52bb4b13f051aec09580a2de845a7fa350000000000000000000000009fbda871d559710256a2502a2517b794b482db40000000000000000000000000000000000000000000000000000000000000000886dfbccad783599a000000000000000000000000000000000000000000000000',
gasPrice: '20000000000',
to: '0xA4392264a2d8c998901D10C154C91725b1BF0158',
value: 0,
Expand Down Expand Up @@ -191,8 +191,8 @@ describe('swap-erc20-fee-proxy', () => {

// Swap and pay
const tx = await swapErc20FeeProxyRequest(validRequest, wallet, {
deadline: Date.now() + 1000,
maxInputAmount: 204,
deadline: Date.now() + 10000,
maxInputAmount: 206,
path: [alphaErc20Address, erc20ContractAddress],
});
const confirmedTx = await tx.wait(1);
Expand Down
14 changes: 13 additions & 1 deletion packages/smart-contracts/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,19 @@ export default {
signer: process.env.ADMIN_PRIVATE_KEY,
networks: process.env.NETWORK
? [process.env.NETWORK]
: ['mainnet', 'matic', 'bsc', 'celo', 'xdai', 'fuse', 'arbitrum-one', 'fantom', 'avalanche'],
: [
'mainnet',
'matic',
'bsc',
'celo',
'xdai',
'fuse',
'arbitrum-one',
'fantom',
'avalanche',
'optimism',
'moonbeam',
],
gasLimit: undefined,
deployerAddress: requestDeployer,
},
Expand Down
12 changes: 8 additions & 4 deletions packages/smart-contracts/scripts-create2/constructor-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const getAdminWalletAddress = (contract: string): string => {

export const getConstructorArgs = (contract: string, network?: string): string[] => {
switch (contract) {
case 'ChainlinkConversionPath': {
return ['0x0000000000000000000000000000000000000000', getAdminWalletAddress(contract)];
}
case 'Erc20ConversionProxy': {
return [
'0x0000000000000000000000000000000000000000',
Expand All @@ -20,12 +23,13 @@ export const getConstructorArgs = (contract: string, network?: string): string[]
return [
'0x0000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000',
// FIXME: This is not right the NativeTokenHash is not the same accross all networks
// It should be set to 0x0, and then updated through setup functions
// These functions needs to be implemented in the contract before it can deployed using xdeployer
'0x39e19aa5b69466dfdc313c7cda37cb2a599015cd',
'0x0000000000000000000000000000000000000000',
getAdminWalletAddress(contract),
];
}
case 'ERC20SwapToPay': {
return ['0x0000000000000000000000000000000000000000', getAdminWalletAddress(contract)];
}
case 'ERC20SwapToConversion': {
return [getAdminWalletAddress(contract)];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ export const updateSwapRouter = async (
txOverrides: Overrides,
): Promise<void> => {
const currentSwapRouter = await contract.swapRouter();
if (currentSwapRouter !== uniswapV2RouterAddresses[network]) {
const tx = await contract.setRouter(uniswapV2RouterAddresses[network], txOverrides);
const expectedRouter = uniswapV2RouterAddresses[network];
if (expectedRouter && currentSwapRouter !== expectedRouter) {
const tx = await contract.setRouter(expectedRouter, txOverrides);
await tx.wait(1);
console.log(`Swap router address set to ${expectedRouter}`);
}
};

Expand All @@ -66,7 +68,9 @@ export const updateRequestSwapFees = async (
if (!currentFees.eq(REQUEST_SWAP_FEES)) {
const tx = await contract.updateRequestSwapFees(REQUEST_SWAP_FEES, txOverrides);
await tx.wait(1);
console.log(`currentFees: ${currentFees.toString()}, new fees: ${REQUEST_SWAP_FEES}`);
console.log(
`currentFees: ${currentFees.toNumber() / 10}%, new fees: ${REQUEST_SWAP_FEES / 10}%`,
);
}
};

Expand Down Expand Up @@ -228,6 +232,28 @@ export const updateNativeAndUSDAddress = async (
}
};

/**
* Update the native token hash used by a contract.
* @param contract contract to be updated.
* @param nativeTokenHash The address of native token, eg: ETH.
* @param txOverrides information related to gas fees. Increase their values if needed.
*/
export const updateNativeTokenHash = async (
contractType: string,
contract: any,
nativeTokenHash: string,
txOverrides: Overrides,
): Promise<void> => {
const currentNativeTokenHash = (await contract.nativeTokenHash()).toLocaleLowerCase();
if (currentNativeTokenHash !== nativeTokenHash.toLocaleLowerCase()) {
const tx = await contract.updateNativeTokenHash(nativeTokenHash, txOverrides);
await tx.wait(1);
console.log(
`${contractType}: the current NativeTokenHash: ${currentNativeTokenHash}, have been replaced by: ${nativeTokenHash}`,
);
}
};

/**
* Gets the signer and gas fees information.
* @param network The network used.
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export { setupChainlinkConversionPath } from './setupChainlinkConversionPath';
export { setupErc20ConversionProxy } from './setupErc20ConversionProxy';
export { setupETHConversionProxy } from './setupETHConversionProxy';
export { setupERC20SwapToPay } from './setupERC20SwapToPay';
export { setupERC20SwapToConversion } from './setupERC20SwapToConversion';
export { setupBatchConversionPayments } from './setupBatchConversionPayments';
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { CurrencyManager } from '@requestnetwork/currency';
import { RequestLogicTypes } from '@requestnetwork/types';
import { chainlinkConversionPath } from '../../src/lib';
import { HardhatRuntimeEnvironmentExtended } from '../types';
import { getSignerAndGasFees, updateNativeTokenHash } from './adminTasks';

/**
* Setup the chainlinkConversionPath values once deployed
* @param contractAddress address of the ChainlinkConversionPath contract
* @param hre Hardhat runtime environment
*/
export const setupChainlinkConversionPath = async (
contractAddress: string,
hre: HardhatRuntimeEnvironmentExtended,
): Promise<void> => {
// Setup contract parameters
const ChainlinkConversionPathContract = new hre.ethers.Contract(
contractAddress,
chainlinkConversionPath.getContractAbi(),
);
await Promise.all(
hre.config.xdeploy.networks.map(async (network) => {
try {
const { signer, txOverrides } = await getSignerAndGasFees(network, hre);
const nativeTokenHash = CurrencyManager.getDefault().getNativeCurrency(
RequestLogicTypes.CURRENCY.ETH,
network,
)?.hash;
if (!nativeTokenHash) {
throw new Error(`Could not guess native token hash for network ${network}`);
}
const ChainlinkConversionPathConnected = ChainlinkConversionPathContract.connect(signer);
await updateNativeTokenHash(
'ChainlinkConversionPath',
ChainlinkConversionPathConnected,
nativeTokenHash,
txOverrides,
);
console.log(`Setup of ChainlinkConversionPath successful on ${network}`);
} catch (err) {
console.warn(`An error occurred during the setup of ChainlinkConversionPath on ${network}`);
console.warn(err);
}
}),
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { erc20SwapToPayArtifact } from '../../src/lib';
import { HardhatRuntimeEnvironmentExtended } from '../types';
import { getSignerAndGasFees, updateRequestSwapFees, updateSwapRouter } from './adminTasks';

/**
* Once deployed, setup the values of the ERC20SwapToPay contract
* @param contractAddress address of the ERC20SwapToPay Proxy
* @param hre Hardhat runtime environment
*/
export const setupERC20SwapToPay = async (
contractAddress: string,
hre: HardhatRuntimeEnvironmentExtended,
): Promise<void> => {
// Setup contract parameters
const ERC20SwapToPayContract = new hre.ethers.Contract(
contractAddress,
erc20SwapToPayArtifact.getContractAbi(),
);
await Promise.all(
hre.config.xdeploy.networks.map(async (network) => {
try {
const { signer, txOverrides } = await getSignerAndGasFees(network, hre);
const ERC20SwapToPayConnected = await ERC20SwapToPayContract.connect(signer);

await updateSwapRouter(ERC20SwapToPayConnected, network, txOverrides);
await updateRequestSwapFees(ERC20SwapToPayConnected, txOverrides);
console.log(`Setup of ERC20SwapToPay successful on ${network}`);
} catch (err) {
console.warn(`An error occurred during the setup of ERC20SwapToPay on ${network}`);
console.warn(err);
}
}),
);
};
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { CurrencyManager } from '@requestnetwork/currency';
import { RequestLogicTypes } from '@requestnetwork/types';
import { ethConversionArtifact } from '../../src/lib';
import { HardhatRuntimeEnvironmentExtended } from '../types';
import {
getSignerAndGasFees,
updateChainlinkConversionPath,
updateNativeTokenHash,
updatePaymentFeeProxyAddress,
} from './adminTasks';

Expand All @@ -24,6 +27,13 @@ export const setupETHConversionProxy = async (
hre.config.xdeploy.networks.map(async (network) => {
try {
const { signer, txOverrides } = await getSignerAndGasFees(network, hre);
const nativeTokenHash = CurrencyManager.getDefault().getNativeCurrency(
RequestLogicTypes.CURRENCY.ETH,
network,
)?.hash;
if (!nativeTokenHash) {
throw new Error(`Could not guess native token hash for network ${network}`);
}
const EthConversionProxyConnected = EthConversionProxyContract.connect(signer);
await updatePaymentFeeProxyAddress(
EthConversionProxyConnected,
Expand All @@ -32,6 +42,12 @@ export const setupETHConversionProxy = async (
'native',
);
await updateChainlinkConversionPath(EthConversionProxyConnected, network, txOverrides);
await updateNativeTokenHash(
'EthConversionProxy',
EthConversionProxyConnected,
nativeTokenHash,
txOverrides,
);
console.log(`Setup of EthConversionProxy successful on ${network}`);
} catch (err) {
console.warn(`An error occurred during the setup of EthConversionProxy on ${network}`);
Expand Down
26 changes: 20 additions & 6 deletions packages/smart-contracts/scripts-create2/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import { IDeploymentParams } from './types';
import { HardhatRuntimeEnvironmentExtended } from './types';
import { xdeploy } from './xdeployer';
import { getConstructorArgs } from './constructor-args';
import { setupERC20SwapToConversion } from './contract-setup';
import { setupBatchConversionPayments } from './contract-setup/setupBatchConversionPayments';
import { setupETHConversionProxy } from './contract-setup/setupETHConversionProxy';
import { setupErc20ConversionProxy } from './contract-setup/setupErc20ConversionProxy';
import {
setupERC20SwapToConversion,
setupERC20SwapToPay,
setupBatchConversionPayments,
setupETHConversionProxy,
setupErc20ConversionProxy,
setupChainlinkConversionPath,
} from './contract-setup';

// Deploys, set up the contracts and returns the address
export const deployOneWithCreate2 = async (
Expand Down Expand Up @@ -60,9 +64,13 @@ export const deployWithCreate2FromList = async (
await deployOneWithCreate2({ contract, constructorArgs }, hre);
break;
}
case 'ChainlinkConversionPath': {
const constructorArgs = getConstructorArgs(contract);
const address = await deployOneWithCreate2({ contract, constructorArgs }, hre);
await setupChainlinkConversionPath(address, hre);
break;
}
case 'EthConversionProxy': {
// FIXME: not deployable through xdeployer yet. Check FIXME in getConstrucotrArgs function
throw new Error('EthConversionProxy not deployable through xdeployer yet');
const constructorArgs = getConstructorArgs(contract);
const address = await deployOneWithCreate2({ contract, constructorArgs }, hre);
await setupETHConversionProxy(address, hre);
Expand All @@ -74,6 +82,12 @@ export const deployWithCreate2FromList = async (
await setupErc20ConversionProxy(address, hre);
break;
}
case 'ERC20SwapToPay': {
const constructorArgs = getConstructorArgs(contract);
const address = await deployOneWithCreate2({ contract, constructorArgs }, hre);
await setupERC20SwapToPay(address, hre);
break;
}
case 'ERC20SwapToConversion': {
const constructorArgs = getConstructorArgs(contract);
const address = await deployOneWithCreate2({ contract, constructorArgs }, hre);
Expand Down
12 changes: 6 additions & 6 deletions packages/smart-contracts/scripts-create2/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import * as artifacts from '../src/lib';
* If you want to skip deploying one or more, then comment them out in the list bellow.
*/
export const create2ContractDeploymentList = [
/* 'ChainlinkConversionPath',
'EthereumProxy',
'EthereumFeeProxy',
'ERC20FeeProxy',
'ERC20SwapToConversion',
'EthConversionProxy',
'ERC20FeeProxy', */
'ERC20SwapToPay',
/* 'ERC20SwapToConversion',
'ERC20EscrowToPay',
'BatchConversionPayments',
// FIXME: EthConversionProxy cannot be deployed using xDeployer yet
// We need to be able to administrate the nativeTokenHash first.
// 'EthConversionProxy',
'BatchConversionPayments', */
];

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/smart-contracts/scripts-create2/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ export async function VerifyCreate2FromList(hre: HardhatRuntimeEnvironmentExtend
try {
await delay();
switch (contract) {
case 'ChainlinkConversionPath':
case 'EthereumProxy':
case 'EthereumFeeProxy':
case 'EthConversionProxy':
case 'ERC20FeeProxy':
case 'ERC20SwapToPay':
case 'ERC20SwapToConversion':
case 'Erc20ConversionProxy': {
const constructorArgs = getConstructorArgs(contract);
Expand Down
Loading

0 comments on commit bfbe7a0

Please sign in to comment.