예제 #1
0
    def create_mint(
        cls,
        conn: Client,
        payer: Account,
        mint_authority: PublicKey,
        decimals: int,
        program_id: PublicKey,
        freeze_authority: Optional[PublicKey] = None,
        skip_confirmation: bool = False,
    ) -> Token:
        """Create and initialize a token.

        :param conn: RPC connection to a solana cluster.
        :param payer: Fee payer for transaction.
        :param mint_authority: Account or multisig that will control minting.
        :param decimals: Location of the decimal place.
        :param program_id: SPL Token program account.
        :param freeze_authority: (optional) Account or multisig that can freeze token accounts.
        :param skip_confirmation: (optional) Option to skip transaction confirmation.
        :return: Token object for the newly minted token.

        If skip confirmation is set to `False`, this method will block for at most 30 seconds
        or until the transaction is confirmed.
        """
        # Allocate memory for the account
        balance_needed = Token.get_min_balance_rent_for_exempt_for_mint(conn)
        # Construct transaction
        token, txn, payer, mint_account, opts = _TokenCore._create_mint_args(
            conn, payer, mint_authority, decimals, program_id,
            freeze_authority, skip_confirmation, balance_needed, cls)
        # Send the two instructions
        conn.send_transaction(txn, payer, mint_account, opts=opts)
        return cast(Token, token)
예제 #2
0
    def create_wrapped_native_account(
        conn: Client,
        program_id: PublicKey,
        owner: PublicKey,
        payer: Account,
        amount: int,
        skip_confirmation: bool = False,
    ) -> PublicKey:
        """Create and initialize a new account on the special native token mint.

        :param conn: RPC connection to a solana cluster.
        :param program_id: SPL Token program account.
        :param owner: The owner of the new token account.
        :param payer: The source of the lamports to initialize, and payer of the initialization fees.
        :param amount: The amount of lamports to wrap.
        :param skip_confirmation: (optional) Option to skip transaction confirmation.
        :return: The new token account.

        If skip confirmation is set to `False`, this method will block for at most 30 seconds
        or until the transaction is confirmed.
        """
        # Allocate memory for the account
        balance_needed = Token.get_min_balance_rent_for_exempt_for_account(
            conn)
        new_account_public_key, txn, payer, new_account, opts = _TokenCore._create_wrapped_native_account_args(
            program_id, owner, payer, amount, skip_confirmation,
            balance_needed)
        conn.send_transaction(txn, payer, new_account, opts=opts)
        return new_account_public_key
예제 #3
0
    def create_mint(
        conn: Client,
        payer: Account,
        mint_authority: PublicKey,
        decimals: int,
        program_id: PublicKey,
        freeze_authority: Optional[PublicKey] = None,
        skip_confirmation: bool = False,
    ) -> Token:
        """Create and initialize a token.

        :param conn: RPC connection to a solana cluster.
        :param payer: Fee payer for transaction.
        :param mint_authority: Account or multisig that will control minting.
        :param decimals: Location of the decimal place.
        :param program_id: SPL Token program account.
        :param freeze_authority: (optional) Account or multisig that can freeze token accounts.
        :param skip_confirmation: (optional) Option to skip transaction confirmation.
        :return: Token object for the newly minted token.

        If skip confirmation is set to `False`, this method will block for at most 30 seconds
        or until the transaction is confirmed.
        """
        mint_account = Account()
        token = Token(conn, mint_account.public_key(), program_id, payer)
        # Allocate memory for the account
        balance_needed = Token.get_min_balance_rent_for_exempt_for_mint(conn)
        # Construct transaction
        txn = Transaction()
        txn.add(
            sp.create_account(
                sp.CreateAccountParams(
                    from_pubkey=payer.public_key(),
                    new_account_pubkey=mint_account.public_key(),
                    lamports=balance_needed,
                    space=MINT_LAYOUT.sizeof(),
                    program_id=program_id,
                )
            )
        )
        txn.add(
            spl_token.initialize_mint(
                spl_token.InitializeMintParams(
                    program_id=program_id,
                    mint=mint_account.public_key(),
                    decimals=decimals,
                    mint_authority=mint_authority,
                    freeze_authority=freeze_authority,
                )
            )
        )
        # Send the two instructions
        conn.send_transaction(
            txn, payer, mint_account, opts=TxOpts(skip_confirmation=skip_confirmation, skip_preflight=True)
        )
        return token
