如何為4萬名訂閱者編寫自動空投指令碼

買賣虛擬貨幣

在本文/教程中,我將介紹編寫node.js指令碼的過程,該指令碼執行自動代幣分發/空投到以太坊地址列表。我將使用Polymath代幣分發過程編寫的程式碼(這是一個非常標準的ERC20令牌),並檢查我處理代幣的自動分發而構建的指令碼。

最初我打算透過Infura執行此指令碼,因此不必在本地執行全節點。這就要求離線簽署交易記錄,這是我使用最新版本的web3中的幾個便捷函式完成的。不幸的是,即使這在testrpc和Ropsten上像魔咒一樣工作,在Mainnet上還是一場災難。交易沒有得到處理,還極其緩慢,昂貴且不可靠。

代幣和代幣分發的合約

我在Polymath的首要任務之一是幫助團隊制定代幣和代幣分發智慧合約,我們將在未來幾天使用這些合約來推出POLY代幣,並向訂閱該平臺的4萬人執行空投活動。

以下是有關polytoken.sol和polydribution.sol智慧合約的一些值得一提的內容,這將有助於理解本教程的其餘部分:

  • PolyToken.sol是POLY代幣的合約,這是一個相當固定的標準ERC20代幣合約。

  • PolyDistribution.sol是將處理代幣初始分配的合約。我們將預售投資者,顧問,創始人等的代幣分配從空投中分離出來,因為其過程是非常不同的。在我們的案例中,我們將使用1000萬個代幣(已發行的10億個代幣)進行空投,向40,000人分發250個代幣。 對於本教程而言,最重要的功能是airdropTokens(),讓我們對其進行回顧:

functionairdropTokens(address[] _recipient) public onlyOwnerOrAdmin {
require(now >= startTime);
    uint airdropped;
for(uint i = 0; i< _recipient.length; i++)
    {
if (!airdrops[_recipient[i]]) {
          airdrops[_recipient[i]] = true;
require(POLY.transfer(_recipient[i], 250 * decimalFactor));
          airdropped = airdropped.add(250 * decimalFactor);
        }
    }
    AVAILABLE_AIRDROP_SUPPLY = AVAILABLE_AIRDROP_SUPPLY.sub(airdropped);
    AVAILABLE_TOTAL_SUPPLY = AVAILABLE_TOTAL_SUPPLY.sub(airdropped);
    grandTotalClaimed = grandTotalClaimed.add(airdropped);
  }

airdropTokens()的基本作用是將250個POLY代幣(通常是ERC20代幣)分發(呼叫ERC20的transfer()函式)到一個地址陣列中。 對於我們收到的每個地址,只要他們尚未收到分配,我們就會向他們轉移250 POLY。 流程完成後,我們將更新可用的供應並跟蹤已經分配了多少代幣。

在本教程中,我們將僅關注分發給空投接收者的代幣。從上面可以看出,這些代幣的分配和轉讓沒有行權期或懸崖期對於其他型別的分配。對於其他型別的分配,情況則不同,那些分配具有一些特殊條件,必須先滿足一些特殊條件,才能轉讓/出售它們。

如果您有興趣瞭解其餘分配的完成方式,可以檢視PolyDistribution.sol中的setAllocation()和transferTokens()函式。

代幣分配事件


當代幣分配日期到來時,我們的團隊需要做的就是將代幣分配給每個註冊空投的帳戶。這些資料是過去幾個月從公司網站上收集的,其中包含註冊空投並在KYC驗證過程中成功驗證的每個帳戶的地址。空投的過程所需收集的資料儲存在CSV檔案中,該檔案只有1列:每個訂閱的以太坊地址。

請注意,可以很容易地修改指令碼,使其不僅包含訂閱使用者的地址,還包含應傳輸的代幣數量。 在這種情況下,由於我們決定將250 POLY分配給每個人,因此這不是必需的,我們選擇在分發智慧合約中對該數字進行硬編碼。

從理論上講,進行空投非常簡單。 我們需要做的就是為我們收集的每個地址呼叫ERC20令牌的transfer()函式。

如果我們只有很少的訂閱者,則可以透過手動執行transfer()函式來完成上述操作,但是潛在的成千上萬的人希望在啟動時立即擁有其代幣,逐個執行上述操作將非常耗時。

