pancakeswap-reserve-calculate

pancakeswap 如何通过 reserve 计算 amountOut 金额

无常损失

当你成了一个 AMM 的 LP(流动性提供者)的时候,那你的收益部分就来自于无常损失。
同时无常损失也不是永久性的,价格经过短暂的下跌之后又重新恢复。为什么会在短时间内恢复呢?正式通过一个个搬砖的人监控不同池子中的价格差价进行套利操作后使得不同池子中的价格达到一个平衡。无常损失的核心公式:

$$
K = A * B
$$

假设我们的池子中有两种货币 token0 和 token1,A 代表 token0 在池子中的剩余数量,B 代表 token1 在池子中的剩余数量,而 K 的值在池子创建的时候就固定了。并且在流动性变化的过程中 K 的值不是完全相等的,而是会有细微的偏差但是不会太大。
当价格发生变化的时候,价格我们兑换数量 amountIn 的 token0,为了使得 K 的值是相等的会得到一下的公式

$$
K = (A+amountIn)(B-amountOut)
$$

$$
amountOut = B - K/(A+amountIn)
$$

举个例子

下面我们拿一个 pancakeswap 的池子来实际算一下这个 amountOut(我们预估能得到的金额)。
为了测试方便我们拿了 bsc 测试网的池子,包含了 BUSD(0xab1a4d4f1d656d2450692d237fdd6c7f9146e814)和 WBNB(0xae13d989dac2f0debff460ac112a837c89baa7cd)两种货币。
pool address
通过 contract 的 ABI 可以看到相关的几个参数:

  • kLast
  • token0
  • token1
  • getReserves
    我们也可以直接通过 UI 界面找到相关的参数
    alt "ABI"

代码实现

这里我通过 python 读取了相关池子中的参数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from web3 import Web3
import json

# init w3 provider
# w3 = Web3(Web3.HTTPProvider("https://bsc-dataseed.binance.org"))
w3 = Web3(Web3.HTTPProvider(TESTNET_PROVIDER_ADDRESS_HERE))


def fetchPool(poolAddress):
with open("./abi/pancake.json", 'r') as json_file:
contract = w3.eth.contract(
address=poolAddress, abi=json.load(json_file))
reserves = contract.functions.getReserves().call()
# arr [reserve0, reserve1, timestamp]
return reserves

# 费用
fee = 0.0025

arr = fetchPool("0xa96818CA65B57bEc2155Ba5c81a70151f63300CD")
# token0 剩余数量
r0 = arr[0]
# token1 剩余数量
r1 = arr[1]
# K的值
k = r0 * r1
amountIn = 10**16
price1 = r1 - k/(r0+amountIn*(1-fee))
print(price1/10**18)
# output
# 606895316154

alt "ABI"
对于 pancakeswap 而言我们最终的输入价格 amountIn 要减掉一个 fee,pancakeswap UI 上预估的价格和计算的价格是对的上的。

how-to-be-successful

引言

如何获得成功?

我曾经观察了上千名的企业创始人,并且思考了这些人是如何赚取大量的金钱或者创造一些很重要的东西。通常人们开始的时候想要前者,但是最终得到了后者。
这里有 13 个关于如何取得如此突出的成功的想法。

1.复利

复利是有魔力的。尽可能的把它用在各种地方。指数曲线是创造财富的关键。如果一个中型企业能以每年百分之 50 的价值增长,那么它就能很快的成长为大型企业。
世界上很少的企业能够有真实的网路影响力和极致的可扩展性。但是随着科技的发展,越来越多的企业会具备这样的能力。我们值得为此付出很大的努力。
如果你个人也想获得这种曲线增长的话你应该把追踪这复利曲线轨迹作为你的人生目标。选择一种具有复利影响的事业是很重要的,大多数的职业发展是比较线性的。
你肯定不会想做那种多年经验的和较少经验的人对比起来的效率差不多的工作,你必须保持一个高频的学习。随着你的事业的发展,你所做的每个独立的工作内容都应该产生越来越多的成果。有很多种方式能够取得这种杠杆作用,比如资金、技术、个人品牌、网络影响力和人员管理。
我愿意花费尽可能多的事件在我的项目之间,来找到我后面要做的事情。我一直希望它是一个项目,如果成功了,将会成为我的职业生涯其中的一个注脚。
大部分人会陷入线性机会的泥潭。他们会专注于潜在的机会上,而忽略了一些小的机会。
我认为商业中最大的竞争优势,不管对于一个公司而言还是对个人而言,是长期对于世界上不同的系统如何广泛的融合在一起的思考。复利增长的显著方面之一是最远的年份越为重要。在现在这个几乎没人真在采用长远眼观看待问题的世界里,真在做到的人在市场上取得的回报是丰厚的。
相信指数的力量,保持耐心,风会来的。

