百亿项目Alchemy Road to Web3 第九周NFT获取教程

Alchemy是什么项目?

2019年12月,Alchemy完成1500万美元A轮融资,资方为Pantera Capital,斯坦福大学,Coinbase,三星等。

2021年4月,Alchemy以5.05亿美元估值完成8000万美元B轮融资,Coatue和Addition领投,DFJ Growth、K5 Global、Chainsmokers(烟鬼组合)、演员Jared Leto和Glazer家族参投。

2021年10月,Alchemy以35亿美元估值完成2.5亿美元C轮融资,由a16z领投的。

2022年2月,Alchemy以102亿美元估值完成2亿美元融资,Lightspeed与Silver Lake领投。

Alchemy是一个背景强大、经费充足、踏实做事、没有发币的团队,这样的项目不刷,难道去刷土狗吗?

并且,Alchemy计划将新资金用于推广Web3采用,这方面的一些举措包括推出Web3 University,就是现在的 Road to Web3 活动,活动为期10周,每周一个NFT。看了下nft数量极少,估计由于任务难度大,很多小伙伴直接放弃,这样的项目若是空投,绝对是大毛。

手把手第九周教程开始:如何使用 0x API 构建代币交换 Dapp

step1 拷贝官方代码

1.在控制台输入如下代码

git clone https://github.com/0xProject/swap-demo-tutorial.git

2.用vscode打开clone的文件夹。

step2 安装live server

1.在vscode中进入extensions,在搜索框输入live server ,出来的第一个直接点安装就可以了。

step3 修改代码

1.将以下代码复制粘贴进swap-demo-tutorial-part-9的index.js替换掉原来的代码。

const qs = require('qs');
const Web3 = require('web3');
const { default: BigNumber } = require('bignumber.js');

let currentTrade = {};
let currentSelectSide;
let tokens;

async function init() {
    await listAvailableTokens();
}

async function listAvailableTokens() {
    console.log("initializing");
    // let response = await fetch('https://tokens.coingecko.com/uniswap/all.json');
    // let tokenListJSON = await response.json();
    let response='{"name":"CoinGecko","logoURI":"https://www.coingecko.com/assets/thumbnail-007177f3eca19695592f0b8b0eabbdae282b54154e1be912285c9034ea6cbaf2.png","keywords":["defi"],"timestamp":"2022-08-17T04:08:12.925+00:00","tokens":[{"chainId":56,"address":"0x55d398326f99059fF775485246999027B3197955","name":"busd","symbol":"busd","decimals":18,"logoURI":"https://assets.coingecko.com/coins/images/9956/thumb/4943.png?1636636734"},{"chainId":56,"address":"0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c","name":"bnb","symbol":"bnb","decimals":18,"logoURI":"https://assets.coingecko.com/coins/images/9956/thumb/4943.png?1636636734"}],"version":{"major":975,"minor":1,"patch":0}}';
    let tokenListJSON = JSON.parse(response);
    console.log("Listing available tokens: ", tokenListJSON);
    tokens = tokenListJSON.tokens;
    console.log("tokens: ", tokens);

    let parent = document.getElementById("token_list");
    for(const i in tokens) {
        let div = document.createElement("div");
        div.className = "token_row";

        let html = 
            `<img class="token_list_img" src="${tokens[i].logoURI}">
                <span class="token_list_text">${tokens[i].symbol}</span>`;
        div.innerHTML = html;
        div.onclick = () => {
            selectToken(tokens[i]);
        }
        parent.appendChild(div);       
    }
}

function selectToken(token) {
    closeModal();
    currentTrade[currentSelectSide] = token;
    console.log("currentTrade: ", currentTrade);
    renderInterface();
}

function renderInterface() {
    if(currentTrade.from) {
        document.getElementById("from_token_img").src = currentTrade.from.logoURI;
        document.getElementById("from_token_text").innerHTML = currentTrade.from.symbol;
    }
    if(currentTrade.to) {
        document.getElementById("to_token_img").src = currentTrade.to.logoURI;
        document.getElementById("to_token_text").innerHTML = currentTrade.to.symbol;
    }
}

async function connect() {
    if (typeof window.ethereum !== "undefined") {
        try {
            console.log("Connecting");
            await ethereum.request({ method: "eth_requestAccounts" });
        } catch (error) {
            console.log(error);
        }
        document.getElementById("login_button").innerHTML = "Connected";
        document.getElementById("swap_button").disabled = false;
    } else {
        document.getElementById("login_button").innerHTML = 
            "Please install Metamask";
    }
}

async function getPrice() {
    console.log("Getting Price");

    if(!currentTrade.from || !currentTrade.to || !document.getElementById("from_amount").value) return;
    let amount = Number(document.getElementById("from_amount").value * 10 ** currentTrade.from.decimals);

    const params = {
        sellToken: currentTrade.from.address,
        buyToken: currentTrade.to.address,
        sellAmount: amount,
    }

    // Fetch the swap price
    const response = await fetch(`https://bsc.api.0x.org/swap/v1/price?${qs.stringify(params)}`);

    swapPriceJSON = await response.json();
    console.log("Price: ", swapPriceJSON);

    document.getElementById("to_amount").value = swapPriceJSON.buyAmount / (10 ** currentTrade.to.decimals);
    document.getElementById("gas_estimate").innerHTML = swapPriceJSON.estimatedGas;
}