透過Node.js指令碼自動執行代幣分發過程。

在解釋了代幣和分發合約的工作原理之後,讓我們深入研究JS程式碼。為了使代幣分配過程自動化,我們需要做一些事情:

  • 我們必須讀取CSV檔案並對其進行處理,以刪除空白或無效的條目。我們假設某些資料會丟失或某些地址可能會錯誤,因此我們確保在將它們傳送到區塊鏈之前將其刪除。

  • 我們會將地址打包成多個陣列,每個陣列包含80個地址。為什麼是80?經過多次測試,考慮到轉讓代幣的氣體成本,這是理想的數字。根據您要對每個條目進行的操作,每次交易可能會花費更多或更少的氣體,因此您應該相應地打包條目,以使交易不會耗盡氣體並回滾。

  • 有了陣列集後,我們將每個陣列傳遞給智慧合約上的airdropTokens()函式,該函式將遍歷陣列併為每個訂閱者呼叫transfer()方法向其傳送代幣。

  • 之後,我們將執行另一個過程來獲取分發合約生成的所有“轉移”事件,以便我們可以檢查分發情況是否良好。(我們將對分發的代幣進行彙總,該代幣應與我們存檔的資料相匹配)。

讓我們從設定專案開始:

設定

執行以下命令以設定全新專案並安裝所需的依賴項:

$ mkdir distributionTutorial
$ npm init
$ truffle init
$ npm install web3 fast-csv truffle-contract ethereumjs-testrpc  --save


對於這個專案,我們將使用一些庫和框架:

  • truffle:它允許我們從javascript輕鬆編譯、遷移和與我們的合約互動。

  • Fast-csv:從CSV檔案讀取和處理資料。

您還應該安裝Parity並將其同步到Ropsten(或您喜歡的任何testnet / mainnet)上。 以下命令對我來說效果很好:

parity — chain ropsten — rpcapi “eth,net,web3,personal,parity” — unlock <THE ACCOUNT YOU WANT TOUNLOCK> — password $HOME/password.file


接下來,將Polymath Distribution智慧合約複製到專案的合約資料夾中。 可以在這裡找到檔案:https://github.com/PolymathNetwork/polymath-token-distribution/tree/master/contracts

開啟truffle.js並將其內容替換為以下程式碼:

module.exports = {
  networks: {
   development: {
      host: 'localhost',
      port: 8545,
      network_id: '*'// Match any network id
      gas: 3500000,
    }, 
   ropsten: {
      host: 'localhost',
      port: 8545,
      network_id: '3'// Match any network id
      gas: 3500000,
      gasPrice: 50000000000
    },
  },
  solc: {
    optimizer: {
      enabled: true,
      runs: 200,
    },
  },
};


上面的程式碼將允許我們執行truffle migrate——network-ropsten來將合同部署到ropsten testnet。 在能夠將合約部署到Ropsten之前,我們需要建立用於truffle的部署指令碼。 使用以下程式碼在migrations資料夾中建立一個名為2_deploy_contracts.js的新檔案:

var PolyToken = artifacts.require('./PolyToken.sol');
var PolyDistribution = artifacts.require('./PolyDistribution.sol');module.exports = async (deployer, network) => {
let _now = Date.now();
let _fromNow = 60 * 5 * 1000// Start distribution in 1 hour
let _startTime = (_now + _fromNow) / 1000;
await deployer.deploy(PolyDistribution, _startTime);
console.log(`
    ---------------------------------------------------------------
    --------- POLYMATH (POLY) TOKEN SUCCESSFULLY DEPLOYED ---------
    ---------------------------------------------------------------
    - Contract address: ${PolyDistribution.address}
    - Distribution starts in: ${_fromNow/1000/60} minutes
    - Local Time: ${newDate(_now + _fromNow)}
    ---------------------------------------------------------------
  `
);
};

上面的程式碼將在執行truffle migrate--network ropsten時執行它將把PolyDistribution合約部署到Ropsten(它也處理POLY Token合約的部署),將startTime設定為5分鐘後確保已正確設定了“starttime”變數,並且在到達“starttime”後嘗試空投,否則執行將失敗。我們正在使用starttime防止人們在代幣分發事件開始之前撤回代幣。

