Revert "Cleaning up"
This reverts commit 0db69bf72b0b090edc22d0e682f8f3bb4356dc3e.
This commit is contained in:
		
							parent
							
								
									2b12c99813
								
							
						
					
					
						commit
						a578978c95
					
				
							
								
								
									
										179
									
								
								Airdrop.fsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								Airdrop.fsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,179 @@ | |||||||
|  | #load "/home/joe/Development/DegenzGame/.paket/load/net6.0/main.group.fsx";; | ||||||
|  | 
 | ||||||
|  | open System | ||||||
|  | open System.IO | ||||||
|  | open Npgsql.FSharp | ||||||
|  | open dotenv.net | ||||||
|  | open Solnet.Rpc | ||||||
|  | open Solnet.Rpc.Models | ||||||
|  | open Solnet.Rpc.Builders | ||||||
|  | open Solnet.Wallet | ||||||
|  | open Solnet.Programs | ||||||
|  | open Solnet.KeyStore | ||||||
|  | 
 | ||||||
|  | let devEnv = DotEnv.Read(DotEnvOptions(envFilePaths = [ "./.dev.env" ])) | ||||||
|  | 
 | ||||||
|  | let ( _ , devConnStr )= devEnv.TryGetValue("DATABASE_URL") | ||||||
|  | 
 | ||||||
|  | let keystore = SolanaKeyStoreService() | ||||||
|  | let file = File.ReadAllText("/home/joe/.config/solana/devnet.json") | ||||||
|  | let authority = keystore.RestoreKeystore(file) | ||||||
|  | 
 | ||||||
|  | //let rpcClient = ClientFactory.GetClient("https://still-empty-field.solana-mainnet.quiknode.pro/5b1b6b5c913ec79a20bef19d5ba5f63023e470d6/") | ||||||
|  | let rpcClient = ClientFactory.GetClient(Cluster.DevNet) | ||||||
|  | 
 | ||||||
|  | let mintAccount = PublicKey("2iS6gcoB5VhiLC4eNB7NdcaLgEHjLrXHYpz7T2JMGBDw") | ||||||
|  | //let associatedTokenAccountOwner = PublicKey("GutKESfJw8PDMbFVqByxTr4f5TUSHUVmkf5gtsWWWqrU") | ||||||
|  | 
 | ||||||
|  | type AirdropStatus = | ||||||
|  |     | Hold = 0 | ||||||
|  |     | Ready = 1 | ||||||
|  |     | Pending = 2 | ||||||
|  |     | Error = 3 | ||||||
|  |     | PendingError = 4 | ||||||
|  |     | Completed = 5 | ||||||
|  |     | Verified = 6 | ||||||
|  | 
 | ||||||
