def test_errors(self): # get random private key private_key_1, account_1 = account.generate_account() private_key_2, account_2 = account.generate_account() private_key_3, account_3 = account.generate_account() # create transaction gh = "JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=" txn = transaction.PaymentTxn(account_2, 3, 1234, 1334, gh, account_2, 1000) # create multisig address with invalid version msig = transaction.Multisig(2, 2, [account_1, account_2]) self.assertRaises(error.UnknownMsigVersionError, msig.validate) # change it to have invalid threshold msig.version = 1 msig.threshold = 3 self.assertRaises(error.InvalidThresholdError, msig.validate) # try to sign multisig transaction msig.threshold = 2 mtx = transaction.MultisigTransaction(txn, msig) self.assertRaises(error.BadTxnSenderError, mtx.sign, private_key_1) # change sender address to be correct txn.sender = msig.address() mtx = transaction.MultisigTransaction(txn, msig) # try to sign with incorrect private key self.assertRaises(error.InvalidSecretKeyError, mtx.sign, private_key_3) # create another multisig with different address msig_2 = transaction.Multisig(1, 2, [account_2, account_3]) # try to merge with different addresses mtx_2 = transaction.MultisigTransaction(txn, msig_2) self.assertRaises(error.MergeKeysMismatchError, transaction.MultisigTransaction.merge, [mtx, mtx_2]) # create another multisig with same address msig_3 = msig_2.get_multisig_account() # add mismatched signatures msig_2.subsigs[0].signature = "sig2" msig_3.subsigs[0].signature = "sig3" # try to merge self.assertRaises(error.DuplicateSigMismatchError, transaction.MultisigTransaction.merge, [ transaction.MultisigTransaction(txn, msig_2), transaction.MultisigTransaction(txn, msig_3) ])
def create_msigpaytxn(context): context.txn = transaction.PaymentTxn(context.msig.address(), context.fee, context.fv, context.lv, context.gh, context.to, context.amt, context.close, context.note, context.gen) context.mtx = transaction.MultisigTransaction(context.txn, context.msig)
def default_msig_txn(context, amt, note): params = context.acl.suggested_params() context.last_round = params["lastRound"] if note == "none": note = None else: note = base64.b64decode(note) context.msig = transaction.Multisig(1, 1, context.accounts) context.txn = transaction.PaymentTxn(context.msig.address(), params["fee"], context.last_round, context.last_round + 1000, params["genesishashb64"], context.accounts[1], int(amt), note=note, gen=params["genesisID"]) context.mtx = transaction.MultisigTransaction(context.txn, context.msig) context.pk = context.accounts[0]
def default_msig_txn(context, amt, note): params = context.acl.suggested_params() context.last_round = params.first if note == "none": note = None else: note = base64.b64decode(note) context.msig = transaction.Multisig(1, 1, context.accounts) context.txn = transaction.PaymentTxn(context.msig.address(), params, context.accounts[1], int(amt), note=note) context.mtx = transaction.MultisigTransaction(context.txn, context.msig) context.pk = context.accounts[0]
def scenario5(): """ Alice and Bob send 100 algos to Charlie from a joint multisignature account. """ alice_bob_multisig = transaction.Multisig(1, 2, [alice, bob]) msig_address = alice_bob_multisig.address() print("Alice and Bob's Multisig Address: {}".format(msig_address)) amount = 100000000 fee = 1000 data = (msig_address, fee, first_valid, last_valid, genesis_hash, charlie, amount) data_add = {"gen": genesis_id, "flat_fee": True} tx = transaction.PaymentTxn(*data, **data_add) tx_with_multisig = transaction.MultisigTransaction(tx, alice_bob_multisig) return (tx, tx_with_multisig)
def test_sign(self): msig = transaction.Multisig(1, 2, [ "DN7MBMCL5JQ3PFUQS7TMX5AH4EEKOBJVDUF4TCV6WERATKFLQF4MQUPZTA", "BFRTECKTOOE7A5LHCF3TTEOH2A7BW46IYT2SX5VP6ANKEXHZYJY77SJTVM", "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU" ]) mn = ("advice pudding treat near rule blouse same whisper inner " + "electric quit surface sunny dismiss leader blood seat clown " + "cost exist hospital century reform able sponsor") sk = mnemonic.to_private_key(mn) rcv = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI" gh = "JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=" close = "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA" txn = transaction.PaymentTxn(msig.address(), 4, 12466, 13466, gh, rcv, 1000, note=base64.b64decode("X4Bl4wQ9rCo="), gen="devnet-v33.0", close_remainder_to=close) mtx = transaction.MultisigTransaction(txn, msig) mtx.sign(sk) golden = ("gqRtc2lng6ZzdWJzaWeTgaJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC" + "8mKvrEiCairgXiBonBrxCAJYzIJU3OJ8HVnEXc5kcfQPhtzyMT1K/av8B" + "qiXPnCcYKicGvEIOfw+E0GgR358xyNh4sRVfRnHVGhhcIAkIZn9ElYcGi" + "hoXPEQF6nXZ7CgInd1h7NVspIPFZNhkPL+vGFpTNwH3Eh9gwPM8pf1EPT" + "HfPvjf14sS7xN7mTK+wrz7Odhp4rdWBNUASjdGhyAqF2AaN0eG6Lo2Ftd" + "M0D6KVjbG9zZcQgQOk0koglZMvOnFmmm2dUJonpocOiqepbZabopEIf/F" + "ejZmVlzQSYomZ2zTCyo2dlbqxkZXZuZXQtdjMzLjCiZ2jEICYLIAmgk6i" + "Gi3lYci+l5Ubt5+0X5NhcTHivsEUmkO3Somx2zTSapG5vdGXECF+AZeME" + "Pawqo3JjdsQge2ziT+tbrMCxZOKcIixX9fY9w4fUOQSCWEEcX+EPfAKjc" + "25kxCCNkrSJkAFzoE36Q1mjZmpq/OosQqBd2cH3PuulR4A36aR0eXBlo3" + "BheQ==") self.assertEqual(golden, encoding.msgpack_encode(mtx)) txid_golden = "TDIO6RJWJIVDDJZELMSX5CPJW7MUNM3QR4YAHYAKHF3W2CFRTI7A" self.assertEqual(txn.get_txid(), txid_golden)
"Please go to: https://bank.testnet.algorand.network/ to fund your multisig account." + '\n' + "Press Enter to continue...") # get suggested parameters params = acl.suggested_params() gen = params["genesisID"] gh = params["genesishashb64"] last_round = params["lastRound"] fee = params["fee"] # create a transaction sender = msig.address() recipient = "4CXXFP3SJJW63HGEQD4OPSDPPIYDW7BXCVP4DQZG7T33Z3BXTOA4UMEDM4" amount = 10000 txn = transaction.PaymentTxn(sender, fee, last_round, last_round + 100, gh, recipient, amount) # create a SignedTransaction object mtx = transaction.MultisigTransaction(txn, msig) # sign the transaction mtx.sign(private_key_1) mtx.sign(private_key_2) # print encoded transaction print(encoding.msgpack_encode(mtx)) # send the transaction transaction_id = acl.send_raw_transaction(encoding.msgpack_encode(mtx)) print("\nTransaction was sent!") print("Transaction ID: " + transaction_id + "\n")
def test_wallet(self): # initialize wallet w = wallet.Wallet(wallet_name, wallet_pswd, self.kcl) # get master derivation key mdk = w.export_master_derivation_key() # get mnemonic mn = w.get_mnemonic() # make sure mnemonic can be converted back to mdk self.assertEqual(mdk, mnemonic.to_master_derivation_key(mn)) # generate account with account and check if it's valid private_key_1, account_1 = account.generate_account() # import generated account import_key = w.import_key(private_key_1) self.assertEqual(import_key, account_1) # check that the account is in the wallet keys = w.list_keys() self.assertIn(account_1, keys) # generate account with kmd account_2 = w.generate_key() private_key_2 = w.export_key(account_2) # get suggested parameters and fee params = self.acl.suggested_params() gen = params["genesisID"] gh = params["genesishashb64"] last_round = params["lastRound"] fee = params["fee"] # create transaction txn = transaction.PaymentTxn(self.account_0, fee, last_round, last_round + 100, gh, account_1, 100000, gen=gen) # sign transaction with wallet signed_kmd = w.sign_transaction(txn) # get self.account_0 private key private_key_0 = w.export_key(self.account_0) # sign transaction with account signed_account = txn.sign(private_key_0) # check that signing both ways results in the same thing self.assertEqual(encoding.msgpack_encode(signed_account), encoding.msgpack_encode(signed_kmd)) # create multisig account and transaction msig = transaction.Multisig(1, 2, [account_1, account_2]) txn = transaction.PaymentTxn(msig.address(), fee, last_round, last_round + 100, gh, self.account_0, 1000, gen=gen) # import multisig account msig_address = w.import_multisig(msig) # check that the multisig account is listed msigs = w.list_multisig() self.assertIn(msig_address, msigs) # export multisig account exported = w.export_multisig(msig_address) self.assertEqual(len(exported.subsigs), 2) # create multisig transaction mtx = transaction.MultisigTransaction(txn, msig) # sign the multisig using kmd msig_1 = w.sign_multisig_transaction(account_1, mtx) signed_kmd = w.sign_multisig_transaction(account_2, msig_1) # sign the multisig offline mtx1 = transaction.MultisigTransaction(txn, msig) mtx1.sign(private_key_1) mtx2 = transaction.MultisigTransaction(txn, msig) mtx2.sign(private_key_2) signed_account = transaction.MultisigTransaction.merge([mtx1, mtx2]) # check that they are the same self.assertEqual(encoding.msgpack_encode(signed_account), encoding.msgpack_encode(signed_kmd)) # delete accounts del_1 = w.delete_key(account_1) del_2 = w.delete_key(account_2) del_3 = w.delete_multisig(msig_address) self.assertTrue(del_1) self.assertTrue(del_2) self.assertTrue(del_3) # test renaming the wallet w.rename(wallet_name + "1") self.assertEqual(wallet_name + "1", w.info()["wallet"]["name"]) w.rename(wallet_name) self.assertEqual(wallet_name, w.info()["wallet"]["name"]) # test releasing the handle w.release_handle() self.assertRaises(error.KMDHTTPError, self.kcl.get_wallet, w.handle) # test handle automation w.info()
def test_multisig(self): # get the default wallet wallets = self.kcl.list_wallets() wallet_id = None for w in wallets: if w["name"] == wallet_name: wallet_id = w["id"] # get a new handle for the wallet handle = self.kcl.init_wallet_handle(wallet_id, wallet_pswd) # generate two accounts with kmd account_1 = self.kcl.generate_key(handle, False) account_2 = self.kcl.generate_key(handle, False) # get their private keys private_key_1 = self.kcl.export_key(handle, wallet_pswd, account_1) private_key_2 = self.kcl.export_key(handle, wallet_pswd, account_2) # get suggested parameters and fee params = self.acl.suggested_params() gen = params["genesisID"] gh = params["genesishashb64"] last_round = params["lastRound"] fee = params["fee"] # create multisig account and transaction msig = transaction.Multisig(1, 2, [account_1, account_2]) txn = transaction.PaymentTxn(msig.address(), fee, last_round, last_round + 100, gh, self.account_0, 1000, gen=gen) # check that the multisig account is valid msig.validate() # import multisig account msig_address = self.kcl.import_multisig(handle, msig) # export multisig account exported = self.kcl.export_multisig(handle, msig_address) self.assertEqual(len(exported.subsigs), 2) # create multisig transaction mtx = transaction.MultisigTransaction(txn, msig) # sign using kmd msig_1 = self.kcl.sign_multisig_transaction(handle, wallet_pswd, account_1, mtx) signed_kmd = self.kcl.sign_multisig_transaction( handle, wallet_pswd, account_2, msig_1) # sign offline mtx1 = transaction.MultisigTransaction(txn, msig) mtx1.sign(private_key_1) mtx2 = transaction.MultisigTransaction(txn, msig) mtx2.sign(private_key_2) signed_account = transaction.MultisigTransaction.merge([mtx1, mtx2]) # check that they are the same self.assertEqual(encoding.msgpack_encode(signed_account), encoding.msgpack_encode(signed_kmd)) # delete accounts del_1 = self.kcl.delete_key(handle, wallet_pswd, account_1) del_2 = self.kcl.delete_key(handle, wallet_pswd, account_2) del_3 = self.kcl.delete_multisig(handle, wallet_pswd, msig_address) self.assertTrue(del_1) self.assertTrue(del_2) self.assertTrue(del_3)
def test_merge(self): msig = transaction.Multisig(1, 2, [ "DN7MBMCL5JQ3PFUQS7TMX5AH4EEKOBJVDUF4TCV6WERATKFLQF4MQUPZTA", "BFRTECKTOOE7A5LHCF3TTEOH2A7BW46IYT2SX5VP6ANKEXHZYJY77SJTVM", "47YPQTIGQEO7T4Y4RWDYWEKV6RTR2UNBQXBABEEGM72ESWDQNCQ52OPASU" ]) mn = ("auction inquiry lava second expand liberty glass involve " + "ginger illness length room item discover ahead table doctor " + "term tackle cement bonus profit right above catch") sk = mnemonic.to_private_key(mn) sender = "RWJLJCMQAFZ2ATP2INM2GZTKNL6OULCCUBO5TQPXH3V2KR4AG7U5UA5JNM" rcv = "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI" gh = "/rNsORAUOQDD2lVCyhg2sA/S+BlZElfNI/YEL5jINp0=" close = "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA" txn = transaction.PaymentTxn(sender, 0, 62229, 63229, gh, rcv, 1000, note=base64.b64decode("RSYiABhShvs="), gen="devnet-v38.0", close_remainder_to=close) mtx = transaction.MultisigTransaction(txn, msig) mtx.sign(sk) golden = ("gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC" + "8mKvrEiCairgXihc8RAuLAFE0oma0skOoAmOzEwfPuLYpEWl4LINtsiLr" + "UqWQkDxh4WHb29//YCpj4MFbiSgD2jKYt0XKRD86zKCF4RDYGicGvEIAl" + "jMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxgaJwa8Qg5/D4TQaB" + "HfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGjdGhyAqF2AaN0eG6Lo2Ftd" + "M0D6KVjbG9zZcQgQOk0koglZMvOnFmmm2dUJonpocOiqepbZabopEIf/F" + "ejZmVlzQPoomZ2zfMVo2dlbqxkZXZuZXQtdjM4LjCiZ2jEIP6zbDkQFDk" + "Aw9pVQsoYNrAP0vgZWRJXzSP2BC+YyDadomx2zfb9pG5vdGXECEUmIgAY" + "Uob7o3JjdsQge2ziT+tbrMCxZOKcIixX9fY9w4fUOQSCWEEcX+EPfAKjc" + "25kxCCNkrSJkAFzoE36Q1mjZmpq/OosQqBd2cH3PuulR4A36aR0eXBlo3" + "BheQ==") self.assertEqual(golden, encoding.msgpack_encode(mtx)) mtx_2 = transaction.MultisigTransaction(txn, msig.get_multisig_account()) mn2 = ("since during average anxiety protect cherry club long " + "lawsuit loan expand embark forum theory winter park twenty " + "ball kangaroo cram burst board host ability left") sk2 = mnemonic.to_private_key(mn2) mtx_2.sign(sk2) mtx_final = transaction.MultisigTransaction.merge([mtx, mtx_2]) golden2 = ("gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUd" + "C8mKvrEiCairgXihc8RAuLAFE0oma0skOoAmOzEwfPuLYpEWl4LINtsi" + "LrUqWQkDxh4WHb29//YCpj4MFbiSgD2jKYt0XKRD86zKCF4RDYKicGvE" + "IAljMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxoXPEQBAhuyRj" + "sOrnHp3s/xI+iMKiL7QPsh8iJZ22YOJJP0aFUwedMr+a6wfdBXk1Oefy" + "rAN1wqJ9rq6O+DrWV1fH0ASBonBrxCDn8PhNBoEd+fMcjYeLEVX0Zx1R" + "oYXCAJCGZ/RJWHBooaN0aHICoXYBo3R4boujYW10zQPopWNsb3NlxCBA" + "6TSSiCVky86cWaabZ1Qmiemhw6Kp6ltlpuikQh/8V6NmZWXNA+iiZnbN" + "8xWjZ2VurGRldm5ldC12MzguMKJnaMQg/rNsORAUOQDD2lVCyhg2sA/S" + "+BlZElfNI/YEL5jINp2ibHbN9v2kbm90ZcQIRSYiABhShvujcmN2xCB7" + "bOJP61uswLFk4pwiLFf19j3Dh9Q5BIJYQRxf4Q98AqNzbmTEII2StImQ" + "AXOgTfpDWaNmamr86ixCoF3Zwfc+66VHgDfppHR5cGWjcGF5") self.assertEqual(golden2, encoding.msgpack_encode(mtx_final))
def create_msigpaytxn(context): context.txn = transaction.PaymentTxn(context.msig.address(), context.params, context.to, context.amt, context.close, context.note) context.mtx = transaction.MultisigTransaction(context.txn, context.msig)