繼續執行truffle migrate--network ropsten如果一切順利,您應該會在控制檯上看到類似的輸出:

TX雜湊值和合約地址對您來說會有所不同。

如果看不到此輸出或出現錯誤,請確保您正在執行Parity並且已完全同步。 另外,請確保帳戶中有足夠的以太幣,用於在Ropsten測試網上部署合約。

記下我們剛剛部署的Poly Distribution合約的地址,稍後我們將使用它。

讀取CSV檔案


讓我們開始編寫指令碼,該指令碼將自動將poly代幣分配到註冊空投的地址。

首先,建立一個名為scripts的新資料夾,並在該資料夾中建立一個名為csv_allocation.js的新檔案。該檔案將包含用於執行分配過程的所有程式碼。

在繼續讀取和處理CSV檔案的程式碼之前,讓我們將檔案新增到專案中。 我們需要一個名為airdrop.csv的1列CSV檔案,該檔案的每個地址都有一個接收代幣的地址。 建立此檔案並將其新增到scripts / data資料夾。

如果要輕鬆測試空投,可以使用您控制的“隨機”地址自己生成此檔案。 一種簡單的方法是執行testrpc並指定要建立的帳戶數,如下所示:

testrpc -m "word1 word2 word3..." -a 300


上面的命令將從您提供的助記符中生成300個帳戶。 將地址複製到airdrop.csv。

回到我們的csv_allocation.js指令碼中,讓我們新增必要的程式碼以能夠讀取airdrop.csv。 將以下程式碼新增到csv_allocation.js中:

