Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
60a9284
add advanced logic and specs for any to eth
vrolland Sep 29, 2021
659a4ff
Merge branch 'master' into any-to-eth-adv-logic
vrolland Sep 29, 2021
558978a
add types
vrolland Sep 29, 2021
d19acc5
gather chainlink supported currencies
vrolland Sep 29, 2021
0301e1d
add tests
vrolland Sep 29, 2021
b32ecdf
feat: Payment netwrok any-to-eth smartcontracts
vrolland Sep 29, 2021
2cba701
fix from YMA review
vrolland Sep 29, 2021
5adabec
from YMA review 2
vrolland Sep 29, 2021
7cc050a
Merge branch 'any-to-eth-adv-logic' into any-to-eth-smartcontracts
vrolland Sep 29, 2021
4593ade
add native token hash on the constructor
vrolland Sep 29, 2021
91df39e
Merge branch 'master' into any-to-eth-adv-logic
vrolland Sep 30, 2021
577a48f
Update packages/advanced-logic/specs/payment-network-any-to-eth-proxy…
vrolland Sep 30, 2021
dfd5fe2
rename chainlink to conversion
vrolland Sep 30, 2021
b9b41a5
remove defult network
vrolland Sep 30, 2021
ba44ed2
network mandatory
vrolland Sep 30, 2021
8a3e862
fix import
vrolland Sep 30, 2021
a52fbad
fix commit
vrolland Sep 30, 2021
8976c58
Merge branch 'any-to-eth-adv-logic' into any-to-eth-smartcontracts
vrolland Sep 30, 2021
cf163d8
Merge branch 'master' into any-to-eth-adv-logic
vrolland Sep 30, 2021
caeae86
rename test var
vrolland Sep 30, 2021
68325a2
Merge branch 'master' into any-to-eth-adv-logic
vrolland Sep 30, 2021
af3961e
from BJU revieuw
vrolland Sep 30, 2021
b663f56
Merge branch 'any-to-eth-adv-logic' into any-to-eth-smartcontracts
vrolland Sep 30, 2021
9035394
Merge branch 'master' into any-to-eth-smartcontracts
vrolland Sep 30, 2021
433fc62
Merge branch 'master' into any-to-eth-smartcontracts
vrolland Oct 1, 2021
ebb5208
Update packages/smart-contracts/src/contracts/EthConversionProxy.sol
vrolland Oct 4, 2021
c5ee3a2
from BLE review
vrolland Oct 4, 2021
75a6561
add comment
vrolland Oct 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions packages/smart-contracts/scripts/3_deploy_chainlink_contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import '@nomiclabs/hardhat-ethers';
import { CurrencyManager } from '@requestnetwork/currency';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import deployERC20ConversionProxy from './erc20-conversion-proxy';
import deployEthConversionProxy from './eth-conversion-proxy';
import deploySwapConversion from './erc20-swap-to-conversion';
import { deployOne } from './deploy-one';

Expand All @@ -15,9 +16,9 @@ export default async function deploy(args: any, hre: HardhatRuntimeEnvironment)

const currencyManager = CurrencyManager.getDefault();
// all these addresses are for test purposes
const ETH_address = currencyManager.fromSymbol('ETH')!.hash;
const USD_address = currencyManager.fromSymbol('USD')!.hash;
const EUR_address = currencyManager.fromSymbol('EUR')!.hash;
const ETH_hash = currencyManager.fromSymbol('ETH')!.hash;
const USD_hash = currencyManager.fromSymbol('USD')!.hash;
const EUR_hash = currencyManager.fromSymbol('EUR')!.hash;
// Cf. ERC20Alpha in TestERC20.sol
const DAI_address = '0x38cF23C52Bb4B13F051Aec09580a2dE845a7FA35';

Expand All @@ -31,8 +32,8 @@ export default async function deploy(args: any, hre: HardhatRuntimeEnvironment)

