- hardhat + typescript で開発するため以下のテンプレートを利用した https://github.com/rhlsthrm/typescript-solidity-dev-starter-kit
- Stakingコントラクトのベース部分は以下を参考にした https://github.com/HQ20/StakingToken
- EternalStorageの実装は以下を参考にした https://github.com/PolymathNetwork/polymath-core/blob/master/contracts/storage/EternalStorage.sol
以下の3つのコントラクトを作成した
- Token.sol
- EternalStorage.sol
- StakingToken.sol
それぞれのコントラクトは以下の役割を持っている
- Token.solはOpenzeppelinのERC20.solを利用し、stake用トークンとreward用トークンを生成するためのコントラクト
- EternalStorage.solはstake量とreward量の書き込み、読み込みをするためのコントラクト
- StakingToken.solは上記2つのコントラクトを引数として持ち、stake, rewardの計算ロジックを記述するためのコントラクト
Rewardは(price - initialPrices[msg.sender]) * STAKED_AMOUNT
によって計算される。
このような問題設定から、price
はユーザーがstakeした時間に応じて単調増加する変数であることが想定される。
つまりprice
とは金利を反映したstakingの契約価格と解釈することができる。
金利が積み上がっていくという意味で、問題文ではcumulative unit priceという言葉が使用されていると考えられる。
もっとも単純な金利のモデルは固定金利で、単位時間あたりに一定の金額がstake量に比例して、積み上がっていくものが考えられる。
ブロックチェーン上の単位時間とは、ブロックであるため、price = 単位時間あたりの金利 * ブロック数
で計算できる。
今回の問題では、price
はstakeイベントごとにアップデートされるという設定があるため、
price
は経過時間によってだけではなく、ユーザーのstake量にも依存して動的に更新されるべきである。
このような設定を考えると、price
の積立金利はユーザーのstake総量の増加に伴い単調減少する関数であることが期待される。
つまりstake総量が小さいうちは金利は高く、ユーザーがstakeするインセンティブも高い。 stake総量が大きくなるに従い、金利は低くなり、もし100%トークンがロックされていれば、金利は0となるべきである。 (もし100%のトークンがロックされてしまえば、トークンの流動性は0となってしまうため)
このような金利の単調減少関数をどのようなものにするかは商品を設計する側に委ねられている。 今回の試験では既存プロダクトの金利設計をそのまま流用することにした。 Dev Protocolの金利はStake比率に応じて金利が指数関数的に減少するように設計してある。 https://github.com/dev-protocol/protocol/blob/main/docs/POLICY.md
上記リンクのrewars function を参考に、stakeごとに金利がアップデートされるようにコントラクトを作成した。
EternalStorage上で、price
, priceUpdatedAt(ブロックナンバー)
, mintPerBlockAndAsset(金利)
の3つの変数を管理し、
ユーザーがstakeするごとに、これら3つの変数がアップデートされるように設計した。
Infura APIを利用し、テストネットのRinkebyにToken.sol(TokenA, TokenB), EternalStorage.sol, Staking.solをデプロイした。
yarn deploy --network rinkeby
を実行し、コントラクトは以下のアドレスにデプロイされた。
- TokenA was deployed to: 0x970917f99732458c2E0cd725221d0711b65f4761
- TokenB was deployed to: 0xFAeDEA9A8CD08d0C162B090672f52Ce9B53e865d
- EternalStorage was deployed to: 0xa63118c8B7B770DAa45f2F9b923b44854906fc25
- StakingToken was deployed to: 0xE594e4F798a7aE94d626c42521C610bE03c73b25
StakingTokenのEtherscan.ioのURLは以下 https://rinkeby.etherscan.io/address/0xE594e4F798a7aE94d626c42521C610bE03c73b25
event-logs.tsというスクリプトを作り、RinkebyにデプロイしたStakingToken.solのStake, Unstake イベントのログを収集できるようにした。
以下のコマンドを実行すると、event-logs.csvが生成され、Etherscan.ioと同様のログが出力されることを確認した。
npx hardhat run --network rinkeby scripts/event-logs.ts
ERC20, EternalStorageを利用し、動的な金利によるStakingのコントラクトを作成することができた。