var fs = require('fs');
var csv = require('fast-csv');
var BigNumber = require('bignumber.js');let polyDistributionAddress = process.argv.slice(2)[0];
let BATCH_SIZE = process.argv.slice(2)[1];
if(!BATCH_SIZE) BATCH_SIZE = 80;
let distribData = newArray();
let allocData = newArray();functionreadFile({
var stream = fs.createReadStream("scripts/data/airdrop.csv");let index = 0;
let batch = 0;console.log(`
    --------------------------------------------
    --------- Parsing distrib.csv file ---------
    --------------------------------------------******** Removing beneficiaries without address data
  `
);var csvStream = csv()
      .on("data"function(data){
let isAddress = web3.utils.isAddress(data[0]);
if(isAddress && data[0]!=null && data[0]!='' ){
            allocData.push(data[0]);index++;
if(index >= BATCH_SIZE)
            {
              distribData.push(allocData);
              allocData = [];
              index = 0;
            }}
      })
      .on("end"function(){
//Add last remainder batch
           distribData.push(allocData);
           allocData = [];
           setAllocation();
      });  stream.pipe(csvStream);
}if(polyDistributionAddress){
console.log("Processing airdrop. Batch size is",BATCH_SIZE, "accounts per transaction");
  readFile();
}else{
console.log("Please run the script by providing the address of the PolyDistribution contract");
}


您現在可以執行以下操作來執行指令碼:

$ node scripts/csv_allocation.js 0x0... 80
// Where 0x0... is the address of the PolyDistribution contract we previously deployed to Ropsten.
// 80 is the batch size we want to process. (How many accounts per array we want to process and send to the airdropTokens function) Can be omitted, defaults to 80.

讓我們回顧一下程式碼:

首先,我們匯入允許我們讀取檔案和處理csv檔案的庫。

然後,如果您檢視程式碼的最後幾行,將會看到我們正在訪問執行指令碼時傳遞的引數,並且如果有PolyDistribution合約的地址,我們將呼叫readFile()函式。

readFile()函式的作用是訪問airdrop.csv檔案,並逐行讀取它。 在每一行中,我們確保該值不為null或為空,並且還使用web3的isAddress()函式來驗證傳遞的地址是否有效。 如果地址正確,我們會將其新增到一個陣列中,該陣列包含用於構建每個以太坊交易的已處理資料。

資料全部處理完畢併到達檔案末尾後,我們將呼叫該函式,我們呼叫函式來獲取80個地址的每個陣列並對它們進行處理。

請注意,此函式非常簡單,可以進一步改進,可以檢測超過poly供應量的代幣數量、重複地址等。所有這些情況仍在合約中處理,但如果我們可以節省一些對ethereum的事務呼叫,那就太好了。

處理代幣分配


現在我們已經將資料處理到一個陣列中了-我們應該將名為distribData的陣列包含幾個陣列,每個陣列最多具有80個地址addresses-我們將從智慧合約中為每個陣列呼叫airdropTokens()函式 。

const delay = ms =>newPromise(resolve => setTimeout(resolve, ms));asyncfunctionsetAllocation({console.log(`
    --------------------------------------------
    ---------Performing allocations ------------
    --------------------------------------------
  `
);let accounts = await web3.eth.getAccounts();let polyDistribution = await PolyDistribution.at(polyDistributionAddress);  for(var i = 0;i< distribData.length;i++){try{
let gPrice = 50000000000;
console.log("Attempting to allocate 250 POLYs to accounts:",distribData[i],"\n\n");
let r = await polyDistribution.airdropTokens(distribData[i],{from:accounts[0], gas:4500000gasPrice:gPrice});
console.log("---------- ---------- ---------- ----------");
console.log("Allocation + transfer was successful.", r.receipt.gasUsed, "gas used. Spent:",r.receipt.gasUsed * gPrice,"wei");
console.log("---------- ---------- ---------- ----------\n\n")
    } catch (err){
console.log("ERROR:",err);
    } }
}


讓我們仔細看看這個函式。 JS指令碼中的setAllocation()所做的只是遍歷用CSV檔案中處理後的資料填充的distribData陣列,然後對於每個條目陣列,我們繼續在智慧合約上執行airdropTokens(),並傳遞該陣列。

對於我們處理的每一批地址,我們都檢索事件日誌並列印花費了多少氣體,以確保過程成功。

每批氣體消耗量應大致相同。 如果有一批天然氣的成本更低,則意味著該批中的某些地址未轉移代幣,或者可能是因為它們之前已經轉移了代幣。

從ERC20令牌讀取轉移事件以驗證交易

在每天呼叫它之前,我們可以做的最後一件事是訪問erc20 poly token transfer()函式的事件日誌,以便我們可以快速檢查有多少帳戶獲得了代幣。

在setAllocation()函式的末尾新增以下行:

console.log("Distribution script finished successfully.")
console.log("Waiting 2 minutes for transactions to be mined...")
await delay(90000);
console.log("Retrieving logs to inform total amount of tokens distributed so far. This may take a while...")let polytokenAddress = await polyDistribution.POLY({from:accounts[0]});
let polyToken = await PolyToken.at(polytokenAddress);var sumAccounts = 0;
var sumTokens = 0;var events = await polyToken.Transfer({from: polyDistribution.address},{fromBlock0toBlock'latest'});
  events.get(function(error, log{
      event_data = log;
//console.log(log);
for (var i=0; i<event_data.length;i++){
//let tokens = event_data[i].args.value.times(10 ** -18).toString(10);
//let addressB = event_data[i].args.to;
          sumTokens += event_data[i].args.value.times(10 ** -18).toNumber();
          sumAccounts +=1;
//console.log(`Distributed ${tokens} POLY to address ${addressB}`);}
console.log(`A total of ${sumTokens} POLY tokens have been distributed to ${sumAccounts} accounts so far.`);
  });

上面的程式碼新增了一個超時函式,因此我們給事務留出一些時間來完成對事務的確認,然後我們獲得POLY代幣的Transfer()事件,並透過作為PolyDistribution合約的from欄位過濾事件。

然後我們計算事件以及分配了多少大筆。我們可以使用該資料將其與原始檔案進行比較。如果我們想花哨的話,我們也可以列出每個獲得代幣的地址,或者新增一個將CSV檔案與事件日誌資料進行比較的函式。

指令碼執行

就這樣! 讓我們嘗試一下指令碼。 執行以下命令:

$ node scripts/csv_allocation.js 0x0...
// Replace 0x0... with the address of the PolyDistribution contract you deployed to Ropsten


如果一切順利,您應該在控制檯上看到以下內容:

而且,如果您轉到Etherscan並輸入已部署的PolyDistribution合同的地址,則應該看到類似以下內容:

如果您可以看到csv檔案中每個帳戶的transfer()事件,那麼恭喜!

你的空投成功了!

到此就結束了,感謝你的耐心閱讀!

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;