예제 #4
0
 def topup(self, api_endpoint, to, amount=None, skip_confirmation=True):
     """
     Send a small amount of native currency to the specified wallet to handle gas fees. Return a status flag of success or fail and the native transaction data.
     """
     msg = ""
     try:
         # Connect to the api_endpoint
         client = Client(api_endpoint)
         msg += "Initialized client"
         # List accounts
         sender_account = Account(self.private_key)
         dest_account = PublicKey(to)
         msg += " | Gathered accounts"
         # List signers
         signers = [sender_account]
         # Start transaction
         tx = Transaction()
         # Determine the amount to send
         try:
             if amount is None:
                 min_rent_reseponse = client.get_minimum_balance_for_rent_exemption(
                     ACCOUNT_LAYOUT.sizeof())
                 lamports = min_rent_reseponse["result"]
             else:
                 lamports = int(amount)
             msg += f" | Fetched lamports: {lamports * 1e-9} SOL"
         except Exception as e:
             msg += " | ERROR: couldn't process lamports"
             raise (e)
         # Generate transaction
         transfer_ix = transfer(
             TransferParams(from_pubkey=sender_account.public_key(),
                            to_pubkey=dest_account,
                            lamports=lamports))
         tx = tx.add(transfer_ix)
         msg += f" | Transferring funds"
         # Send request
         try:
             response = client.send_transaction(
                 tx,
                 *signers,
                 opts=types.TxOpts(skip_confirmation=skip_confirmation))
             return json.dumps({
                 'status':
                 HTTPStatus.OK,
                 'msg':
                 f"Successfully sent {lamports * 1e-9} SOL to {to}",
                 'tx':
                 response.get('result') if skip_confirmation else
                 response['result']['transaction']['signatures'],
             })
         except Exception as e:
             msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
             raise (e)
     except Exception as e:
         return json.dumps({
             'status': HTTPStatus.BAD_REQUEST,
             'msg': msg,
         })
예제 #5
0
 def mint_to(self,
             api_endpoint,
             pool_account,
             dest,
             amount,
             skip_confirmation=True):
     msg = ""
     client = Client(api_endpoint)
     msg += "Initialized client"
     # Create account objects
     source_account = Account(self.private_key)
     signers = [source_account]
     pool = self.load_binary_option(api_endpoint, pool_account)
     # List non-derived accounts
     pool_account = PublicKey(pool_account)
     dest_account = PublicKey(dest)
     escrow_mint_account = PublicKey(pool["escrow_mint"])
     mint_authority_account = source_account.public_key()
     payer_account = source_account.public_key()
     token_account = PublicKey(TOKEN_PROGRAM_ID)
     tx = Transaction()
     token_pda_address = get_associated_token_address(
         dest_account, escrow_mint_account)
     associated_token_account_ix = create_associated_token_account(
         payer=payer_account,
         owner=dest_account,
         mint=escrow_mint_account,
     )
     tx = tx.add(associated_token_account_ix)
     mint_to_ix = mint_to(
         MintToParams(
             program_id=token_account,
             mint=escrow_mint_account,
             dest=token_pda_address,
             mint_authority=mint_authority_account,
             amount=int(amount),
             signers=[mint_authority_account],
         ))
     tx = tx.add(mint_to_ix)
     # Send request
     try:
         response = client.send_transaction(
             tx,
             *signers,
             opts=types.TxOpts(skip_confirmation=skip_confirmation))
         return json.dumps({
             'status':
             HTTPStatus.OK,
             'msg':
             msg + f" | MintTo {dest} successful",
             'tx':
             response.get('result') if skip_confirmation else
             response['result']['transaction']['signatures'],
         })
     except Exception as e:
         msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
         raise (e)
예제 #6
0
 def settle(self,
            api_endpoint,
            pool_account,
            winning_mint,
            skip_confirmation=True):
     msg = ""
     client = Client(api_endpoint)
     msg += "Initialized client"
     # Create account objects
     source_account = Account(self.private_key)
     # Signers
     signers = [source_account]
     # List non-derived accounts
     pool_account = PublicKey(pool_account)
     winning_mint_account = PublicKey(winning_mint)
     tx = Transaction()
     settle_ix = settle_instruction(
         pool_account,
         winning_mint_account,
         source_account.public_key(),
     )
     tx = tx.add(settle_ix)
     # Send request
     try:
         response = client.send_transaction(
             tx,
             *signers,
             opts=types.TxOpts(skip_confirmation=skip_confirmation))
         return json.dumps({
             'status':
             HTTPStatus.OK,
             'msg':
             msg +
             f" | Settle successful, winner: {str(winning_mint_account)}",
             'tx':
             response.get('result') if skip_confirmation else
             response['result']['transaction']['signatures'],
         })
     except Exception as e:
         msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
         raise (e)