// all these aggregators are for test purposes
await conversionPathInstance.updateAggregatorsList(
[DAI_address, EUR_address, ETH_address, USDT_address],
[USD_address, USD_address, USD_address, ETH_address],
[DAI_address, EUR_hash, ETH_hash, USDT_address],
[USD_hash, USD_hash, USD_hash, ETH_hash],
[AggDAI_USD_address, AggEUR_USD_address, AggETH_USD_address, AggUSDT_ETH_address],
);
console.log('AggregatorsList updated.');
Expand Down Expand Up @@ -65,6 +66,16 @@ export default async function deploy(args: any, hre: HardhatRuntimeEnvironment)
// FIXME: should try to retrieve information from artifacts instead
await erc20SwapConversion.approveRouterToSpend('0x9FBDa871d559710256a2502A2517b794B482Db40');

// EthConversion
const ethConversionProxyAddress = await deployEthConversionProxy(
{
...args,
chainlinkConversionPathAddress: conversionPathInstance.address,
ethFeeProxyAddress: '0x3d49d1eF2adE060a33c6E6Aa213513A7EE9a6241',
nativeTokenHash: ETH_hash,
},
hre,
);
// ----------------------------------
console.log('Contracts deployed');
console.log(`
Expand All @@ -73,5 +84,6 @@ export default async function deploy(args: any, hre: HardhatRuntimeEnvironment)
ChainlinkConversionPath: ${conversionPathInstance.address}
Erc20ConversionProxy: ${erc20ConversionAddress}
Erc20SwapConversionProxy: ${erc20SwapConversionAddress}
EthConversionProxy: ${ethConversionProxyAddress}
`);
}
33 changes: 33 additions & 0 deletions packages/smart-contracts/scripts/eth-conversion-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { deployOne } from './deploy-one';

export default async function deploy(
args: { chainlinkConversionPathAddress?: string; ethFeeProxyAddress?: string, nativeTokenHash?: string },
hre: HardhatRuntimeEnvironment,
) {
const contractName = 'EthConversionProxy';

if (!args.chainlinkConversionPathAddress) {
// FIXME: should try to retrieve information from artifacts instead
console.error(
`Missing ChainlinkConversionPath on ${hre.network.name}, cannot deploy ${contractName}.`,
);
return;
}
if (!args.ethFeeProxyAddress) {
// FIXME: should try to retrieve information from artifacts instead
console.error(`Missing EthereumFeeProxy on ${hre.network.name}, cannot deploy ${contractName}.`);
return;
}

if (!args.nativeTokenHash) {
console.error(`Missing nativeTokenHash on ${hre.network.name}, cannot deploy ${contractName}.`);
return;
}

return deployOne(args, hre, contractName, [
args.ethFeeProxyAddress,
args.chainlinkConversionPathAddress,
args.nativeTokenHash,
]);
}
124 changes: 124 additions & 0 deletions packages/smart-contracts/src/contracts/EthConversionProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ChainlinkConversionPath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

