//tips
//smart contract
App.jsにて受け取ったcoingeckoの値をページに反映させる。
選んだトークンに応じて換金額を表示させたい。
現在は$(this).text()の中に選んだトークン情報が格納されるようになっているので、そこと連携させる必要がある。
一旦下記のようにapp.jsを編集。
$(document).on('click', ".dropdown-menu li a", function () {
let element = $(this);
let img = element[0].firstElementChild.outerHTML;
let text = $(this).text();
グローバル変数にtokenを設定し、
token=text.replace(/\s/g,"");
で不必要なスペースを除去した文字情報を格納している。
//input時点で換金を実行させる
//inputfield内部の入力が変換するたびに呼ばれる
$("#input").on("input",function(){
if(token===undefined){
return;
}
//inputの中身の値を取得
//stringから数に直している
const input=parseFloat($(this).val());
updateOutput(input);
})
//coingecko情報読み取り
async function getPrice(){
const daiData = await (await fetch("https://api.coingecko.com/api/v3/simple/price?ids=dai&vs_currencies=eth")).json();
const compData = await (
await fetch(
"https://api.coingecko.com/api/v3/simple/price?ids=compound-governance-token&vs_currencies=eth"
)
).json();
const linkData = await (
//fetchによりapiの為替情報を取得
await fetch(
"https://api.coingecko.com/api/v3/simple/price?ids=chainlink&vs_currencies=eth"
)
).json();//json形式で帰ってくるので.jsonによりオブジェクト化
//オブジェクトの中の必要な価格部分を抜き出し
//jsonオブジェクトの構造に基づいている
return {
daiEth: daiData.dai.eth,
linkEth: linkData.chainlink.eth,
compEth: compData["compound-governance-token"].eth
}
}
//inputをもとにoutputされる数値
function updateOutput(input){
let output;
switch(token){
//inputにはethの値を入れているので
case "COMP":
output=buymode ? input /priceData.compEth : input *priceData.compEth;
break;
case "LINK":
output=buymode ? input /priceData.linkEth : input *priceData.linkEth;
break;
case "DAI":
output=buymode ? input /priceData.daiEth : input *priceData.daiEth;
break;
}
//入力時の出力制限
const exchangeRate=output/input;
if(output===0||isNaN(output)){
//output表示はしない
$("#output").val("");
$(".rate.value").css("display","none");
//swapもできないようにしておく
$(".btn.swap").html("Enter an amount");
$(".btn.swap").addClass("disabled");
}else{
//少数の制限
$("#output").val(output.toFixed(7));
$(".rate.value").css("display","block");
//exchangerateの計算表示
if(buyMode){
$("#top-text").html("ETH");
$("#bottom-text").html(""+token);
$("#rate-value").html(exchangeRate.toFixed(5));
}else{
$("#top-text").html(token);
$("#bottom-text").html( ETH);
$("#rate-value").html(exchangeRate.toFixed(5));
}
}
}
なぜかoutputが表示されない。
コンソールは確認し、apiはきちんと確認できているよう。
Uncaught ReferenceError: buymode is not definedとなっており、buyModeの大文字のMに編集。
これにより無事にinputに対してoutputを出せるようになった。
売買反転した時のexchangerateの表示がおかしかったので
//exchangerateの計算表示
if(buyMode){
$("#top-text").html("ETH");
$("#bottom-text").html(""+token);
$("#rate-value").html(exchangeRate.toFixed(5));
}else{
$("#top-text").html(token);
$("#bottom-text").html("ETH");
$("#rate-value").html(exchangeRate.toFixed(5));
}
に変更。
/コントラクトのインスタンスを設定し、swap機能を作成
//インスタンスにはコントラクトのアドレスとabiが必要
//アドレスがdeployしたganacheに記載されている
//実際のtoken売買の実行段階
const linkAddr="0xDa4A07281aCFc7D8C83E9B1062d0F5389a3C2009";
const daiAddr="0xD2e3658987db3Dd37E667fB00706aFae05eaB627";
const compAddr="0xA51ceEBf5E8a865dD5e6bc88840b71Ed09ae85e0";
const dexAddr="0x22d586899e3d082fCEe040Ac924E6eA8272D98Be";
//接続された時点でdexコントラクトのインスタンス生成
dexInst=new web3.eth.Contract(abi.dex,dexAddr,{from:user});
この際にはabiが必要。インスタンス生成にはabiが必要のはkickstartなども同じであった。
ここでは別途abi.jsをなぜ作成するのかの方に着目する。
これはdexとerc20のコンパイルした.jsonのabi部分を抽出したものになっている。
Htmlにも下記を挿入し、読み込ませる。
<script src="./assets/abi.js"></script>
まだ、dexだけでは関数を実行できないのでトークンの方もインスタンス化。
これはethから変換するトークンを決めた時に実行。
$(document).on('click', ".dropdown-menu li a", function () {
let element = $(this);
let img = element[0].firstElementChild.outerHTML;
let text = $(this).text();
token=text.replace(/\s/g,"");
//tokenのインスタンス化
//userはログインしている時でないと取得できないのでif
if(user){
switch(token){
case "DAI":
tokenInst=new web3.eth.Contract(abi.token,daiAddr,{from:user});
break;
case "LINK":
tokenInst=new web3.eth.Contract(abi.token,linkAddr,{from:user});
break;
case "COMP":
tokenInst=new web3.eth.Contract(abi.token,compAddr,{from:user});
break;
}
}
$(".input-group .btn").html(img + text);
$(".input-group .btn").css("color", "#fff");
$(".input-group .btn").css("font-size", "large");
});
ここまででswap実行の下準備ができたので、実際に機能を実装。
/enter amount ボタンをクリックするとswapを実行
$("#swap-box").submit(async(e)=>{
e.preventDefault();
//ガスなどの問題で失敗する可能性もあるので
try{
//コントラクトからのメソッド実行なので時間がかかるawait
buyMode ? await buyToken(): await sellToken()
}catch(err){
alert(err.message);
}
})
async function checkBalance(input){
//buyとsellでは確認するbalanceが異なる
//userの残高はbuyの場合は接続walletのeth,sellの場合はtokenアカウント内のuserのwalletを参照する
const balanceRaw=buyMode?await web3.eth.getBalance(user)
:await tokenInst.methods.balanceOf(user).call();
//weiからethへ変換
const balance =parseFloat(web3.utils.fromWei(balanceRaw,"ether"));
if(balance>=input){
$(".btn.swap").removeClass("disabled");
$(".btn.swap").html("Swap");//swap可能な場合表記をswapにかえる
}else{
$(".btn.swap").addClass("disabled");
$(".btn.swap").html(`Insufficient ${buyMode?"Eth":token}balence`);
}
}
async function buyToken(){
//const tokenAddr=tokenInst._address;
try{
const tokenAddr=tokenInst._address;
const buyTx= await dexInst.methods
.buyToken(tokenAddr,finalInput,finalOutput)
.send();
}catch(err){
throw(err);
}
}
async function sellToken(){
//dexからuserにtokenを渡すのにallowanceという制約がかかっているので
//token側からdexに許可を与えるケースを想定する
const allowance=await tokenInst.methods.allowance(user,dexAddr).call();
if(parseInt(finalInput)>parseInt(allowance)){
try{
await tokenInst.methods.approve(dexAddr,finalInput).send();
}catch(err){
throw(err);
}
}
//swap実装
try{
const tokenAddr=tokenInst._address;
const sellTx= await dexInst.methods
.sellToken(tokenAddr,finalInput,finalOutput)
.send();
}catch(err){
throw(err);
}
}
きちんと表示できた。
先のなぜかrequireが入っていた現象のようにvscodeの上部に//import { enable } from "debug”;などのコードが挿入される事象が見受けられた。
どこかの更新のタイミングなどで勝手に組み込まれるよう。これには注意しておく。
Buytokenの方でエラーが出たので修正。
async function buyToken(){
const tokenAddr=tokenInst._address;
return new Promise((resolve,reject)=>{
dexInst.methods
.buyToken(tokenAddr,finalInput,finalOutput)
.send({value:finalInput})
.then((receipt)=>{
console.log(receipt);
resolve();
})
.catch((err)=>reject(err));
});
「ガス リミットは 21000 以上にする必要があります」とのエラーが発生。これはdeployできていないなどの問題か。
全てのコンパイルファイルを削除して再度コンパイル、それからデプロイをしなおすときちんとworkした。
おそらく古いコンパイルが残って悪さをしていたよう。これは要注意。