예제 #7
0
class TestAirdropperIntegration(TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        cls.create_token_mint(cls)
        cls.deploy_erc20_wrapper_contract(cls)
        cls.acc_num = 0

    def create_token_mint(self):
        self.solana_client = SolanaClient(SOLANA_URL)

        with open("proxy/operator-keypairs/id.json") as f:
            d = json.load(f)
        self.mint_authority = SolanaAccount(d[0:32])
        self.solana_client.request_airdrop(self.mint_authority.public_key(),
                                           1000_000_000_000, Confirmed)

        while True:
            balance = self.solana_client.get_balance(
                self.mint_authority.public_key(), Confirmed)["result"]["value"]
            if balance > 0:
                break
            sleep(1)
        print('create_token_mint mint, SolanaAccount: ',
              self.mint_authority.public_key())

        self.token = SplToken.create_mint(
            self.solana_client,
            self.mint_authority,
            self.mint_authority.public_key(),
            9,
            TOKEN_PROGRAM_ID,
        )

    def deploy_erc20_wrapper_contract(self):
        self.wrapper = ERC20Wrapper(proxy, NAME, SYMBOL, self.token, admin,
                                    self.mint_authority, EVM_LOADER_ID)
        self.wrapper.deploy_wrapper()

    def create_account_instruction(self, eth_address: str, payer: PublicKey):
        dest_address_solana, nonce = get_evm_loader_account_address(
            eth_address)
        neon_token_account = get_associated_token_address(
            dest_address_solana, ETH_TOKEN_MINT_ID)
        return TransactionInstruction(
            program_id=EVM_LOADER_ID,
            data=create_account_layout(0, 0, bytes.fromhex(eth_address[2:]),
                                       nonce),
            keys=[
                AccountMeta(pubkey=payer, is_signer=True, is_writable=True),
                AccountMeta(pubkey=dest_address_solana,
                            is_signer=False,
                            is_writable=True),
                AccountMeta(pubkey=neon_token_account,
                            is_signer=False,
                            is_writable=True),
                AccountMeta(pubkey=SYS_PROGRAM_ID,
                            is_signer=False,
                            is_writable=False),
                AccountMeta(pubkey=ETH_TOKEN_MINT_ID,
                            is_signer=False,
                            is_writable=False),
                AccountMeta(pubkey=TOKEN_PROGRAM_ID,
                            is_signer=False,
                            is_writable=False),
                AccountMeta(pubkey=ASSOCIATED_TOKEN_PROGRAM_ID,
                            is_signer=False,
                            is_writable=False),
                AccountMeta(pubkey=SYSVAR_RENT_PUBKEY,
                            is_signer=False,
                            is_writable=False),
            ])

    def create_sol_account(self):
        account = SolanaAccount()
        print(
            f"New solana account created: {account.public_key().to_base58()}. Airdropping..."
        )
        self.solana_client.request_airdrop(account.public_key(),
                                           1000_000_000_000, Confirmed)
        return account

    def create_token_account(self, owner: PublicKey, mint_amount: int):
        new_token_account = self.wrapper.create_associated_token_account(
            owner, self.mint_authority)
        self.wrapper.mint_to(new_token_account, mint_amount)
        return new_token_account

    def create_eth_account(self):
        self.acc_num += 1
        account = proxy.eth.account.create(
            f'neonlabsorg/proxy-model.py/issues/344/eth_account{self.acc_num}')
        print(f"NEON account created: {account.address}")
        return account

    def test_success_airdrop_simple_case(self):
        from_owner = self.create_sol_account()
        mint_amount = 1000_000_000_000
        from_spl_token_acc = self.create_token_account(from_owner.public_key(),
                                                       mint_amount)
        to_neon_acc = self.create_eth_account().address

        self.assertEqual(self.wrapper.get_balance(from_spl_token_acc),
                         mint_amount)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc), 0)

        TRANSFER_AMOUNT = 123456
        trx = Transaction()
        trx.add(
            self.create_account_instruction(to_neon_acc,
                                            from_owner.public_key()))
        trx.add(
            self.wrapper.create_neon_erc20_account_instruction(
                from_owner.public_key(), to_neon_acc))
        trx.add(
            self.wrapper.create_input_liquidity_instruction(
                from_owner.public_key(), from_spl_token_acc, to_neon_acc,
                TRANSFER_AMOUNT))

        opts = TxOpts(skip_preflight=True, skip_confirmation=False)
        print(self.solana_client.send_transaction(trx, from_owner, opts=opts))

        self.assertEqual(self.wrapper.get_balance(from_spl_token_acc),
                         mint_amount - TRANSFER_AMOUNT)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc),
                         TRANSFER_AMOUNT)

        wait_time = 0
        eth_balance = 0
        while wait_time < MAX_AIRDROP_WAIT_TIME:
            eth_balance = proxy.eth.get_balance(to_neon_acc)
            balance_ready = eth_balance > 0 and eth_balance < 10 * pow(10, 18)
            if balance_ready:
                break
            sleep(1)
            wait_time += 1
        print(f"Wait time for simple transaction (1 airdrop): {wait_time}")

        eth_balance = proxy.eth.get_balance(to_neon_acc)
        print("NEON balance is: ", eth_balance)
        self.assertTrue(
            eth_balance > 0 and
            eth_balance < 10 * pow(10, 18))  # 10 NEON is a max airdrop amount

    def test_success_airdrop_complex_case(self):
        from_owner = self.create_sol_account()
        mint_amount = 1000_000_000_000
        from_spl_token_acc = self.create_token_account(from_owner.public_key(),
                                                       mint_amount)
        to_neon_acc1 = self.create_eth_account().address
        to_neon_acc2 = self.create_eth_account().address

        self.assertEqual(self.wrapper.get_balance(from_spl_token_acc),
                         mint_amount)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc1), 0)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc2), 0)

        TRANSFER_AMOUNT1 = 123456
        TRANSFER_AMOUNT2 = 654321
        trx = Transaction()
        trx.add(
            self.create_account_instruction(to_neon_acc1,
                                            from_owner.public_key()))
        trx.add(
            self.create_account_instruction(to_neon_acc2,
                                            from_owner.public_key()))
        trx.add(
            self.wrapper.create_neon_erc20_account_instruction(
                from_owner.public_key(), to_neon_acc1))
        trx.add(
            self.wrapper.create_neon_erc20_account_instruction(
                from_owner.public_key(), to_neon_acc2))
        trx.add(
            self.wrapper.create_input_liquidity_instruction(
                from_owner.public_key(), from_spl_token_acc, to_neon_acc1,
                TRANSFER_AMOUNT1))
        trx.add(
            self.wrapper.create_input_liquidity_instruction(
                from_owner.public_key(), from_spl_token_acc, to_neon_acc2,
                TRANSFER_AMOUNT2))

        opts = TxOpts(skip_preflight=True, skip_confirmation=False)
        print(self.solana_client.send_transaction(trx, from_owner, opts=opts))

        self.assertEqual(self.wrapper.get_balance(from_spl_token_acc),
                         mint_amount - TRANSFER_AMOUNT1 - TRANSFER_AMOUNT2)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc1),
                         TRANSFER_AMOUNT1)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc2),
                         TRANSFER_AMOUNT2)

        wait_time = 0
        eth_balance1 = 0
        eth_balance2 = 0
        while wait_time < MAX_AIRDROP_WAIT_TIME:
            eth_balance1 = proxy.eth.get_balance(to_neon_acc1)
            eth_balance2 = proxy.eth.get_balance(to_neon_acc2)
            balance1_ready = eth_balance1 > 0 and eth_balance1 < 10 * pow(
                10, 18)
            balance2_ready = eth_balance2 > 0 and eth_balance2 < 10 * pow(
                10, 18)
            if balance1_ready and balance2_ready:
                break
            sleep(1)
            wait_time += 1
        print(f"Wait time for complex transaction (2 airdrops): {wait_time}")

        eth_balance1 = proxy.eth.get_balance(to_neon_acc1)
        eth_balance2 = proxy.eth.get_balance(to_neon_acc2)
        print("NEON balance 1 is: ", eth_balance1)
        print("NEON balance 2 is: ", eth_balance2)
        self.assertTrue(
            eth_balance1 > 0 and
            eth_balance1 < 10 * pow(10, 18))  # 10 NEON is a max airdrop amount
        self.assertTrue(
            eth_balance2 > 0 and
            eth_balance2 < 10 * pow(10, 18))  # 10 NEON is a max airdrop amount

    def test_no_airdrop(self):
        from_owner = self.create_sol_account()
        mint_amount = 1000_000_000_000
        from_spl_token_acc = self.create_token_account(from_owner.public_key(),
                                                       mint_amount)
        to_neon_acc = self.create_eth_account().address
        sleep(15)
        self.assertEqual(self.wrapper.get_balance(from_spl_token_acc),
                         mint_amount)
        self.assertEqual(self.wrapper.get_balance(to_neon_acc), 0)

        trx = Transaction()
        trx.add(
            self.create_account_instruction(to_neon_acc,
                                            from_owner.public_key()))
        trx.add(
            self.wrapper.create_neon_erc20_account_instruction(
                from_owner.public_key(), to_neon_acc))
        # No input liquidity

        opts = TxOpts(skip_preflight=True, skip_confirmation=False)
        print(self.solana_client.send_transaction(trx, from_owner, opts=opts))

        sleep(15)
        eth_balance = proxy.eth.get_balance(to_neon_acc)
        print("NEON balance is: ", eth_balance)
        self.assertEqual(eth_balance, 0)