/**
* @title EthConversionProxy
* @notice This contract converts from chainlink then swaps ETH (or native token)
* before paying a request thanks to a conversion payment proxy.
* The inheritance from ReentrancyGuard is required to perform
* "transferExactEthWithReferenceAndFee" on the eth-fee-proxy contract
*/
contract EthConversionProxy is ReentrancyGuard {
address public paymentProxy;
ChainlinkConversionPath public chainlinkConversionPath;
address public nativeTokenHash;

constructor(address _paymentProxyAddress, address _chainlinkConversionPathAddress, address _nativeTokenHash) {
paymentProxy = _paymentProxyAddress;
chainlinkConversionPath = ChainlinkConversionPath(_chainlinkConversionPathAddress);
nativeTokenHash = _nativeTokenHash;
}

// Event to declare a conversion with a reference
event TransferWithConversionAndReference(
uint256 amount,
address currency,
bytes indexed paymentReference,
uint256 feeAmount,
uint256 maxRateTimespan
);

// Event to declare a transfer with a reference
// This event is emitted by this contract from a delegate call of the payment-proxy
event TransferWithReferenceAndFee(
address to,
uint256 amount,
bytes indexed paymentReference,
uint256 feeAmount,
address feeAddress
);

/**
* @notice Performs an ETH transfer with a reference computing the payment amount based on the request amount
* @param _to Transfer recipient of the payement
* @param _requestAmount Request amount
* @param _path Conversion path
* @param _paymentReference Reference of the payment related
* @param _feeAmount The amount of the payment fee
* @param _feeAddress The fee recipient
* @param _maxRateTimespan Max time span with the oldestrate, ignored if zero
*/
function transferWithReferenceAndFee(
address _to,
uint256 _requestAmount,
address[] calldata _path,
bytes calldata _paymentReference,
uint256 _feeAmount,
address _feeAddress,
uint256 _maxRateTimespan
)
external
payable
{
require(
_path[_path.length - 1] == nativeTokenHash,
"payment currency must be the native token"
);

(uint256 amountToPay, uint256 amountToPayInFees) = getConversions(
_path,
_requestAmount,
_feeAmount,
_maxRateTimespan);

// Pay the request and fees
(bool status, ) = paymentProxy.delegatecall(
abi.encodeWithSignature(
"transferExactEthWithReferenceAndFee(address,uint256,bytes,uint256,address)",
_to,
amountToPay,
_paymentReference,
amountToPayInFees,
_feeAddress
)
);

require(status, "paymentProxy transferExactEthWithReferenceAndFee failed");

// Event to declare a transfer with a reference
emit TransferWithConversionAndReference(
_requestAmount,
// request currency
_path[0],
_paymentReference,
_feeAmount,
_maxRateTimespan
);
}

function getConversions(
address[] memory _path,
uint256 _requestAmount,
uint256 _feeAmount,
uint256 _maxRateTimespan
)
internal
view
returns (uint256 amountToPay, uint256 amountToPayInFees)
{
(uint256 rate, uint256 oldestTimestampRate, uint256 decimals) = chainlinkConversionPath.getRate(_path);

// Check rate timespan
require(
_maxRateTimespan == 0 || block.timestamp - oldestTimestampRate <= _maxRateTimespan,
"aggregator rate is outdated"
);

// Get the amount to pay in the native token
amountToPay = (_requestAmount * rate) / decimals;
amountToPayInFees = (_feeAmount * rate) /decimals;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
{
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_paymentProxyAddress",
"type": "address"
},
{
"internalType": "address",
"name": "_chainlinkConversionPathAddress",
"type": "address"
},
{
"internalType": "address",
"name": "_nativeTokenHash",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "currency",
"type": "address"
},
{
"indexed": true,
"internalType": "bytes",
"name": "paymentReference",
"type": "bytes"
},
{
"indexed": false,
"internalType": "uint256",
"name": "feeAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "maxRateTimespan",
"type": "uint256"
}
],
"name": "TransferWithConversionAndReference",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": true,
"internalType": "bytes",
"name": "paymentReference",
"type": "bytes"
},
{
"indexed": false,
"internalType": "uint256",
"name": "feeAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "feeAddress",
"type": "address"
}
],
"name": "TransferWithReferenceAndFee",
"type": "event"
},
{
"inputs": [],
"name": "chainlinkConversionPath",
"outputs": [
{
"internalType": "contract ChainlinkConversionPath",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "nativeTokenHash",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "paymentProxy",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_requestAmount",
"type": "uint256"
},
{
"internalType": "address[]",
"name": "_path",
"type": "address[]"
},
{
"internalType": "bytes",
"name": "_paymentReference",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_feeAmount",
"type": "uint256"
},
{
"internalType": "address",
"name": "_feeAddress",
"type": "address"
},
{
"internalType": "uint256",
"name": "_maxRateTimespan",
"type": "uint256"
}
],
"name": "transferWithReferenceAndFee",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
]
}
Loading