2.自信到自恋

自信的力量是巨大的。我认识的最成功的人都自信到几乎自恋。
随着你的判断越来越准确,你可以持续的输出结果,那么你就会更加相信自己的判断。
如果你不相信自己,很难让自己对未来有个准确的判断。
我记得很多年前 Elon Musk 带我去参观他的 SpaceX 工厂。他和我详细的描述了至少火箭的每个步骤,但是最让我印象深刻的是他脸上表现出来的对于发射巨大的火箭到火星上的自信。后来我想到这可能就是信念的力量吧。
管理自己的士气和团队的士气往往是大多数努力中最具挑战性的。如果没有自信的话几乎不可能做到。不幸的是,在现实中你越是雄心勃勃,这个世界越会打击你。
大多数成功的人有至少有这么一次对未来有了正确的判断,但是大部分人认为他是错的。如果不是这样的话他们会面临很多竞争。
自信必须要和自我认知有个平衡。我曾经厌恶各种形式的批评,并且主动的回避它。但是现在我都积极的听取这些批评,并且假设它们都是对的,接下来决定是否要对这些问题采取行动。求实往往是很困难的并且通常非常痛苦,但是它能够把自信和自欺欺人区分开来。

3.学会独立思考

很难教别人学会创业精神,因为原创思维是很难教会别人的。学校不是建立来教这些的知识的,实际上学校教的内容反而与之相悖。你需要自己衡量和取舍。
通过第一原理的思维模式去思考并且得到一些新的想法的过程是很有意思的,你还可以和别人交流这些想法来使它更加完善。下一步我们需要找到便捷快速的方式在现实世界中去验证你的想法。
我可以失败很多次,但是我只需要对一次,这是企业家的思维。你需要给自己很多次的机会让自己得到哪怕一次幸运。
你学习到这些思维的最好机会就是当你遇到这种看似毫无办法的情况下。你遇到更新这种的情形,你就会对自己更加的自信。毅力来自于你发现你可以在被击倒的情况下重新站起来。

4.擅长销售

单单只有自信还不够,你还需要能说服别人你所相信的东西。
所有伟大的职业,在某种程度上,都成为了销售。你必须像你的客户、潜在员工、媒体、投资者宣传你的计划。这需要一个鼓舞人心的愿景,很强的沟通技巧,一定程度的人格魅力,和执行能力。
擅长沟通,特别是书面沟通,是一项值得投资精力进去的地方。我对沟通清楚的最好建议是首先你需要确保你的想法是清晰的,然后使用简单明了的语言去表达。
最好销售的最好方式是你真诚的相信你所卖的东西。推销你真行相信的东西的感觉是很棒的,而去卖一些类似减肥药的产品会让你感觉很糟糕。
练习好销售就像提升你的别的技能,任何人都可以通过练习来获得。但是由于某种原因,也许因为销售让人反感,许多人把他当做不能学习的技能。
My other big sales tip is to show up in person whenever it’s important. When I was first starting out, I was always willing to get on a plane. It was frequently unnecessary, but three times it led to career-making turning points for me that otherwise would have gone the other way.

5.学会冒险

6.专注

7.努力工作

8.大胆

9.任性

10.Be hard to compete with

11.Build a network

12.You get rich by owning things

13.Be internally driven

balancer-v2-vault

概览

本文主要介绍了在 balancer v2 上实现借贷并在一个交易中归还所借到的 token。