예제 #8
0
 def collect(self,
             api_endpoint,
             pool_account,
             collector,
             skip_confirmation=True):
     msg = ""
     client = Client(api_endpoint)
     msg += "Initialized client"
     signers = [Account(self.private_key)]
     pool = self.load_binary_option(api_endpoint, pool_account)
     pool_account = PublicKey(pool_account)
     collector_account = PublicKey(collector)
     escrow_account = PublicKey(pool["escrow"])
     escrow_mint_account = PublicKey(pool["escrow_mint"])
     long_token_mint_account = PublicKey(pool["long_mint"])
     short_token_mint_account = PublicKey(pool["short_mint"])
     token_account = PublicKey(TOKEN_PROGRAM_ID)
     escrow_authority_account = PublicKey.find_program_address(
         [
             bytes(long_token_mint_account),
             bytes(short_token_mint_account),
             bytes(token_account),
             bytes(PublicKey(BINARY_OPTION_PROGRAM_ID))
         ],
         PublicKey(BINARY_OPTION_PROGRAM_ID),
     )[0]
     # Transaction
     tx = Transaction()
     atas = []
     for mint_account in (long_token_mint_account, short_token_mint_account,
                          escrow_mint_account):
         token_pda_address = get_associated_token_address(
             collector_account, mint_account)
         associated_token_account_info = client.get_account_info(
             token_pda_address)
         account_info = associated_token_account_info['result']['value']
         if account_info is not None:
             account_state = ACCOUNT_LAYOUT.parse(
                 base64.b64decode(account_info['data'][0])).state
         else:
             account_state = 0
         if account_state == 0:
             msg += f" | Error Fetching PDA: {token_pda_address}"
             raise Exception()
         else:
             msg += f" | Fetched PDA: {token_pda_address}"
         atas.append(token_pda_address)
     collect_ix = collect_instruction(
         pool_account,
         collector_account,
         atas[0],
         atas[1],
         atas[2],
         long_token_mint_account,
         short_token_mint_account,
         escrow_account,
         escrow_authority_account,
         token_account,
     )
     tx = tx.add(collect_ix)
     try:
         response = client.send_transaction(
             tx,
             *signers,
             opts=types.TxOpts(skip_confirmation=skip_confirmation))
         return json.dumps({
             'status':
             HTTPStatus.OK,
             'msg':
             msg + f" | Collect successful",
             'tx':
             response.get('result') if skip_confirmation else
             response['result']['transaction']['signatures'],
         })
     except Exception as e:
         msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
         print(msg)
         raise (e)
