From 5f1fc664dd179d2cc1dafb51d24b258aec24d281 Mon Sep 17 00:00:00 2001 From: Cameron Yuan Date: Fri, 6 May 2022 23:35:18 -0500 Subject: [PATCH 1/5] Fix spelling. Change owner to Owner wallet for clarity --- prepareAirdrop.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/prepareAirdrop.ts b/prepareAirdrop.ts index f8f044c..ee591d6 100644 --- a/prepareAirdrop.ts +++ b/prepareAirdrop.ts @@ -4,11 +4,11 @@ import * as anchor from "@project-serum/anchor"; import { assert } from 'console'; import * as splToken from "@solana/spl-token"; import { token } from '@project-serum/anchor/dist/cjs/utils'; -const fs = require('fs'); +import * as fs from 'fs'; const VERIFIED_CREATOR = "AHx6cQKhJQ6vV9zhb37B7gKtRRGDuLtTfNWgvMiLDJp7"; const TOKEN_TO_SEND = "toKPe7ENJiRBANPLnnp4dHs7ccFyHRg2oSEPdDfumg8"; -const AMOUNT_TO_SEND = 42000000000; // including decimans +const AMOUNT_TO_SEND = 42000000000; // including decimals export const PROGRESS_FILE_PATH = "./progress.json"; @@ -16,7 +16,7 @@ export class TokenInfo { metadataAccount: string; nftTokenMint: string; nftName: string | undefined; - owner: string | undefined; + ownerWallet: string | undefined; sendableTokenMint: string | undefined; sendableAmount: number | undefined; txid: string | undefined; @@ -27,7 +27,7 @@ export class TokenInfo { } show(){ - console.log(this.metadataAccount + " -> " + this.nftTokenMint +' -> '+ this.owner); + console.log(this.metadataAccount + " -> " + this.nftTokenMint +' -> '+ this.ownerWallet); } } @@ -143,8 +143,8 @@ async function main(){ console.log("finding owners...") allInfo.forEach(async tokenInfo => { - if (!tokenInfo.owner) { - tokenInfo.owner = await (await getOwnerForNFT(c, tokenInfo.nftTokenMint)).toBase58(); + if (!tokenInfo.ownerWallet) { + tokenInfo.ownerWallet = await (await getOwnerForNFT(c, tokenInfo.nftTokenMint)).toBase58(); writeJson(allInfo); } }); From a874390cdd02967eccd7c20967fae397d3f94ee5 Mon Sep 17 00:00:00 2001 From: Cameron Yuan Date: Fri, 6 May 2022 23:46:31 -0500 Subject: [PATCH 2/5] Update to catch errors on the transactions Added Magic Eden escrow Added error file Updated to ownerWallet from the tokenInfo Update KEYPAIR to constant Added then/catch block to the send Token transactions. This allows the script to continue without restarting. Also lets the user review the wallets with errors in the case that a transaction "fails". Often they are just unconfirmed but successful --- executeAirdrop.ts | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/executeAirdrop.ts b/executeAirdrop.ts index 12d83ae..23bf2e8 100644 --- a/executeAirdrop.ts +++ b/executeAirdrop.ts @@ -3,18 +3,20 @@ import * as web3 from '@solana/web3.js'; import * as anchor from "@project-serum/anchor"; import * as splToken from "@solana/spl-token"; const fs = require('fs'); - import { TokenInfo, readJson, writeJson } from "./prepareAirdrop"; const USE_MAINNET = false; const MAGIC_EDEN_ADDRESS = "GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp"; +const MAGIC_EDEN_ESCROW = "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix"; +export const ERROR_FILE_PATH = "./error.json"; +export const KEYPAIR_FILE = "C:\\Users\\loopc\\wkdir\\DEVkasD4qwUJQ8LS7rcJHcGDQQzrEtWgk2jB6v5FHngo.json"; async function sendToken(connection: web3.Connection, dropInfo: TokenInfo, sender: web3.Keypair): Promise{ - if(!dropInfo.sendableAmount || !dropInfo.sendableTokenMint || !dropInfo.owner) return ""; + if(!dropInfo.sendableAmount || !dropInfo.sendableTokenMint || !dropInfo.ownerWallet) return ""; const mint = new web3.PublicKey(dropInfo.sendableTokenMint); - const owner = new web3.PublicKey(dropInfo.owner); + const owner = new web3.PublicKey(dropInfo.ownerWallet); const transaction = new web3.Transaction(); @@ -56,7 +58,7 @@ async function sendToken(connection: web3.Connection, dropInfo: TokenInfo, sende ) transaction.add(transferInstruction); - console.log("Sending form", sourceAccount.toBase58(),"to", destinationAccount.toBase58()); + console.log("Sending from", sourceAccount.toBase58(),"to", destinationAccount.toBase58()); const txid = await web3.sendAndConfirmTransaction( connection, transaction, [sender], { commitment: 'confirmed' }); @@ -73,7 +75,12 @@ export function loadWalletKey(keypairFile:string): web3.Keypair { ); console.log(`using wallet: ${loaded.publicKey}`); return loaded; - } +} + + export function writeErrors(data: TokenInfo[]){ + let json = JSON.stringify(data); + fs.writeFileSync(ERROR_FILE_PATH, json); +} async function main() { @@ -82,26 +89,37 @@ async function main() { const allInfo = readJson(); - const myKeypairFile = "C:\\Users\\loopc\\wkdir\\DEVkasD4qwUJQ8LS7rcJHcGDQQzrEtWgk2jB6v5FHngo.json"; - const sender = loadWalletKey(myKeypairFile); + const sender = loadWalletKey(KEYPAIR_FILE); //const txid = await sendToken(c, allInfo[0], sender); //console.log(txid); //return; + + let counter = 0; + let errorTransactions: TokenInfo[] = []; for (let i = 0; i { + return txn; + }).catch( err => { + console.log(err); + //unfortunately I didn't figure out how to get the txn id from the error, but the wallet is easy enough to look at + errorTransactions.push(allInfo[i]); + return "error or timeout"; + }); allInfo[i].txid = txid; writeJson(allInfo); - console.log(txid); + // console.log(txid); await new Promise(f => setTimeout(f, 500)); } } + writeErrors(errorTransactions); + console.log(counter); } From 6d13b7968081ef364db2466e227901ae39269082 Mon Sep 17 00:00:00 2001 From: Cameron Yuan Date: Fri, 6 May 2022 23:53:12 -0500 Subject: [PATCH 3/5] Seperate all these constants into one file for easy viewing and updating --- constants.ts | 14 ++++++++++++++ executeAirdrop.ts | 9 +++------ prepareAirdrop.ts | 24 ++---------------------- tokenInfo.ts | 19 +++++++++++++++++++ 4 files changed, 38 insertions(+), 28 deletions(-) create mode 100644 constants.ts create mode 100644 tokenInfo.ts diff --git a/constants.ts b/constants.ts new file mode 100644 index 0000000..a3b92ac --- /dev/null +++ b/constants.ts @@ -0,0 +1,14 @@ +//Solana and token variables +export const USE_MAINNET = false; +export const VERIFIED_CREATOR = "AHx6cQKhJQ6vV9zhb37B7gKtRRGDuLtTfNWgvMiLDJp7"; +export const TOKEN_TO_SEND = "toKPe7ENJiRBANPLnnp4dHs7ccFyHRg2oSEPdDfumg8"; +export const AMOUNT_TO_SEND = 42000000000; // including decimals + +//Filename inputs and outputs +export const KEYPAIR_FILE = "C:\\Users\\loopc\\wkdir\\DEVkasD4qwUJQ8LS7rcJHcGDQQzrEtWgk2jB6v5FHngo.json"; +export const PROGRESS_FILE_PATH = "./progress.json"; +export const ERROR_FILE_PATH = "./error.json"; + +//secondary Market wallets +export const MAGIC_EDEN_ADDRESS = "GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp"; +export const MAGIC_EDEN_ESCROW = "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix"; \ No newline at end of file diff --git a/executeAirdrop.ts b/executeAirdrop.ts index 23bf2e8..0c5f524 100644 --- a/executeAirdrop.ts +++ b/executeAirdrop.ts @@ -3,13 +3,10 @@ import * as web3 from '@solana/web3.js'; import * as anchor from "@project-serum/anchor"; import * as splToken from "@solana/spl-token"; const fs = require('fs'); -import { TokenInfo, readJson, writeJson } from "./prepareAirdrop"; +import { readJson, writeJson } from "./prepareAirdrop"; +import { ERROR_FILE_PATH, USE_MAINNET, KEYPAIR_FILE, MAGIC_EDEN_ADDRESS, MAGIC_EDEN_ESCROW } from './constants'; +import { TokenInfo } from './tokenInfo'; -const USE_MAINNET = false; -const MAGIC_EDEN_ADDRESS = "GUfCR9mK6azb9vcpsxgXyj7XRPAKJd4KMHTTVvtncGgp"; -const MAGIC_EDEN_ESCROW = "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix"; -export const ERROR_FILE_PATH = "./error.json"; -export const KEYPAIR_FILE = "C:\\Users\\loopc\\wkdir\\DEVkasD4qwUJQ8LS7rcJHcGDQQzrEtWgk2jB6v5FHngo.json"; async function sendToken(connection: web3.Connection, dropInfo: TokenInfo, sender: web3.Keypair): Promise{ diff --git a/prepareAirdrop.ts b/prepareAirdrop.ts index ee591d6..d4fe69f 100644 --- a/prepareAirdrop.ts +++ b/prepareAirdrop.ts @@ -5,31 +5,11 @@ import { assert } from 'console'; import * as splToken from "@solana/spl-token"; import { token } from '@project-serum/anchor/dist/cjs/utils'; import * as fs from 'fs'; +import { TokenInfo } from './tokenInfo'; +import { PROGRESS_FILE_PATH, AMOUNT_TO_SEND, TOKEN_TO_SEND, VERIFIED_CREATOR } from './constants'; -const VERIFIED_CREATOR = "AHx6cQKhJQ6vV9zhb37B7gKtRRGDuLtTfNWgvMiLDJp7"; -const TOKEN_TO_SEND = "toKPe7ENJiRBANPLnnp4dHs7ccFyHRg2oSEPdDfumg8"; -const AMOUNT_TO_SEND = 42000000000; // including decimals -export const PROGRESS_FILE_PATH = "./progress.json"; -export class TokenInfo { - metadataAccount: string; - nftTokenMint: string; - nftName: string | undefined; - ownerWallet: string | undefined; - sendableTokenMint: string | undefined; - sendableAmount: number | undefined; - txid: string | undefined; - - constructor(metadataAccount: string, tokenMint: string) { - this.metadataAccount = metadataAccount; - this.nftTokenMint = tokenMint; - } - - show(){ - console.log(this.metadataAccount + " -> " + this.nftTokenMint +' -> '+ this.ownerWallet); - } -} export function writeJson(data: TokenInfo[]){ let json = JSON.stringify(data); diff --git a/tokenInfo.ts b/tokenInfo.ts new file mode 100644 index 0000000..340418d --- /dev/null +++ b/tokenInfo.ts @@ -0,0 +1,19 @@ + +export class TokenInfo { + metadataAccount: string; + nftTokenMint: string; + nftName: string | undefined; + ownerWallet: string | undefined; + sendableTokenMint: string | undefined; + sendableAmount: number | undefined; + txid: string | undefined; + + constructor(metadataAccount: string, tokenMint: string) { + this.metadataAccount = metadataAccount; + this.nftTokenMint = tokenMint; + } + + show(){ + console.log(this.metadataAccount + " -> " + this.nftTokenMint +' -> '+ this.ownerWallet); + } +} From a792712ba46894054b5293bde27c9151d7a48ab0 Mon Sep 17 00:00:00 2001 From: Cameron Yuan Date: Fri, 6 May 2022 23:53:58 -0500 Subject: [PATCH 4/5] Moving this up. Could move all these json read/writes into a utils file or something, but I think this is still pretty straightforward --- executeAirdrop.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/executeAirdrop.ts b/executeAirdrop.ts index 0c5f524..cfb75f5 100644 --- a/executeAirdrop.ts +++ b/executeAirdrop.ts @@ -7,6 +7,10 @@ import { readJson, writeJson } from "./prepareAirdrop"; import { ERROR_FILE_PATH, USE_MAINNET, KEYPAIR_FILE, MAGIC_EDEN_ADDRESS, MAGIC_EDEN_ESCROW } from './constants'; import { TokenInfo } from './tokenInfo'; +export function writeErrors(data: TokenInfo[]){ + let json = JSON.stringify(data); + fs.writeFileSync(ERROR_FILE_PATH, json); +} async function sendToken(connection: web3.Connection, dropInfo: TokenInfo, sender: web3.Keypair): Promise{ @@ -74,10 +78,6 @@ export function loadWalletKey(keypairFile:string): web3.Keypair { return loaded; } - export function writeErrors(data: TokenInfo[]){ - let json = JSON.stringify(data); - fs.writeFileSync(ERROR_FILE_PATH, json); -} async function main() { From 802efa087b63a5f3f741cf692067b76164b9fd6a Mon Sep 17 00:00:00 2001 From: Cameron Yuan Date: Sat, 7 May 2022 00:03:53 -0500 Subject: [PATCH 5/5] Update the counters to print success/error at the end --- executeAirdrop.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/executeAirdrop.ts b/executeAirdrop.ts index cfb75f5..8ced934 100644 --- a/executeAirdrop.ts +++ b/executeAirdrop.ts @@ -93,7 +93,8 @@ async function main() { //return; - let counter = 0; + let success = 0; + let errors = 0; let errorTransactions: TokenInfo[] = []; for (let i = 0; i { + success++; return txn; }).catch( err => { + errors++; console.log(err); //unfortunately I didn't figure out how to get the txn id from the error, but the wallet is easy enough to look at errorTransactions.push(allInfo[i]); @@ -116,7 +119,7 @@ async function main() { } } writeErrors(errorTransactions); - console.log(counter); + console.log(`${success} successful transactions and ${errors} error/timeout transactions`); }