Cleaning up
This commit is contained in:
		
							parent
							
								
									7cae807bfa
								
							
						
					
					
						commit
						0db69bf72b
					
				
							
								
								
									
										179
									
								
								Airdrop.fsx
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								Airdrop.fsx
									
									
									
									
									
								
							| @ -1,179 +0,0 @@ | ||||
| #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 | ||||
| @ -1,188 +0,0 @@ | ||||
| #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 | ||||
| 
 | ||||
| @ -1,148 +0,0 @@ | ||||
| #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 | ||||
| @ -1,96 +0,0 @@ | ||||
| #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