Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
7 changes: 7 additions & 0 deletions common/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ export interface ITokens {
// Mountain
USDM?: string
wUSDM?: string

// NUM
snARS?: string
nARS?: string
}

export type ITokensKeys = Array<keyof ITokens>
Expand Down Expand Up @@ -513,6 +517,8 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
sUSDbC: '0x4c80e24119cfb836cdf0a6b53dc23f04f7e652ca',
wstETH: '0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452',
STG: '0xE3B53AF74a4BF62Ae5511055290838050bf764Df',
snARS: '0xC1F4C75e8925A67BE4F35D6b1c044B5ea8849a58',
nARS: '0x5e40f26E89213660514c51Fb61b2d357DBf63C85',
},
chainlinkFeeds: {
DAI: '0x591e79239a7d679378ec8c847e5038150364c78f', // 0.3%, 24hr
Expand All @@ -529,6 +535,7 @@ export const networkConfig: { [key: string]: INetworkConfig } = {
stETHETH: '0xf586d0728a47229e747d824a939000Cf21dEF5A0', // 0.5%, 24h
ETHUSD: '0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70', // 0.15%, 20min
wstETHstETH: '0xB88BAc61a4Ca37C43a3725912B1f472c9A5bc061', // 0.5%, 24h
nARS: '0xC3a426Ef79fd60A4cA785FC04a2C3cB09d2FEeae', // 0.5%, 15min
},
GNOSIS_EASY_AUCTION: '0xb1875Feaeea32Bbb02DE83D81772e07E37A40f02', // mock
COMET_REWARDS: '0x123964802e6ABabBE1Bc9547D72Ef1B69B00A6b1',
Expand Down
32 changes: 32 additions & 0 deletions contracts/plugins/assets/num/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Collateral Plugins for nARS and snARS

## Summary

This plugin allows `nARS` and `snARS` holders to use their tokens as collateral in the Reserve Protocol.

As described in the [Num Site](https://new.num.finance/) nTokens are ERC20 tokens, tracking the value of an underlying financial asset.
Each nToken issued by Num Finance is fully collateralized by an asset in the traditional market. This means that for every nToken in circulation, there is a real-world asset backing it, ensuring the token's value and stability.

In this particular case we're incorporating through this plugin 2 nTokens.
- `nARS` is a stablecoin pegged to the `Argentine Peso (ARS)`.
- `snARS` is the staked version of `nARS`. When users stake their `nARS`, they receive `snARS` in return, which grants them certain benefits in the form of yield or Numun Rewards.

Staking of `nARS` is possible at: https://numun.fi/
Official num website: https://num.finance/
nStables documentation: https://docs.nstables.fi/

## Implementation

### Units

| tok | ref | target | UoA |
| ---- | ---- | ------ | --- |
| nARS | ARS | ARS | USD |

| tok | ref | target | UoA |
| ---- | ---- | ------ | --- |
| sNARS | ARS | ARS | USD |

### claimRewards()

There are no rewards to claim
21 changes: 21 additions & 0 deletions contracts/plugins/assets/num/SnARSFiatCollateral.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: BlueOak-1.0.0
pragma solidity 0.8.19;

import { CollateralConfig } from "../AppreciatingFiatCollateral.sol";
import { ERC4626FiatCollateral } from "../ERC4626FiatCollateral.sol";

/**
* @title SnARSFiatCollateral
* @notice Collateral plugin for a Num vault with fiat collateral
* Expected: {tok} != {ref}, {ref} is pegged to {target} unless defaulting, {target} == ARS, {UoA} == USD
*/
contract SnARSFiatCollateral is ERC4626FiatCollateral {
/// config.erc20 must be a Num ERC4626 vault
/// @param config.chainlinkFeed Feed units: {UoA/ref}
/// @param revenueHiding {1} A value like 1e-6 that represents the maximum refPerTok to hide
constructor(CollateralConfig memory config, uint192 revenueHiding)
ERC4626FiatCollateral(config, revenueHiding)
{
require(config.defaultThreshold != 0, "defaultThreshold zero");
}
}
24 changes: 24 additions & 0 deletions scripts/deployment/phase2-assets/2_deploy_collateral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,30 @@ async function main() {
fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2))
}

/******** Deploy Fiat Collateral - nARS **************************/
if (networkConfig[chainId].tokens.nARS && networkConfig[chainId].chainlinkFeeds.nARS) {
const { collateral: narsCollateral } = await hre.run('deploy-fiat-collateral', {
priceTimeout: priceTimeout.toString(),
priceFeed: networkConfig[chainId].chainlinkFeeds.nARS,
oracleError: fp('0.005').toString(), // 0.5%
tokenAddress: networkConfig[chainId].tokens.nARS,
maxTradeVolume: fp('1e6').toString(), // $1m,
oracleTimeout: '900',
targetName: hre.ethers.utils.formatBytes32String('ARS'),
defaultThreshold: fp('0.01').toString(), // 1.5%
Comment thread
pmckelvy1 marked this conversation as resolved.
Outdated
delayUntilDefault: bn('86400').toString(), // 24h
})
collateral = <ICollateral>await ethers.getContractAt('ICollateral', narsCollateral)
await (await collateral.refresh()).wait()
expect(await collateral.status()).to.equal(CollateralStatus.SOUND)

assetCollDeployments.collateral.nARS = narsCollateral
assetCollDeployments.erc20s.nARS = networkConfig[chainId].tokens.nARS
deployedCollateral.push(narsCollateral.toString())

fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2))
}