环境

  • node
  • hardhat(solidity 0.8.0)

Balancer v2 介绍

Balancer 是一个多链部署(Ethereum、Polygon、Arbitrum),基于 AMM(自动做市商)模型的 Dex。
Balancer 于 2020 年正式上线 V1 版本,并于 2021 年 5 月升级为 Balancer V2,目前市面上主要使用的都是基于 V2 的产品。
Balancer Vault 是一个安全的、非监管的数字资产保管库,可以用来将数字资产存储到 Balancer 池中,进行高效分散。Balancer Vault 是一种特殊的智能合约,可以在没有任何门槛的情况下,保护您的数字资产不受恶意攻击。此外,它还可以提供具有开放式架构和不断改进的即时更新能力的强大安全性功能,可以有效防止欺诈和非法交易。

Show me the code

solidity

1
2
3
4
5
6
7
8
9
...
function makeFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external {
vault.flashLoan(this, tokens, amounts, userData);
emit eventLog("making flash...");
}

完整代码:
https://gist.github.com/coffiasd/440c42e5a0211d096080ad5b1b50b4ae

部署代码

1
2
3
4
5
6
7
8
9
10
11
12
const hre = require("hardhat");

async function main() {
const Swap = await hre.ethers.getContractFactory("Swap");
const swap = await Swap.deploy();
await swap.deployed();
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const hre = require("hardhat");

async function main() {
const Bundle = await hre.ethers.getContractFactory("Swap");
const bundle = Bundle.attach("替换成部署完的合约地址");
console.log(bundle.address);
const tokenIn = "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6"; //weth
let ret = await bundle.makeFlashLoan(
[tokenIn],
[hre.ethers.utils.parseEther("1")],
[]
);
console.log(ret);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});

hardhat.config.js 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
require("dotenv").config();
require("@nomiclabs/hardhat-waffle");
require("@nomiclabs/hardhat-etherscan");

module.exports = {
solidity: "0.8.0",
networks: {
goerli: {
url: [process.env.GOERLI_ENDPOINT],
accounts: [process.env.PRIVATE_KEY],
}
}
};

运行代码

运行部署代码

1
npx hardhat run .\scripts\swap.js --network goerli

运行测试代码

1
npx hardhat run .\scripts\test.js --network goerli

输出

alt ""

interact-with-aptos-python

安装 python SDK

pip

1
pip install aptos-sdk

源码安装

1
2
3
git clone https://github.com/aptos-labs/aptos-core
cd aptos-core/ecosystem/python/sdk
python setup.py install --user

embedding

1
2
cd /path/to/python/project
cp -r /path/to/aptos-core/ecosystem/python/sdk/aptos-sdk aptos-sdk

账号创建 && 转账

https://gist.github.com/coffiasd/89a812c66ab10785bc8abd7dc6bc1ca4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python main.py
=== Addresses ===
Alice: 0x6a377fbf8e07576d8b11b7104a9100d6ecadfc9a6a3d809105b3822e84f170b6
Bob: 0x04807454e47d0c4e733ccec4de02cfc8d0cfb28e2c822db60e4bbffb5d0d821c

=== Initial Balances ===
Alice: 100000000
Bob: 0

=== Intermediate Balances ===
Alice: 99944800
Bob: 1000

=== Final Balances ===
Alice: 99889600
Bob: 2000

useRef and useState

Add a ref to your project

1
2
3
4
5
6
7
import {useRef} from 'react';
const ref = useRef(0);

//the ref'll be like this
{
current: 0 // The value you passed to useRef
}

Ref 使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useRef } from 'react';

export default function Counter() {
let ref = useRef(0);

function handleClick() {
ref.current = ref.current + 1;
alert('You clicked ' + ref.current + ' times!');
}

return (
<button onClick={handleClick}>
Click me!
</button>
);
}

这个用法看起来和 useState 差不多,使用 useState 也可以达到相同的效果,下面这个例子是 useState 的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useState } from 'react';

export default function Counter() {
let [ref,setRef] = useState(1);

function handleClick() {
setRef(ref+1);
alert('You clicked ' + ref + ' times!');
}

return (
<button onClick={handleClick}>
Click me!
</button>
);
}