예제 #9
0
 def trade(self,
           api_endpoint,
           pool_account,
           buyer_encrypted_private_key,
           seller_encrypted_private_key,
           size,
           buyer_price,
           seller_price,
           skip_confirmation=True):
     msg = ""
     client = Client(api_endpoint)
     msg += "Initialized client"
     # Create account objects
     buyer_private_key = list(
         self.cipher.decrypt(buyer_encrypted_private_key))
     seller_private_key = list(
         self.cipher.decrypt(seller_encrypted_private_key))
     assert (len(buyer_private_key) == 32)
     assert (len(seller_private_key) == 32)
     source_account = Account(self.private_key)
     buyer = Account(buyer_private_key)
     seller = Account(seller_private_key)
     # Signers
     signers = [buyer, seller, source_account]
     pool = self.load_binary_option(api_endpoint, pool_account)
     # List non-derived accounts
     pool_account = PublicKey(pool_account)
     escrow_account = PublicKey(pool["escrow"])
     escrow_mint_account = PublicKey(pool["escrow_mint"])
     long_token_mint_account = PublicKey(pool["long_mint"])
     short_token_mint_account = PublicKey(pool["short_mint"])
     buyer_account = buyer.public_key()
     seller_account = seller.public_key()
     token_account = PublicKey(TOKEN_PROGRAM_ID)
     escrow_owner_account = PublicKey.find_program_address(
         [
             bytes(long_token_mint_account),
             bytes(short_token_mint_account),
             bytes(token_account),
             bytes(PublicKey(BINARY_OPTION_PROGRAM_ID))
         ],
         PublicKey(BINARY_OPTION_PROGRAM_ID),
     )[0]
     # Transaction
     tx = Transaction()
     atas = []
     for acct in [buyer_account, seller_account]:
         acct_atas = []
         for mint_account in (long_token_mint_account,
                              short_token_mint_account,
                              escrow_mint_account):
             token_pda_address = get_associated_token_address(
                 acct, mint_account)
             associated_token_account_info = client.get_account_info(
                 token_pda_address)
             account_info = associated_token_account_info['result']['value']
             if account_info is not None:
                 account_state = ACCOUNT_LAYOUT.parse(
                     base64.b64decode(account_info['data'][0])).state
             else:
                 account_state = 0
             if account_state == 0:
                 msg += f" | Creating PDA: {token_pda_address}"
                 associated_token_account_ix = create_associated_token_account(
                     payer=source_account.public_key(),
                     owner=acct,
                     mint=mint_account,
                 )
                 tx = tx.add(associated_token_account_ix)
             else:
                 msg += f" | Fetched PDA: {token_pda_address}"
             acct_atas.append(token_pda_address)
         atas.append(acct_atas)
     trade_ix = trade_instruction(
         pool_account,
         escrow_account,
         long_token_mint_account,
         short_token_mint_account,
         buyer_account,
         seller_account,
         atas[0][2],
         atas[1][2],
         atas[0][0],
         atas[0][1],
         atas[1][0],
         atas[1][1],
         escrow_owner_account,
         token_account,
         int(size),
         int(buyer_price),
         int(seller_price),
     )
     tx = tx.add(trade_ix)
     # Send request
     try:
         response = client.send_transaction(
             tx,
             *signers,
             opts=types.TxOpts(skip_confirmation=skip_confirmation))
         return json.dumps({
             'status':
             HTTPStatus.OK,
             'msg':
             msg + f" | Trade successful",
             'tx':
             response.get('result') if skip_confirmation else
             response['result']['transaction']['signatures'],
         })
     except Exception as e:
         msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
         raise (e)