/*** AAVE V2 not available in Base or Arbitrum L2s */
if (!baseL2Chains.includes(hre.network.name) && !arbitrumL2Chains.includes(hre.network.name)) {
/******** Deploy AToken Fiat Collateral - aDAI **************************/
Expand Down
83 changes: 83 additions & 0 deletions scripts/deployment/phase2-assets/collaterals/deploy_snARS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import fs from 'fs'
import hre from 'hardhat'
import { getChainId } from '../../../../common/blockchain-utils'
import { networkConfig } from '../../../../common/configuration'
import { bn, fp } from '../../../../common/numbers'
import { expect } from 'chai'
import { CollateralStatus } from '../../../../common/constants'
import {
getDeploymentFile,
getAssetCollDeploymentFilename,
IAssetCollDeployments,
getDeploymentFilename,
fileExists,
} from '../../common'
import { priceTimeout } from '../../utils'
import { SnARSFiatCollateral } from '../../../../typechain'
import { ContractFactory } from 'ethers'

async function main() {
// ==== Read Configuration ====
const [deployer] = await hre.ethers.getSigners()

const chainId = await getChainId(hre)

console.log(`Deploying Collateral to network ${hre.network.name} (${chainId})
with burner account: ${deployer.address}`)

if (!networkConfig[chainId]) {
throw new Error(`Missing network configuration for ${hre.network.name}`)
}

// Get phase1 deployment
const phase1File = getDeploymentFilename(chainId)
if (!fileExists(phase1File)) {
throw new Error(`${phase1File} doesn't exist yet. Run phase 1`)
}
// Check previous step completed
const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId)
const assetCollDeployments = <IAssetCollDeployments>getDeploymentFile(assetCollDeploymentFilename)

const deployedCollateral: string[] = []

/******** Deploy snARS Collateral - snARS **************************/

const nuARSCollateralFactory: ContractFactory = await hre.ethers.getContractFactory(
'FiatCollateral'
)

const collateral = <SnARSFiatCollateral>await nuARSCollateralFactory.connect(deployer).deploy(
{
priceTimeout: priceTimeout.toString(),
chainlinkFeed: networkConfig[chainId].chainlinkFeeds.snARS,
oracleError: fp('0.005').toString(), // 0.5%
erc20: networkConfig[chainId].tokens.snARS,
maxTradeVolume: fp('1e6').toString(), // $1m,
oracleTimeout: '900', // 15min
targetName: hre.ethers.utils.formatBytes32String('ARS'),
defaultThreshold: fp('0.015').toString(), // 2% = 0.5% oracleError + 1% buffer
delayUntilDefault: bn('86400').toString(), // 24h
},
'0' // revenueHiding = 0
)
await collateral.deployed()

console.log(`Deployed snARS to ${hre.network.name} (${chainId}): ${collateral.address}`)
await (await collateral.refresh()).wait()
expect(await collateral.status()).to.equal(CollateralStatus.SOUND)

assetCollDeployments.collateral.snARS = collateral.address
assetCollDeployments.erc20s.snARS = networkConfig[chainId].tokens.snARS
deployedCollateral.push(collateral.address.toString())

fs.writeFileSync(assetCollDeploymentFilename, JSON.stringify(assetCollDeployments, null, 2))

console.log(`Deployed collateral to ${hre.network.name} (${chainId})
New deployments: ${deployedCollateral}
Deployment file: ${assetCollDeploymentFilename}`)
}

main().catch((error) => {
console.error(error)
process.exitCode = 1
})
53 changes: 53 additions & 0 deletions scripts/verification/collateral-plugins/verify_snARS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import hre from 'hardhat'
import { getChainId } from '../../../common/blockchain-utils'
import { developmentChains, networkConfig } from '../../../common/configuration'
import { fp, bn } from '../../../common/numbers'
import {
getDeploymentFile,
getAssetCollDeploymentFilename,
IAssetCollDeployments,
} from '../../deployment/common'
import { priceTimeout, verifyContract } from '../../deployment/utils'

let deployments: IAssetCollDeployments

async function main() {
// ********** Read config **********
const chainId = await getChainId(hre)
if (!networkConfig[chainId]) {
throw new Error(`Missing network configuration for ${hre.network.name}`)
}

if (developmentChains.includes(hre.network.name)) {
throw new Error(`Cannot verify contracts for development chain ${hre.network.name}`)
}

const assetCollDeploymentFilename = getAssetCollDeploymentFilename(chainId)
deployments = <IAssetCollDeployments>getDeploymentFile(assetCollDeploymentFilename)

/******** Verify snARS **************************/
await verifyContract(
chainId,
deployments.collateral.snARS,
[
{
priceTimeout: priceTimeout.toString(),
chainlinkFeed: networkConfig[chainId].chainlinkFeeds.snARS,
oracleError: fp('0.01').toString(), // 1%
erc20: networkConfig[chainId].tokens.snARS,
maxTradeVolume: fp('1e6').toString(), // $1m,
oracleTimeout: '3600', // 1 hr
targetName: hre.ethers.utils.formatBytes32String('ARS'),
defaultThreshold: fp('0.02').toString(), // 2%
delayUntilDefault: bn('86400').toString(), // 24h
},
'0', // revenueHiding = 0
],
'contracts/plugins/assets/num/SnARSFiatCollateral.sol:SnARSFiatCollateral'
)
}

main().catch((error) => {
console.error(error)
process.exitCode = 1
})
1 change: 1 addition & 0 deletions test/plugins/individual-collateral/collateralTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
} from '../../../typechain'
import snapshotGasCost from '../../utils/snapshotGasCost'
import { IMPLEMENTATION, Implementation, ORACLE_ERROR, PRICE_TIMEOUT } from '../../fixtures'
import { NUM_HOLDER } from './num/constants'

const getDescribeFork = (targetNetwork = 'mainnet') => {
return useEnv('FORK') && useEnv('FORK_NETWORK') === targetNetwork ? describe : describe.skip
Expand Down
Loading