async function getQuote(account) {
    console.log("Getting Quote");

    if(!currentTrade.from || !currentTrade.to || !document.getElementById("from_amount").value) return;
    let amount = Number(document.getElementById("from_amount").value * 10 ** currentTrade.from.decimals);

    const params = {
        sellToken: currentTrade.from.symbol,
        buyToken: currentTrade.to.symbol,
        sellAmount: amount,
        takerAddress: account,
        slippagePercentage: 0.05
    }; 

    // Fetch the swap price
    const response = await fetch(`https://bsc.api.0x.org/swap/v1/quote?${qs.stringify(params)}`);

    swapQuoteJSON = await response.json();
    console.log("Quote: ", swapQuoteJSON);

    // document.getElementById("to_amount").value = swapQuoteJSON.price;
    document.getElementById("gas_estimate").innerHTML = swapQuoteJSON.estimatedGas;

    return swapQuoteJSON;
}

async function trySwap() {

    let accounts = await ethereum.request({ method: "eth_accounts" });
    let takerAddress = accounts[0];

    console.log("takerAddress:", takerAddress);

    const swapQuoteJSON = await getQuote(takerAddress);

    // Set Token Allowance
    // Interact with ERC20TokenContract
    const web3 = new Web3(Web3.givenProvider);
    const fromTokenAddress = currentTrade.from.address;
    const erc20abi = [{ "inputs": [ { "internalType": "string", "name": "name", "type": "string" }, { "internalType": "string", "name": "symbol", "type": "string" }, { "internalType": "uint256", "name": "max_supply", "type": "uint256" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "spender", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Approval", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "Transfer", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" }, { "internalType": "address", "name": "spender", "type": "address" } ], "name": "allowance", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "approve", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burn", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "burnFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "decimals", "outputs": [ { "internalType": "uint8", "name": "", "type": "uint8" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "subtractedValue", "type": "uint256" } ], "name": "decreaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "spender", "type": "address" }, { "internalType": "uint256", "name": "addedValue", "type": "uint256" } ], "name": "increaseAllowance", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [], "name": "name", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "symbol", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "address", "name": "recipient", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferFrom", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" }]
    console.log("trying swap"); 

    const ERC20TokenContract = new web3.eth.Contract(erc20abi, fromTokenAddress);
    console.log("setup ERC20TokenContract: ", ERC20TokenContract);

    const maxApproval = new BigNumber(2).pow(256).minus(1);
    console.log("approval amount: ", maxApproval);

    const tx = await ERC20TokenContract.methods
        .approve(swapQuoteJSON.allowanceTarget, maxApproval)
        .send({ from: takerAddress })
        .then((tx) => {
            console.log("tx: ", tx)
        });

    const receipt = await web3.eth.sendTransaction(swapQuoteJSON);
    console.log("receipt: ", receipt);
}

init();

function openModal(side) {
    currentSelectSide = side;
    document.getElementById("token_modal").style.display = "block";
}

function closeModal() {
    document.getElementById("token_modal").style.display = "none";
}

document.getElementById("login_button").onclick = connect;
document.getElementById("from_token_select").onclick = () => {
     openModal("from");
};
document.getElementById("to_token_select").onclick = () => {
    openModal("to");
};
document.getElementById("modal_close").onclick = closeModal;
document.getElementById("from_amount").onblur = getPrice;
document.getElementById("swap_button").onclick = trySwap;

step4 安装modules

1.在控制台输入以下代码,安装相关modules。

npm i qs
npm i bignumber
npm i web3
npm install -g browserify
browserify index.js --standalone bundle -o bundle.js

step5 测试交互功能

1.回到vscode,选中index.html,右键点击open with live server。

2.会出现这样的界面

当然,也可以在index.html的第31行和40行加入“选择币种”字样,保存后在运行就会变成这样,不过这个无所谓,根本不影响。

3.点击右上角链接小狐狸钱包。

4.点击选择币种那里,官方原版代码会出现好多币,也不知道哪个币是哪个链上的,直接ctrl+f找找你有的币就行。然后我这里用jay改过的的index.js的代码,就会只有两个币选择。

5.输入一定数额完成兑换即可,然后将交易的hash复制下来,留着等会提交。

step6 上传代码至github

1.登录github,点击New。

2.这三个地方填一下,然后直接拉到最下面,点击Create repository。

3.点击code,复制仓库地址备用。

4..接下来就到本地操作了,首先确保你已经成功安装Git这个软件,在电脑上找到你要上传到Github上面的那个项目文件夹,进入项目文件夹,单击鼠标右键,选择Git Bash Here,如下图所示。

5.接下来输入如下代码(关键步骤),把github上面的仓库克隆到本地

git clone https://github.com/qpc666/road-to-web3-09.git(https://github.com/qpc666/road-to-web3-09.git替换成你之前复制的地址),如图即可。

6.这个步骤以后你的本地项目文件夹下面就会多出个文件夹,该文件夹名即为你github上面的项目名,如图我多出了个road-to-web3-09文件夹,我们把本地项目文件夹下的所有文件(除了新多出的那个文件夹不用),其余都复制到那个新多出的文件夹下。

7.接着继续输入命令 cd road-to-web3-09,进入road-to-web3-09文件夹(road-to-web3-09是我建的仓库,这里应该改成你自己的仓库名字)

8.接下来依次输入以下代码即可完成其他剩余操作:

git add .  (注:别忘记后面的 . ,此操作是把Test文件夹下面的文件都添加进来)

git commit  -m  "提交信息"  (注:“提交信息”里面换成你需要,也可以不管,这里可能会出现如下第一张图提示,按照提示输入git config --global user.email "you@example.com"
git config --global user.name "Your Name" 就可以了 )

git push -u origin main   (注:此操作目的是把本地仓库push到github上面,此步骤需要你输入帐号和密码)

9.第一次使用Git,会弹框要求登录,把这个码复制下来。

10.点第九步码下面那个链接,进去登录自己的git账号,然后把把复制粘贴在这里,授权就可以了。

11.复制这个链接即可。

step7 提交项目

注意,提交github代码地址和交易的合约地址。

Subscribe to Greta
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.