那为什么还要多加一个 ref 呢?实际上是因为两者之间还是存在一些不同

useRef 和 useState 区别

# refs state
初始化后返回值 { current: initialValue } 返回值和设置函数
是否触发重新渲染
值的改变 可在渲染过程外改变值 只能通过设置函数
读写时间 不能在渲染期间读写 任何时间都能读写

基于上诉的区别我们再看下例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { useRef } from 'react';

export default function Counter() {
let countRef = useRef(0);

function handleClick() {
// This doesn't re-render the component!
countRef.current = countRef.current + 1;
}

return (
<button onClick={handleClick}>
You clicked {countRef.current} times
</button>
);
}

通过运行脚本我们会发现及时触发了点击事件并且改变了 countRef 的值,但是实际页面上没有任何的变化

useRef 的使用场景

  • 存储 timeout ID
  • 存储 DOM element
    我们再通过一个示例看下 useRef 的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { useState } from 'react';

export default function Chat() {
const [text, setText] = useState('');
const [isSending, setIsSending] = useState(false);
let timeoutID = null;

function handleSend() {
setIsSending(true);
timeoutID = setTimeout(() => {
alert('Sent!');
setIsSending(false);
}, 3000);
}

function handleUndo() {
setIsSending(false);
clearTimeout(timeoutID);
}

return (
<>
<input
disabled={isSending}
value={text}
onChange={e => setText(e.target.value)}
/>
<button
disabled={isSending}
onClick={handleSend}>
{isSending ? 'Sending...' : 'Send'}
</button>
{isSending &&
<button onClick={handleUndo}>
Undo
</button>
}
</>
);
}

通过运行我们会发现及时我们触发了 Undo 事件取消了 timeoutID,我们还是会再页面上收到 alert 信息?
这是因为我们页面在 re-render 的时候其实是读不到 timeoutID 这个本地变量的.通过 console.log 可以看到这个 undo 里面的 timeoutID 的值是 null。
我们只需要进行一些修改:

1
2
3
4
5
const timeoutRef = useRef(null);

timeoutRef.current = ....

clearTimeout(timeoutRef.current);

What is solidity unchecked

unchecked 的官网定义

unchecked 在 solidity 0.8 版本中加入,先看下官网的定义

  • Arithmetic operations revert on underflow and overflow. You can use unchecked { … } to use the previous wrapping behaviour.
  • Checks for overflow are very common, so we made them the default to increase readability of code, even if it comes at a slight increase of gas costs.
    因为检查溢出的情况非常普遍,所以即使会增加 gas 费用我们还是将检查溢出设置为默认情况。但是在 0.8 版本之后你可以在函数中添加 unchecked{…}块来使这部分代码不需要再考虑溢出的情况。

接下来我们使用一个例子看下具体的区别

1
2
3
4
5
6
7
8
9
10
11
12
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

contract Counter {
uint8 public count = 0;

function increment() external returns(uint8) {
count --;

return count;
}
}

alt "unchecked"
溢出之后直接报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

contract Counter {
uint8 public count = 0;

function increment() external returns(uint8) {
unchecked{
count --;
}

return count;
}
}

alt "unchecked"
允许溢出 count 的值变为 type(int8).max

What is ERC20

what is ERC20 ?

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol

ERC20 中的 state 变量

1
2
3
4
5
6
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;

string private _name;
string private _symbol;
  • _balances:
    储存每个地址的余额
  • _allowances:
    在_approve()函数中使用,授权给目标地址固定的提款额度
  • _totalSupply(e.g.: 10000000000000000000000000000)
  • _name(e.g.: Matic Token)
  • symbol(e.g.: MATIC)

_appove

alt "appove"

transfer

public 属性且可以被重写,简单的调用了共用方法获得了 msg.sender 的地址调用了下面的_transfer 函数
alt "transfer"

_transfer

内部函数可以被重写
alt "_transfer"

allowance

alt "allowance"

transferFrom

alt "transferFrom"

Four primitive data type