|  | let updateError wallet msg = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "msg" , Sql.string msg ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET error_msg = @msg, status = 'Error' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updatePendingError wallet msg txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "msg" , Sql.string msg ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET error_msg = @msg, pending_tx = @txId, status = 'PendingError' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updatePending wallet txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET pending_tx = @txId, status = 'Pending' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updateCompleted wallet txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET successful_tx = pending_tx, status = 'Completed' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updateVerified wallet txId amount = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ; "amount" , Sql.int amount ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET pending_tx = @txId, status = 'Verified', total_dropped = @amount WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let getTokenCountToDrop wallet = | ||||||
|  |     task { | ||||||
|  |         let! wl = | ||||||
|  |             devConnStr | ||||||
|  |             |> Sql.connect | ||||||
|  |             |> Sql.parameters [ "wallet" , Sql.string wallet ] | ||||||
|  |             |> Sql.query """ | ||||||
|  |                     SELECT has_wl, has_og FROM crypto WHERE wallet_address = @wallet; | ||||||
|  |                 """ | ||||||
|  |             |> Sql.executeRowAsync (fun reader -> {| HasWhitelist = reader.bool "has_wl" ; HasOg = reader.bool "has_og" |}) | ||||||
|  |         return (if wl.HasWhitelist then 1uL else 0uL) + (if wl.HasOg then 2uL else 0uL) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | // TODO: Change was_successful to status and check if attempted, pending, errored, or completed | ||||||
|  | let executeDrop (wallet : string) = | ||||||
|  |     let associatedTokenAccountOwner = PublicKey(wallet) | ||||||
|  |     let associatedTokenAccount = AssociatedTokenAccountProgram.DeriveAssociatedTokenAccount(associatedTokenAccountOwner, mintAccount) | ||||||
|  |     let log msg = printfn $"{wallet} || {msg}" | ||||||
|  | 
 | ||||||
|  |     log $"ATA: {associatedTokenAccount.Key}" | ||||||
|  |     let buildTransaction (block : LatestBlockHash) amount (targetWallet : string) = | ||||||
|  |         TransactionBuilder() | ||||||
|  |             .SetRecentBlockHash(block.Blockhash) | ||||||
|  |             .SetFeePayer(authority.Account) | ||||||
|  |             .AddInstruction(AssociatedTokenAccountProgram.CreateAssociatedTokenAccount( | ||||||
|  |                 authority.Account, | ||||||
|  |                 PublicKey(targetWallet), | ||||||
|  |                 mintAccount)) | ||||||
|  |             .AddInstruction(TokenProgram.Transfer( | ||||||
|  |                 PublicKey("CRa7GCMUaB4np32XoTD2sEyCXFVfYKKF4JRPkQTwV3EY"), | ||||||
|  |                 associatedTokenAccount, | ||||||
|  |                 amount, | ||||||
|  |                 authority.Account)) | ||||||
|  |             .Build(authority.Account); | ||||||
|  |     task { | ||||||
|  | //        let streamingClient = ClientFactory.GetStreamingClient("wss://still-empty-field.solana-mainnet.quiknode.pro/5b1b6b5c913ec79a20bef19d5ba5f63023e470d6/") | ||||||
|  |         let streamingClient = ClientFactory.GetStreamingClient(Cluster.DevNet) | ||||||
|  |         do! streamingClient.ConnectAsync() | ||||||
|  |         let blockHash = rpcClient.GetLatestBlockHash() | ||||||
|  |         let! amount = getTokenCountToDrop wallet | ||||||
|  |         log $"Dropping {amount} tokens" | ||||||
|  |         let tx = buildTransaction blockHash.Result.Value amount wallet | ||||||
|  |         let! tx = rpcClient.SendTransactionAsync(tx) | ||||||
|  |         if tx.ErrorData <> null then | ||||||
|  |             let! _ = updateError wallet (tx.ErrorData.Logs |> String.concat "\n") | ||||||
|  |             () | ||||||
|  |             log $"Transaction error: {wallet}" | ||||||
|  |             return () | ||||||
|  |         elif String.IsNullOrWhiteSpace(tx.Result) then | ||||||
|  |             let msg = $"Transaction did not have an ID but the ErrorData was null: {tx.Reason}" | ||||||
|  |             let! _ = updateError wallet msg | ||||||
|  |             log $"Odd Transaction Error" | ||||||
|  |             return () | ||||||
|  |         else | ||||||
|  |             log $"Successful, now waiting for RPC" | ||||||
|  |             let! _ = updatePending wallet tx.Result | ||||||
|  |             let! _ = streamingClient.SubscribeSignatureAsync(tx.Result, fun _ result -> | ||||||
|  |                 if result.Value.Error = null then | ||||||
|  |                     log "RPC Finished" | ||||||
|  |                     task { | ||||||
|  |                         let! _ = updateCompleted wallet tx.Result | ||||||
|  |                         log "Getting Transaction and Token Balance" | ||||||
|  |                         let! txInfo = rpcClient.GetTransactionAsync(tx.Result) | ||||||
|  |                         let! tokenBalance = rpcClient.GetTokenAccountBalanceAsync(associatedTokenAccount) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                         log $"Transaction Successful? {txInfo.WasSuccessful} - Token Balance {tokenBalance.Result.Value.AmountUlong}" | ||||||
|  |                         if txInfo.WasSuccessful = true && tokenBalance.Result.Value.AmountUlong = amount then | ||||||
|  |                             let! _ = updateVerified wallet tx.Result (int amount) | ||||||
|  |                             () | ||||||
|  |                         return () | ||||||
|  |                     } |> Async.AwaitTask |> Async.Start | ||||||
|  |                 else | ||||||
|  |                     let msg =  $"Got an error, let's check it out {result.Value.Error}" | ||||||
|  |                     updatePendingError wallet msg tx.Result |> Async.AwaitTask |> Async.Ignore |> Async.Start) | ||||||
|  |             return () | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | let targetWallets = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.query """ | ||||||
|  |             SELECT wallet_address FROM crypto WHERE status = 'Ready'; | ||||||
|  |         """ | ||||||
|  |     |> Sql.execute (fun reader -> reader.string "wallet_address") | ||||||
|  | 
 | ||||||
|  | printfn $"Got target wallets: {targetWallets.Length}" | ||||||
|  | 
 | ||||||
|  | // "GK7rkZYrdAEpTm9n9TkHWK1T5nDXeRfVUVfcHQwSDyuJ" | ||||||
|  | let asyncs = | ||||||
|  |     targetWallets | ||||||
|  |     |> List.map executeDrop | ||||||
|  |     |> List.map Async.AwaitTask | ||||||
|  | 
 | ||||||
|  | Async.Parallel ( asyncs , 16 ) |> Async.StartChild | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Console.ReadLine() |> ignore | ||||||
							
								
								
									
										188
									
								
								Bot/Scripts/Airdrop.fsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								Bot/Scripts/Airdrop.fsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,188 @@ | |||||||
|  | #load "/home/joe/Development/DegenzGame/.paket/load/net6.0/main.group.fsx";; | ||||||
|  | 
 | ||||||
|  | open System | ||||||
|  | open System.IO | ||||||
|  | open Npgsql.FSharp | ||||||
|  | open dotenv.net | ||||||
|  | open Solnet.Rpc | ||||||
|  | open Solnet.Rpc.Models | ||||||
|  | open Solnet.Rpc.Builders | ||||||
|  | open Solnet.Wallet | ||||||
|  | open Solnet.Programs | ||||||
|  | open Solnet.KeyStore | ||||||
|  | 
 | ||||||
|  | let devEnv = DotEnv.Read(DotEnvOptions(envFilePaths = [ "./.dev.env" ])) | ||||||
|  | 
 | ||||||
|  | let ( _ , devConnStr )= devEnv.TryGetValue("DATABASE_URL") | ||||||
|  | let ( _ , rpcClientUrl )= devEnv.TryGetValue("RPC_CLIENT") | ||||||
|  | let ( _ , wssClientUrl )= devEnv.TryGetValue("WSS_CLIENT") | ||||||
|  | 
 | ||||||
|  | let keystore = SolanaKeyStoreService() | ||||||
|  | //let file = File.ReadAllText("/home/joe/.config/solana/devnet.json") | ||||||
|  | let file = File.ReadAllText("/home/joe/.config/solana/DegenzW7kWzac5zEdTWEuqVasoVMPKd16T3za2j6S3qR.json") | ||||||
|  | let authority = keystore.RestoreKeystore(file) | ||||||
|  | 
 | ||||||
|  | //let rpcClient = ClientFactory.GetClient(Cluster.DevNet) | ||||||
|  | let rpcClient = ClientFactory.GetClient(rpcClientUrl) | ||||||
|  | 
 | ||||||
|  | //let mintAccount = PublicKey("2iS6gcoB5VhiLC4eNB7NdcaLgEHjLrXHYpz7T2JMGBDw") | ||||||
|  | let mintAccount = PublicKey("4gN1u9LNBnvFERpDU3SrMusMJ1gKLbE9XB6EYraQkWTf") | ||||||
|  | //let ataAccount = PublicKey("CRa7GCMUaB4np32XoTD2sEyCXFVfYKKF4JRPkQTwV3EY") | ||||||
|  | let sourceAtaAccount = PublicKey("7CB459UJC3qtTYJzfC8bFNvdycQGXTPzKoEHxys8Ytfs") | ||||||
|  | //let associatedTokenAccountOwner = PublicKey("GutKESfJw8PDMbFVqByxTr4f5TUSHUVmkf5gtsWWWqrU") | ||||||
|  | 
 | ||||||
|  | type AirdropStatus = | ||||||
|  |     | Hold = 0 | ||||||
|  |     | Ready = 1 | ||||||
|  |     | Pending = 2 | ||||||
|  |     | Error = 3 | ||||||
|  |     | PendingError = 4 | ||||||
|  |     | Completed = 5 | ||||||
|  |     | Verified = 6 | ||||||
|  | 
 | ||||||
|  | let updateError wallet msg = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "msg" , Sql.string msg ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET error_msg = @msg, status = 'Error' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updatePendingError wallet msg txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "msg" , Sql.string msg ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET error_msg = @msg, pending_tx = @txId, status = 'PendingError' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  |      | ||||||
|  | let updatePending wallet txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET pending_tx = @txId, status = 'Pending' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  | 
 | ||||||
|  | let updateCompleted wallet txId = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET successful_tx = pending_tx, status = 'Completed' WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  |      | ||||||
|  | let updateVerified wallet txId amount = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "txId" , Sql.string txId ; "amount" , Sql.int amount ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET pending_tx = @txId, status = 'Verified', total_dropped = @amount WHERE crypto.wallet_address = @wallet; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQueryAsync | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | let getTokenCountToDrop wallet = | ||||||
|  |     task { | ||||||
|  |         let! wl =  | ||||||
|  |             devConnStr | ||||||
|  |             |> Sql.connect | ||||||
|  |             |> Sql.parameters [ "wallet" , Sql.string wallet ] | ||||||
|  |             |> Sql.query """ | ||||||
|  |                     SELECT has_wl, has_og FROM crypto WHERE wallet_address = @wallet; | ||||||
|  |                 """ | ||||||
|  |             |> Sql.executeRowAsync (fun reader -> {| HasWhitelist = reader.bool "has_wl" ; HasOg = reader.bool "has_og" |}) | ||||||
|  |         return (if wl.HasWhitelist then 1uL else 0uL) + (if wl.HasOg then 2uL else 0uL) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | let executeDrop (wallet : string) = | ||||||
|  |     let associatedTokenAccountOwner = PublicKey(wallet) | ||||||
|  |     let associatedTokenAccount = AssociatedTokenAccountProgram.DeriveAssociatedTokenAccount(associatedTokenAccountOwner, mintAccount) | ||||||
|  |     let log msg = printfn $"{wallet} || {msg}" | ||||||
|  | 
 | ||||||
|  |     log $"ATA: {associatedTokenAccount.Key}" | ||||||
|  |     let buildTransaction (block : LatestBlockHash) amount (targetWallet : string) = | ||||||
|  |         TransactionBuilder() | ||||||
|  |             .SetRecentBlockHash(block.Blockhash) | ||||||
|  |             .SetFeePayer(authority.Account) | ||||||
|  |             .AddInstruction(AssociatedTokenAccountProgram.CreateAssociatedTokenAccount( | ||||||
|  |                 authority.Account, | ||||||
|  |                 PublicKey(targetWallet), | ||||||
|  |                 mintAccount)) | ||||||
|  |             .AddInstruction(TokenProgram.Transfer( | ||||||
|  |                 sourceAtaAccount, | ||||||
|  |                 associatedTokenAccount, | ||||||
|  |                 amount, | ||||||
|  |                 authority.Account)) | ||||||
|  |             .Build(authority.Account); | ||||||
|  |     async { | ||||||
|  | //        let streamingClient = ClientFactory.GetStreamingClient(Cluster.DevNet) | ||||||
|  |         let streamingClient = ClientFactory.GetStreamingClient(wssClientUrl) | ||||||
|  |         do! streamingClient.ConnectAsync() |> Async.AwaitTask | ||||||
|  |         let blockHash = rpcClient.GetLatestBlockHash() | ||||||
|  |         let! amount = getTokenCountToDrop wallet |> Async.AwaitTask | ||||||
|  |         log $"Dropping {amount} tokens" | ||||||
|  |         let tx = buildTransaction blockHash.Result.Value amount wallet | ||||||
|  |         let! tx = rpcClient.SendTransactionAsync(tx) |> Async.AwaitTask | ||||||
|  |         if tx.ErrorData <> null then | ||||||
|  |             let! _ = updateError wallet (tx.ErrorData.Logs |> String.concat "\n") |> Async.AwaitTask | ||||||
|  |             () | ||||||
|  |             log $"Transaction error: {wallet}" | ||||||
|  |             return () | ||||||
|  |         elif String.IsNullOrWhiteSpace(tx.Result) then | ||||||
|  |             let msg = $"Transaction did not have an ID but the ErrorData was null: {tx.Reason}" | ||||||
|  |             let! _ = updateError wallet msg |> Async.AwaitTask | ||||||
|  |             log $"Odd Transaction Error" | ||||||
|  |             return () | ||||||
|  |         else | ||||||
|  |             log $"Successful, now waiting for RPC" | ||||||
|  |             let! _ = updatePending wallet tx.Result |> Async.AwaitTask | ||||||
|  |             let! _ = streamingClient.SubscribeSignatureAsync(tx.Result, fun sub result -> | ||||||
|  |                 if result.Value.Error = null then | ||||||
|  |                     log "RPC Finished" | ||||||
|  |                     task { | ||||||
|  |                         let! _ = updateCompleted wallet tx.Result | ||||||
|  |                         log "Getting Transaction and Token Balance" | ||||||
|  |                         let! txInfo = rpcClient.GetTransactionAsync(tx.Result) | ||||||
|  |                         let! tokenBalance = rpcClient.GetTokenAccountBalanceAsync(associatedTokenAccount) | ||||||
|  |                          | ||||||
|  |                         log $"Transaction Successful? {txInfo.WasSuccessful} - Token Balance {tokenBalance.Result.Value.AmountUlong}" | ||||||
|  |                         if txInfo.WasSuccessful = true && tokenBalance.Result.Value.AmountUlong = amount then | ||||||
|  |                             let! _ = updateVerified wallet tx.Result (int amount)  | ||||||
|  |                             () | ||||||
|  |                         return () | ||||||
|  |                     } |> Async.AwaitTask |> Async.Start | ||||||
|  |                 else | ||||||
|  |                     let msg =  $"Got an error, check the tx id" | ||||||
|  |                     updatePendingError wallet msg tx.Result |> Async.AwaitTask |> Async.Ignore |> Async.Start) |> Async.AwaitTask | ||||||
|  |             return () | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | let targetWallets =  | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.query """ | ||||||
|  |             SELECT wallet_address FROM crypto WHERE status = 'Ready' AND total_dropped = 0; | ||||||
|  |         """ | ||||||
|  |     |> Sql.execute (fun reader -> reader.string "wallet_address") | ||||||
|  | 
 | ||||||
|  | printfn $"Got target wallets: {targetWallets.Length}" | ||||||
|  | 
 | ||||||
|  | let asyncs = | ||||||
|  |     targetWallets | ||||||
|  |     |> List.map executeDrop | ||||||
|  |     |> List.chunkBySize 5 | ||||||
|  | 
 | ||||||
|  | async { | ||||||
|  |     for a in asyncs do | ||||||
|  |         let! _ = Async.Parallel a | ||||||
|  |         do! Async.Sleep 500 | ||||||
|  | } |> Async.Start | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | Console.ReadLine() |> ignore | ||||||
|  | 
 | ||||||
							
								
								
									
										148
									
								
								Bot/Scripts/GetWhitelisted.fsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								Bot/Scripts/GetWhitelisted.fsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,148 @@ | |||||||
|  | #load "/home/joe/Development/DegenzGame/.paket/load/net6.0/main.group.fsx";; | ||||||
|  | 
 | ||||||
|  | open Npgsql.FSharp | ||||||
|  | open DSharpPlus | ||||||
|  | open DSharpPlus.Entities | ||||||
|  | open Solnet.Programs | ||||||
|  | open dotenv.net | ||||||
|  | 
 | ||||||
|  | let prodEnv = DotEnv.Read(DotEnvOptions(envFilePaths = [ "./.prod.env" ])) | ||||||
|  | let devEnv = DotEnv.Read(DotEnvOptions(envFilePaths = [ "./.dev.env" ])) | ||||||
|  | 
 | ||||||
|  | let ( _ , prodConnStr )= prodEnv.TryGetValue("DATABASE_URL") | ||||||
|  | let ( _ , devConnStr )= devEnv.TryGetValue("DATABASE_URL") | ||||||
|  | let ( _ , adminBotToken )= prodEnv.TryGetValue("TOKEN_ADMINBOT") | ||||||
|  | 
 | ||||||
|  | let botConfig = DiscordConfiguration() | ||||||
|  | botConfig.TokenType <- TokenType.Bot | ||||||
|  | botConfig.Intents <- DiscordIntents.All | ||||||
|  | botConfig.Token <- adminBotToken | ||||||
|  | 
 | ||||||
|  | printfn "Connecting" | ||||||
|  | let bot = new DiscordClient(botConfig) | ||||||
|  | bot.ConnectAsync() |> Async.AwaitTask |> Async.RunSynchronously | ||||||
|  | 
 | ||||||
|  | printfn "Getting Guild" | ||||||
|  | let prodGuild = 933888229776703559uL | ||||||
|  | let guild = bot.GetGuildAsync(prodGuild) |> Async.AwaitTask |> Async.RunSynchronously | ||||||
|  | printfn "Getting Members" | ||||||
|  | let users = guild.GetAllMembersAsync() |> Async.AwaitTask |> Async.RunSynchronously | ||||||
|  | printfn $"Total Members: {users.Count}" | ||||||
|  | 
 | ||||||
|  | let firstDrop = | ||||||
|  |     users | ||||||
|  |     |> Seq.filter (fun u ->  u.Roles |> Seq.exists (fun role -> | ||||||
|  |         role.Id = 978229149569286174uL)) | ||||||
|  |     |> Seq.distinct | ||||||
|  |     |> Seq.toList | ||||||
|  |      | ||||||
|  | printfn $"{firstDrop.Length}" | ||||||
|  |      | ||||||
|  | let changeStatus ids = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "ids" , Sql.stringArray ids ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET status = 'Ready' WHERE discord_id = ANY (ARRAY[@ids]::varchar[]) AND status = 'Nothing' | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQuery | ||||||
|  | 
 | ||||||
|  | changeStatus (firstDrop |> List.map (fun m -> string m.Id) |> List.toArray) | ||||||
|  |      | ||||||
|  | let whitelisted = | ||||||
|  |     users | ||||||
|  |     |> Seq.filter (fun u ->  u.Roles |> Seq.exists (fun role -> role.Name.Contains("Confirmed"))) | ||||||
|  |     |> Seq.toList | ||||||
|  |      | ||||||
|  | printfn $"Total Whitelist Confirmed: {whitelisted.Length}" | ||||||
|  | 
 | ||||||
|  | printfn "Getting Wallet Addresses:" | ||||||
|  | let walletAddresses = | ||||||
|  |     prodConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.query """ | ||||||
|  |             SELECT DISTINCT discord_id, display_name, wallet_address FROM "user" WHERE wallet_address IS NOT NULL; | ||||||
|  |         """ | ||||||
|  |     |> Sql.execute (fun reader -> {| Id = reader.string "discord_id" |> uint64 ; Name = reader.string "display_name" ; Wallet = reader.string "wallet_address" |}) | ||||||
|  |      | ||||||
|  | printfn $"Total Wallet Addresses: {walletAddresses.Length}" | ||||||
|  | 
 | ||||||
|  | let insert did name wallet wl og = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "did" , Sql.string (string did) ; "name" , Sql.string name ; "wallet" , Sql.string wallet  | ||||||
|  |                         "wl" , Sql.bool wl ; "og" , Sql.bool og ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             INSERT INTO crypto(discord_id, display_name, wallet_address, has_wl, has_og) VALUES (@did, @name, @wallet, @wl, @og) | ||||||
|  |             ON CONFLICT (discord_id) DO | ||||||
|  |             UPDATE SET wallet_address = @wallet, has_wl = @wl , has_og = @og WHERE crypto.discord_id = @did AND crypto.status = 'Nothing'; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQuery | ||||||
|  |      | ||||||
|  | let updateUserWithWallet wallet wl og = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "wallet" , Sql.string wallet ; "wl" , Sql.bool wl ; "og" , Sql.bool og ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             UPDATE crypto SET has_wl = @wl, has_og = @og WHERE crypto.wallet_address = @wallet AND crypto.status = 'Nothing'; | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQuery | ||||||
|  |      | ||||||
|  | let prune ids = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.parameters [ "ids" , Sql.stringArray ids ] | ||||||
|  |     |> Sql.query """ | ||||||
|  |             DELETE FROM crypto WHERE discord_id = ANY (ARRAY[@ids]::varchar[]) AND status = 'Nothing' | ||||||
|  |         """ | ||||||
|  |     |> Sql.executeNonQuery | ||||||
|  |      | ||||||
|  | let getExisting () = | ||||||
|  |     devConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.query """ | ||||||
|  |             SELECT discord_id, display_name, wallet_address FROM crypto | ||||||
|  |         """ | ||||||
|  |     |> Sql.execute (fun reader -> {| Id = reader.string "discord_id" |> uint64 ; Name = reader.string "display_name" ; Wallet = reader.string "wallet_address" |}) | ||||||
|  |      | ||||||
|  | let walletExists wallet = | ||||||
|  |     let list = | ||||||
|  |         devConnStr | ||||||
|  |         |> Sql.connect | ||||||
|  |         |> Sql.parameters [ "wallet" , Sql.string wallet ] | ||||||
|  |         |> Sql.query """ | ||||||
|  |                 SELECT wallet_address FROM crypto WHERE wallet_address = @wallet | ||||||
|  |             """ | ||||||
|  |         |> Sql.execute (fun reader -> reader.string "wallet_address") | ||||||
|  |     not list.IsEmpty  | ||||||
|  |      | ||||||
|  | printfn "Inserting" | ||||||
|  | async { | ||||||
|  |     for user in whitelisted do | ||||||
|  |         for wa in walletAddresses do | ||||||
|  |             if wa.Id = user.Id then | ||||||
|  |                 let hasWL = user.Roles |> Seq.exists (fun role -> role.Name = "Whitelist Confirmed") | ||||||
|  |                 let hasOG = user.Roles |> Seq.exists (fun role -> role.Name = "OG Whitelist Confirmed") | ||||||
|  |                 try | ||||||
|  |                     if walletExists wa.Wallet then | ||||||
|  |                         let _ = updateUserWithWallet wa.Wallet hasWL hasOG | ||||||
|  |                         () | ||||||
|  |                     else | ||||||
|  |                         let _ = insert wa.Id wa.Name wa.Wallet hasWL hasOG | ||||||
|  |                         () | ||||||
|  |                 with ex -> printfn $"Huh? {ex.Message}" | ||||||
|  |         () | ||||||
|  |     () | ||||||
|  |     let existing = getExisting () | ||||||
|  |     let usersToFilter = | ||||||
|  |         existing |> List.filter (fun wa -> (whitelisted |> List.exists (fun wl -> wl.Id = wa.Id)) |> not)  | ||||||
|  |     let toPrune = usersToFilter |> List.map (fun u -> u.Id |> string) |> List.toArray | ||||||
|  |     let _ = prune toPrune | ||||||
|  |     if toPrune.Length > 0 then | ||||||
|  |         printfn $"Pruning {toPrune.Length} users: {toPrune}" | ||||||
|  |     let existing = getExisting () | ||||||
|  |     printfn $"Total Users: {existing.Length}" | ||||||
|  |          | ||||||
|  | } |> Async.RunSynchronously | ||||||
|  | 
 | ||||||
|  | bot.DisconnectAsync() |> Async.AwaitTask |> Async.RunSynchronously | ||||||
							
								
								
									
										96
									
								
								Bot/Scripts/TransferNFT.fsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								Bot/Scripts/TransferNFT.fsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,96 @@ | |||||||
|  | #load "/home/joe/Development/DegenzGame/.paket/load/net6.0/main.group.fsx";; | ||||||
|  | 
 | ||||||
|  | open Npgsql.FSharp | ||||||
|  | open dotenv.net | ||||||
|  | open System.IO | ||||||
|  | open System.Diagnostics | ||||||
|  | open System.Threading.Tasks | ||||||
|  | 
 | ||||||
|  | let prodEnv = DotEnv.Read(DotEnvOptions(envFilePaths = [ "./.prod.env" ])) | ||||||
|  | let ( _ , prodConnStr )= prodEnv.TryGetValue("DATABASE_URL") | ||||||
|  | 
 | ||||||
|  | type NftTransfer = { | ||||||
|  |     Id : uint64 | ||||||
|  |     Name : string | ||||||
|  |     NftName : string | ||||||
|  |     NftAddress : string | ||||||
|  |     UserWallet : string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | printfn "Getting Wallet Addresses:" | ||||||
|  | 
 | ||||||
|  | let pending = | ||||||
|  |     prodConnStr | ||||||
|  |     |> Sql.connect | ||||||
|  |     |> Sql.query """ | ||||||
|  |             SELECT u.id, u.display_name, token.name, token.address, mpa.tx_wallet FROM gen_one_token token | ||||||
|  |             JOIN mint_pass_assignment mpa on token.id = mpa.token_id | ||||||
|  |             JOIN "user" u on mpa.recipient_id = u.id | ||||||
|  |             WHERE mpa.fulfilled = false AND token.locked = false | ||||||
|  |             ORDER BY mpa.created_at; | ||||||
|  |         """ | ||||||
|  |     |> Sql.execute (fun reader -> | ||||||
|  |             { Id = reader.string "id" |> uint64 | ||||||
|  |               Name = reader.string "display_name" | ||||||
|  |               NftName = reader.string "name" | ||||||
|  |               NftAddress = reader.string "address" | ||||||
|  |               UserWallet = reader.string "tx_wallet" }) | ||||||
|  |      | ||||||
|  | 
 | ||||||
|  | let testSample = [ pending |> List.last ] | ||||||
|  | 
 | ||||||
|  | type CommandResult = {  | ||||||
|  |   ExitCode: int;  | ||||||
|  |   StandardOutput: string; | ||||||
|  |   StandardError: string  | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | let executeCommand executable args = | ||||||
|  |     async { | ||||||
|  |         let startInfo = ProcessStartInfo() | ||||||
|  |         startInfo.FileName <- executable | ||||||
|  | 
 | ||||||
|  |         for a in args do | ||||||
|  |             startInfo.ArgumentList.Add(a) | ||||||
|  | 
 | ||||||
|  |         startInfo.RedirectStandardOutput <- true | ||||||
|  |         startInfo.RedirectStandardError <- true | ||||||
|  |         startInfo.UseShellExecute <- false | ||||||
|  |         startInfo.CreateNoWindow <- true | ||||||
|  |         use p = new Process() | ||||||
|  |         p.StartInfo <- startInfo | ||||||
|  |         p.Start() |> ignore | ||||||
|  | 
 | ||||||
|  |         let outTask = | ||||||
|  |             Task.WhenAll( | ||||||
|  |                 [| p.StandardOutput.ReadToEndAsync() | ||||||
|  |                    p.StandardError.ReadToEndAsync() |] | ||||||
|  |             ) | ||||||
|  | 
 | ||||||
|  |         do! p.WaitForExitAsync() |> Async.AwaitTask | ||||||
|  |         let! out = outTask |> Async.AwaitTask | ||||||
|  | 
 | ||||||
|  |         return | ||||||
|  |             { ExitCode = p.ExitCode | ||||||
|  |               StandardOutput = out.[0] | ||||||
|  |               StandardError = out.[1] } | ||||||
|  |     } | ||||||
|  | let executeShellCommand command = | ||||||
|  |     executeCommand "/usr/bin/env" [ "-S"; "bash"; "-c"; command ] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | let transfer (nft : NftTransfer) = | ||||||
|  |     printfn $"Transferring {nft.NftName} to {nft.Name} " | ||||||
|  |     let result = | ||||||
|  |         $"spl-token transfer --allow-unfunded-recipient --fund-recipient {nft.NftAddress} 1 {nft.UserWallet}" | ||||||
|  |         |> executeShellCommand  | ||||||
|  |         |> Async.RunSynchronously | ||||||
|  |     if result.ExitCode = 0 then | ||||||
|  |         let user = $"{nft.Id} - {nft.Name} - {nft.NftName}" | ||||||
|  |         let tx = result.StandardOutput | ||||||
|  |         File.AppendAllLines("/home/joe/Downloads/transactions", [ user ; tx ]) | ||||||
|  |     else | ||||||
|  |         printfn $"{result.StandardError}" | ||||||
|  | 
 | ||||||
|  | for nft in pending do | ||||||
|  |     transfer nft | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user