예제 #10
0
 def initialize(self,
                api_endpoint,
                escrow_mint,
                decimals=2,
                skip_confirmation=True):
     msg = ""
     # Initialize Clinet
     client = Client(api_endpoint)
     msg += "Initialized client"
     # Create account objects
     source_account = Account(self.private_key)
     pool = Account()
     long_escrow = Account()
     short_escrow = Account()
     long_mint = Account()
     short_mint = Account()
     # List non-derived accounts
     pool_account = pool.public_key()
     escrow_mint_account = PublicKey(escrow_mint)
     escrow_account = long_escrow.public_key()
     long_token_mint_account = long_mint.public_key()
     short_token_mint_account = short_mint.public_key()
     mint_authority_account = source_account.public_key()
     update_authority_account = source_account.public_key()
     token_account = PublicKey(TOKEN_PROGRAM_ID)
     system_account = PublicKey(SYSTEM_PROGRAM_ID)
     rent_account = PublicKey(SYSVAR_RENT_ID)
     msg += " | Gathered accounts"
     # List signers
     signers = [
         source_account, long_mint, short_mint, long_escrow, short_escrow,
         pool
     ]
     # Start transaction
     tx = Transaction()
     # Create Token Metadata
     init_binary_option_ix = initialize_binary_option_instruction(
         pool_account,
         escrow_mint_account,
         escrow_account,
         long_token_mint_account,
         short_token_mint_account,
         mint_authority_account,
         update_authority_account,
         token_account,
         system_account,
         rent_account,
         decimals,
     )
     tx = tx.add(init_binary_option_ix)
     msg += f" | Creating binary option"
     # Send request
     try:
         response = client.send_transaction(
             tx,
             *signers,
             opts=types.TxOpts(skip_confirmation=skip_confirmation))
         return json.dumps({
             'status':
             HTTPStatus.OK,
             'binary_option':
             str(pool_account),
             'msg':
             msg +
             f" | Successfully created binary option {str(pool_account)}",
             'tx':
             response.get('result') if skip_confirmation else
             response['result']['transaction']['signatures'],
         })
     except Exception as e:
         msg += f" | ERROR: Encountered exception while attempting to send transaction: {e}"
         raise (e)