这里我们介绍 4 种 solidity 的原始数据类型

  • boolean
  • uint
  • int
  • address

uint

uint 代表了无符号的整形,包含以下的几个范围的变量

  • uint8 大小从 0 - 2**8 -1
  • uint16 大小从 0 - 2**16 -1
  • uint32 大小从 0 - 2**32 -1
  • uint64 大小从 0 - 2**64 -1
  • uint128 大小从 0 - 2**128 -1
  • uint256 大小从 0 - 2**256 -1

声明方式:
uint8 public u8 = 1;
当我们声明 uint 的时候没有指定范围的时候默认为 uint256:
uint public u = 1; 这里的 u 为 uint256
在具体的使用过程中我们可以根据范围需求去决定具体使用哪个范围的 uint.

int

int 代表了有符号的整形,和 uint 相似,只是因为占用了一位来代表符号导致了最终的范围和 uint 不一样.
举个例子:
int256 的范围从 -2 ** 255 到 2 ** 255 - 1

范围测试

我们可以直接在 http://remix.ethereum.org/ 上进行测试,得到最终的返回值.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Learn{
uint8 public u = 1;

constructor(){
u = 20;
}

function testUintRange() public pure returns (uint8){
// 这个输出是255
return type(uint8).max;
}

}

boolean 值

1
2
3
4
5
6
7
8
9
10
11
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Learn{
bool public defaultBoo = true;

function testUintRange() public view returns (bool){
return defaultBoo;
}

}

address

ETH 使用 hash 函数(keccak-256)来生成地址。在 ETH 或者 solidity 中,一个地址由 20byte 长度的值组成,这个地址对应于公钥的 hash 函数(keccak-256)的最后 20bytes 的值。一个地址总固定是以 ox 开头,因为它是以 16 进制的格式表示的.

1
2
3
4
5
6
7
8
9
10
11
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;

contract Learn{
address public a = 0xE2bCb3e6e03B477DA0698e1b4ECf570D06B34Ce7;

function testAddress() public view returns (address){
return a;
}

}

How to quick start web3.storage

register an account

  • Email
  • Github (recommand)

install the client

1
2
3
4
javascript
npm install web3.storage
golang
go get github.com/web3-storage/go-w3s-client

create a client instance

1
2
3
4
5
6
7
8
//get the access token
function getAccessToken(){
return process.env.TOKEN
}
//creata an instance
function makeStorageClient(){
return new Web3storage({token:getAccessToken()})
}

preparing files for uploading

1
2
3
4
function getFiles(){
const fileInput = document.querySelector('input[type="file"]')
return fileInput.files
}

upload files to web3.storage

1
2
3
4
5
6
//async upload process
async function storageFiles(files){
const client = makeStorageClient()
const cid = await client.put(files)
return cid
}

directory wrapping

after uploading you’ll get a cid of the directory and then the entire link gonna be ipfs:///
to make a gateway link :

1
2
https://<cid>.ipfs.<gateway-host>/<filename>
https://<gateway-host>/ipfs/<cid>/<filename>

storing ipfs content archives?

if you already have some files you can use putCar client function.I don’t want to jump into this here.

how to access data we uploaded above ?

  • using an IPFS http gateway
  • using client library
  • ipfs command line
  • system command line

how to query web3.storage

1
2
3
4
async function checkStatus(cid){
const client = xxxx
const status = await client.status(cid)
}

return data structure

  • cid
  • created
  • dagSize
  • pins
  • deals

how to list files uploaded to web3.storage

1
2
3
4
const client = xxxx
for await (const upload of client.list(){
console.log(upload.name,upload.cid,upload.dagSize)
})

listing the content of an IPFS directory

How to write a reserve plugin part 2

Contructor params of a collateral contract

  • fallbackPrice
  • chainlinkFeed
  • ERC20+rewardERC20
  • maxTradeVolume
  • oracleTimeout
  • targetName
  • delayUnitDefault

What’s fallbackPrice?

fallback price is when we try to get the real price but revert then we provide a fallback price.
fallback price is return when function price(bool allowFallback) is called and the param past in is true.
In the price() function we’ll call strictPrice() function first once it revert we’ll check if the value of allowFallback is true. If false return value is (isFallback-bool,fallbackPrice)
the unit of fallback price if {UoA}

What’s chainlinkFeed ?

Firstly ,it’s been created by chainlink.The interface allows your contract run functions on that deployed aggregator contract. For example ,you can use chainlink data feed to connect your smart contract to asset pricing data like the ETH/USD feed.
the unit of feed is {UoA/tok}

What’s ERC20 ?

this is import from openzeppein/contracts/token/ERC20/extensions/IERC20Metadata.sql
IERC20Metadata is inherit IERC20
some function like transfer,totalSuoply,balanceOf,approve,transferFrom all we need to create an ERC20 token.

What’s max trade volume?

the unit of max trade price if {UoA}

What’s oracle timeout?

the number of seconds until a oracle value becomes invalid.Otherwise we have to change the collateral status by calling markStatus().

What’s target name?

the canonical name of this collateral’s target unit.

What’s delayUnitDefault?

the number of seconds an oracle can mulfunction.
this value is used when we call markStatus() function.
when collateral status is “IFFY” . smart contract compare blocktime+delayUnitDfault and _whenDefault and then return the min(Math.min) one?

Reserve protocol introduce

All you need to know for writing a reserve protocol collateral plugins quick start

core plugin depends on two plugin types:

  • Assets / Collateral (contracts/plugins/assets)
  • Trading (contract/plugins/trading) not discussed here

Collateral is erc20 token + below:

  • if ERC20 back ?
  • refresh()
  • status() SOUND/IFFY/DISABLED
  • rate exchange

Monetary units

  • Unit of Account
  • Target unit
    RToken maintaining stability or appreciation against its target unit
  • Reference unit

e.g. of 3 different tokens

  • Collateral : cUSDC
  • Refence : USDC
  • Target : USD

Units definition

  • {UoA} unit of account recommand USD here
  • {tok} whole token
  • {ref} whole reference token
  • {target} whole target unit
  • {ref/tok} refPerTok()
  • {target/ref} targetPerRef()
  • {UoA/target} pricePerTarget()

Basket definition

  • Prime basket
    this is set by governance , on changes through successful governance proposals. it consists of an array of triples
    <collateral token,target unit,tartget amount>
    e.g. : <cUSDC,USD,0.1>
  • Reference basket
    <collateral token,reference unit,reference amount>
    e.g. : <aDAI,DAI,0.33>
  • Collateral bascket
    <collateral token,token amount>
    e.g.: <cUSDC,0.29>

IAsset interface

alt "interface"

Accounting units

before we create a collateral plugin we have to choose 3 accounting units

Collateral unit

its just erc20 token

Reference unit

to be ask , what’s a unit that this collateral token will always be worth the same value or more of .

Target unit

target unit has to do with a concept called the target basket. what’s prime basket ?
A example of linear combination of target units:

  • 1 USD
  • 0.5 USD + 0.55 EURO
  • 0.5 USD + 0.35 EURO + 0.00001BTC

Unit of account

we can assume UoA == USD , because for now USD price are king.

Important properties for collateral plugins

Collateral plugins should be permisionless and should be able to used by any number if RTokens
Token balance can’t be rebasing

refresh() should never be revert

refresh is been called before any transactions , it return exchange rates.
if occur an important error , refresh should change the state to DISABLED

strictPrice() price(bool) status()

the IFFY status should be temporary

Collateral must default if refPerTok() falls

Defaulted Collateral must stay defaulted

if status() ever returns disabled , then it must always return disabled in the nearly future

Token rewards should be claimable

  • rewardERC20()
  • getClaimCalldata()

Smaller Constraints

The value of the following methods should never change:

  • isColleteral()
  • targetName()
  • erc20()
  • rewardERC20()
  • erc20Deciamls()

Function-by-function walkthrough

  • strictPrice() {UoA/tok}
  • price(bool) {UoA/tok}
    if revert depends on the bool value true or false
  • refPerTok() {ref/tok}
  • targetPerRef() {target/ref}
  • pricePerTarget(){UoA/tartget}