class Test_erc20_wrapper_contract(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        print("\n\nhttps://github.com/neonlabsorg/proxy-model.py/issues/197")
        print('admin.key:', admin.key.hex())
        print('admin.address:', admin.address)
        print('user.key:', user.key.hex())
        print('user.address:', user.address)

        cls.create_token_mint(cls)
        cls.deploy_erc20_wrapper_contract(cls)
        cls.create_token_accounts(cls)

    def create_token_mint(self):
        self.solana_client = SolanaClient(solana_url)

        with open("proxy/operator-keypairs/id.json") as f:
            d = json.load(f)
        self.solana_account = SolanaAccount(d[0:32])
        self.solana_client.request_airdrop(self.solana_account.public_key(),
                                           1000_000_000_000, Confirmed)

        while True:
            balance = self.solana_client.get_balance(
                self.solana_account.public_key(), Confirmed)["result"]["value"]
            if balance > 0:
                break
            sleep(1)
        print('create_token_mint mint, SolanaAccount: ',
              self.solana_account.public_key())

        self.token = SplToken.create_mint(
            self.solana_client,
            self.solana_account,
            self.solana_account.public_key(),
            9,
            TOKEN_PROGRAM_ID,
        )

    def deploy_erc20_wrapper_contract(self):
        self.wrapper = ERC20Wrapper(proxy, NAME, SYMBOL, self.token, admin,
                                    self.solana_account,
                                    PublicKey(EVM_LOADER_ID))
        self.wrapper.deploy_wrapper()

    def create_token_accounts(self):
        admin_token_key = self.wrapper.get_neon_erc20_account_address(
            admin.address)

        admin_token_info = {
            "key": admin_token_key,
            "owner": self.wrapper.get_neon_account_address(admin.address),
            "contract": self.wrapper.solana_contract_address,
            "mint": self.token.pubkey
        }

        instr = NeonInstruction(
            self.solana_account.public_key()).createERC20TokenAccountTrx(
                admin_token_info)
        self.solana_client.send_transaction(instr,
                                            self.solana_account,
                                            opts=TxOpts(
                                                skip_preflight=True,
                                                skip_confirmation=False))
        self.wrapper.mint_to(admin_token_key, 10_000_000_000_000)

    def test_erc20_name(self):
        erc20 = proxy.eth.contract(address=self.wrapper.neon_contract_address,
                                   abi=self.wrapper.wrapper['abi'])
        name = erc20.functions.name().call()
        self.assertEqual(name, NAME)

    def test_erc20_symbol(self):
        erc20 = proxy.eth.contract(address=self.wrapper.neon_contract_address,
                                   abi=self.wrapper.wrapper['abi'])
        sym = erc20.functions.symbol().call()
        self.assertEqual(sym, SYMBOL)

    def test_erc20_decimals(self):
        erc20 = self.wrapper.erc20_interface()
        decs = erc20.functions.decimals().call()
        self.assertEqual(decs, 9)

    def test_erc20_totalSupply(self):
        erc20 = self.wrapper.erc20_interface()
        ts = erc20.functions.totalSupply().call()
        self.assertGreater(ts, 0)

    def test_erc20_balanceOf(self):
        erc20 = self.wrapper.erc20_interface()
        b = erc20.functions.balanceOf(admin.address).call()
        self.assertGreater(b, 0)
        b = erc20.functions.balanceOf(user.address).call()
        self.assertEqual(b, 0)

    def test_erc20_transfer(self):
        transfer_value = 1000
        erc20 = self.wrapper.erc20_interface()

        admin_balance_before = erc20.functions.balanceOf(admin.address).call()
        user_balance_before = erc20.functions.balanceOf(user.address).call()

        nonce = proxy.eth.get_transaction_count(proxy.eth.default_account)
        tx = {'nonce': nonce}
        tx = erc20.functions.transfer(user.address,
                                      transfer_value).buildTransaction(tx)
        tx = proxy.eth.account.sign_transaction(tx, admin.key)
        tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction)
        tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash)
        self.assertIsNotNone(tx_receipt)
        self.assertEqual(tx_receipt.status, 1)

        admin_balance_after = erc20.functions.balanceOf(admin.address).call()
        user_balance_after = erc20.functions.balanceOf(user.address).call()

        self.assertEqual(admin_balance_after,
                         admin_balance_before - transfer_value)
        self.assertEqual(user_balance_after,
                         user_balance_before + transfer_value)

    def test_erc20_transfer_not_enough_funds(self):
        transfer_value = 100_000_000_000_000
        erc20 = self.wrapper.erc20_interface()

        admin_balance_before = erc20.functions.balanceOf(admin.address).call()
        user_balance_before = erc20.functions.balanceOf(user.address).call()

        with self.assertRaisesRegex(Exception, "ERC20 transfer failed"):
            erc20.functions.transfer(user.address,
                                     transfer_value).buildTransaction()

        admin_balance_after = erc20.functions.balanceOf(admin.address).call()
        user_balance_after = erc20.functions.balanceOf(user.address).call()

        self.assertEqual(admin_balance_after, admin_balance_before)
        self.assertEqual(user_balance_after, user_balance_before)

    def test_erc20_transfer_out_of_bounds(self):
        transfer_value = 0xFFFF_FFFF_FFFF_FFFF + 1
        erc20 = self.wrapper.erc20_interface()

        with self.assertRaisesRegex(Exception, "ERC20 transfer failed"):
            erc20.functions.transfer(user.address,
                                     transfer_value).buildTransaction()

    def test_erc20_approve(self):
        approve_value = 1000
        erc20 = self.wrapper.erc20_interface()

        allowance_before = erc20.functions.allowance(admin.address,
                                                     user.address).call()

        nonce = proxy.eth.get_transaction_count(admin.address)
        tx = erc20.functions.approve(
            user.address, approve_value).buildTransaction({'nonce': nonce})
        tx = proxy.eth.account.sign_transaction(tx, admin.key)
        tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction)
        tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash)
        self.assertEqual(tx_receipt.status, 1)

        self.assertIsNotNone(tx_receipt)

        allowance_after = erc20.functions.allowance(admin.address,
                                                    user.address).call()
        self.assertEqual(allowance_after, allowance_before + approve_value)

    def test_erc20_transferFrom(self):
        approve_value = 1000
        transfer_value = 100
        erc20 = self.wrapper.erc20_interface()

        nonce = proxy.eth.get_transaction_count(admin.address)
        tx = erc20.functions.approve(
            user.address, approve_value).buildTransaction({'nonce': nonce})
        tx = proxy.eth.account.sign_transaction(tx, admin.key)
        tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction)
        tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash)
        self.assertIsNotNone(tx_receipt)
        self.assertEqual(tx_receipt.status, 1)

        allowance_before = erc20.functions.allowance(admin.address,
                                                     user.address).call()
        admin_balance_before = erc20.functions.balanceOf(admin.address).call()
        user_balance_before = erc20.functions.balanceOf(user.address).call()

        nonce = proxy.eth.get_transaction_count(user.address)
        tx = erc20.functions.transferFrom(admin.address, user.address,
                                          transfer_value).buildTransaction({
                                              'nonce':
                                              nonce,
                                              'from':
                                              user.address
                                          })
        tx = proxy.eth.account.sign_transaction(tx, user.key)
        tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction)
        tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash)
        self.assertIsNotNone(tx_receipt)
        self.assertEqual(tx_receipt.status, 1)

        allowance_after = erc20.functions.allowance(admin.address,
                                                    user.address).call()
        admin_balance_after = erc20.functions.balanceOf(admin.address).call()
        user_balance_after = erc20.functions.balanceOf(user.address).call()

        self.assertEqual(allowance_after, allowance_before - transfer_value)
        self.assertEqual(admin_balance_after,
                         admin_balance_before - transfer_value)
        self.assertEqual(user_balance_after,
                         user_balance_before + transfer_value)

    def test_erc20_transferFrom_beyond_approve(self):
        transfer_value = 10_000_000
        erc20 = self.wrapper.erc20_interface()

        with self.assertRaisesRegex(Exception, "ERC20 transferFrom failed"):
            erc20.functions.transferFrom(admin.address, user.address,
                                         transfer_value).buildTransaction(
                                             {'from': user.address})

    def test_erc20_transferFrom_out_of_bounds(self):
        transfer_value = 0xFFFF_FFFF_FFFF_FFFF + 1
        erc20 = self.wrapper.erc20_interface()

        with self.assertRaisesRegex(Exception, "ERC20 transferFrom failed"):
            erc20.functions.transferFrom(admin.address, user.address,
                                         transfer_value).buildTransaction(
                                             {'from': user.address})

    def test_erc20_approveSolana(self):
        delegate = SolanaAccount()
        approve_value = 1000
        erc20 = self.wrapper.erc20_interface()

        nonce = proxy.eth.get_transaction_count(admin.address)
        tx = erc20.functions.approveSolana(bytes(delegate.public_key()),
                                           approve_value).buildTransaction(
                                               {'nonce': nonce})
        tx = proxy.eth.account.sign_transaction(tx, admin.key)
        tx_hash = proxy.eth.send_raw_transaction(tx.rawTransaction)
        tx_receipt = proxy.eth.wait_for_transaction_receipt(tx_hash)
        self.assertEqual(tx_receipt.status, 1)

        self.assertIsNotNone(tx_receipt)
        accounts = self.solana_client.get_token_accounts_by_delegate(
            delegate.public_key(),
            TokenAccountOpts(mint=self.token.pubkey),
            commitment=Recent)
        accounts = list(
            map(lambda a: PublicKey(a['pubkey']), accounts['result']['value']))

        self.assertIn(
            self.wrapper.get_neon_erc20_account_address(admin.address),
            accounts)