def msg_deployed(self, message): print('msg_deployed method of the solana spl token') if self.contract.state != 'WAITING_FOR_DEPLOYMENT': take_off_blocking(self.contract.network.name) return else: conn = SolanaInt(self.contract.network.name).connect() key = Keypair.from_secret_key(bytes(SOLANA_KEYPAIR[0:32])) token_address = PublicKey(self.solana_contract.address) tok_int = Token(conn, token_address, TOKEN_PROGRAM_ID, key) holders = self.contract.tokenholder_set.all() if holders: print('transfering premint tokens') for th in holders: holder_addr = PublicKey(th.address) try: associated_address = tok_int.create_associated_token_account(holder_addr) print(f'created associated account {associated_address}') except RPCException: print('associated token account already created') associated_address = get_associated_token_address(holder_addr, tok_int.pubkey) response = tok_int.mint_to(associated_address, key, int(th.amount)) print(f'tx_hash = {response["result"]}') print('transferring of mint authority started') owner = PublicKey(self.admin_address) address = self.solana_contract.address tok_int.set_authority(address, key.public_key, 0, owner) print('successfully transferred mint authority') self.initialized({})
def sol_instr_partial_call_or_continue(self, storage_account, step_count, evm_instruction): return TransactionInstruction( program_id=self.loader.loader_id, data=bytearray.fromhex("0D") + self.collateral_pool_index_buf + step_count.to_bytes(8, byteorder='little') + evm_instruction, keys=[ AccountMeta(pubkey=storage_account, is_signer=False, is_writable=True), # System instructions account: AccountMeta(pubkey=PublicKey(SYSVAR_INSTRUCTION_PUBKEY), is_signer=False, is_writable=False), # Operator address: AccountMeta(pubkey=self.acc.public_key(), is_signer=True, is_writable=True), # Collateral pool address: AccountMeta(pubkey=self.collateral_pool_address, is_signer=False, is_writable=True), # Operator's NEON token account: AccountMeta(pubkey=get_associated_token_address(self.acc.public_key(), ETH_TOKEN_MINT_ID), is_signer=False, is_writable=True), # User's NEON token account: AccountMeta(pubkey=self.caller_token, is_signer=False, is_writable=True), # System program account: AccountMeta(pubkey=PublicKey(SYS_PROGRAM_ID), is_signer=False, is_writable=False), AccountMeta(pubkey=self.reId, is_signer=False, is_writable=True), AccountMeta(pubkey=self.re_code, is_signer=False, is_writable=True), AccountMeta(pubkey=self.caller, is_signer=False, is_writable=True), AccountMeta(pubkey=self.caller_token, is_signer=False, is_writable=True), AccountMeta(pubkey=self.loader.loader_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), ])
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 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)
def __init__(self): # Initialize user account self.signer = get_solana_accounts()[0] self.solana = SolanaInteractor(SOLANA_URL) self.waiter = None self._operator = self.signer.public_key() self.operator_token = get_associated_token_address( PublicKey(self._operator), ETH_TOKEN_MINT_ID) self.builder = NeonInstruction(self._operator)
def get_accounts(self, ether): (sol_address, _) = self.loader.ether2program(ether) info = client.get_account_info(sol_address, commitment=Confirmed)['result']['value'] data = base64.b64decode(info['data'][0]) acc_info = ACCOUNT_INFO_LAYOUT.parse(data) code_address = PublicKey(acc_info.code_account) alternate_token = get_associated_token_address(PublicKey(sol_address), ETH_TOKEN_MINT_ID) return (sol_address, alternate_token, code_address)
async def test_deposit_withdraw_sol(async_client, payer): fee = Fee(numerator=1, denominator=1000) referral_fee = 20 (stake_pool_address, validator_list_address) = await create_all(async_client, payer, fee, referral_fee) resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) deposit_amount = 100_000_000 await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) assert pool_token_balance['result']['value']['amount'] == str(deposit_amount) recipient = Keypair() await withdraw_sol(async_client, payer, token_account, stake_pool_address, recipient.public_key, deposit_amount) pool_token_balance = await async_client.get_token_account_balance(token_account, Confirmed) assert pool_token_balance['result']['value']['amount'] == str('0')
async def test_deposit_withdraw_stake(async_client, validators, payer, stake_pool_addresses, waiter): (stake_pool_address, validator_list_address) = stake_pool_addresses resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) validator = next(iter(validators)) stake_amount = 1_000_000 stake = Keypair() await create_stake(async_client, payer, stake, payer.public_key, stake_amount) stake = stake.public_key await delegate_stake(async_client, payer, payer, stake, validator) resp = await async_client.get_account_info(stake, commitment=Confirmed) data = resp['result']['value']['data'] stake_state = StakeState.decode(data[0], data[1]) print(stake_state) await waiter.wait_for_next_epoch(async_client) await update_stake_pool(async_client, payer, stake_pool_address) token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) await deposit_stake(async_client, payer, stake_pool_address, validator, stake, token_account) pool_token_balance = await async_client.get_token_account_balance( token_account, Confirmed) pool_token_balance = pool_token_balance['result']['value']['amount'] resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) stake_rent_exemption = resp['result'] assert pool_token_balance == str(stake_amount + stake_rent_exemption) destination_stake = Keypair() await withdraw_stake(async_client, payer, payer, destination_stake, stake_pool_address, validator, payer.public_key, token_account, stake_amount) pool_token_balance = await async_client.get_token_account_balance( token_account, Confirmed) pool_token_balance = pool_token_balance['result']['value']['amount'] assert pool_token_balance == str(stake_rent_exemption)
async def test_rebalance_this_is_very_slow(async_client, validators, payer, stake_pool_addresses, waiter): (stake_pool_address, validator_list_address) = stake_pool_addresses resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) stake_rent_exemption = resp['result'] increase_amount = 100_000_000 deposit_amount = (increase_amount + stake_rent_exemption) * len(validators) resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) # Test case 1: Increase await rebalance(ENDPOINT, stake_pool_address, payer, 0.0) # should only have minimum left resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) assert resp['result']['value']['lamports'] == stake_rent_exemption + 1 # should all be the same resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.active_stake_lamports == 0 assert validator.transient_stake_lamports == increase_amount + stake_rent_exemption # Test case 2: Decrease print('Waiting for next epoch') await waiter.wait_for_next_epoch(async_client) await rebalance(ENDPOINT, stake_pool_address, payer, deposit_amount / 1_000_000_000) # should still only have minimum left + rent exemptions from increase resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) reserve_lamports = resp['result']['value']['lamports'] assert reserve_lamports == stake_rent_exemption * ( 1 + len(validator_list.validators)) + 1 # should all be decreasing now resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.active_stake_lamports == 0 assert validator.transient_stake_lamports == increase_amount # Test case 3: Do nothing print('Waiting for next epoch') await waiter.wait_for_next_epoch(async_client) await rebalance(ENDPOINT, stake_pool_address, payer, deposit_amount / 1_000_000_000) # should still only have minimum left + rent exemptions from increase resp = await async_client.get_account_info(stake_pool.reserve_stake, commitment=Confirmed) reserve_lamports = resp['result']['value']['lamports'] assert reserve_lamports == stake_rent_exemption + deposit_amount + 1 # should all be decreasing now resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.active_stake_lamports == 0 assert validator.transient_stake_lamports == 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)
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)
def getTokenAddr(account): return get_associated_token_address(PublicKey(account), ETH_TOKEN_MINT_ID)
async def test_increase_decrease_this_is_very_slow(async_client, validators, payer, stake_pool_addresses, waiter): (stake_pool_address, validator_list_address) = stake_pool_addresses resp = await async_client.get_minimum_balance_for_rent_exemption(STAKE_LEN) stake_rent_exemption = resp['result'] increase_amount = 100_000_000 decrease_amount = increase_amount // 2 deposit_amount = (increase_amount + stake_rent_exemption) * len(validators) resp = await async_client.get_account_info(stake_pool_address, commitment=Confirmed) data = resp['result']['value']['data'] stake_pool = StakePool.decode(data[0], data[1]) token_account = get_associated_token_address(payer.public_key, stake_pool.pool_mint) await deposit_sol(async_client, payer, stake_pool_address, token_account, deposit_amount) # increase to all futures = [ increase_validator_stake(async_client, payer, payer, stake_pool_address, validator, increase_amount) for validator in validators ] await asyncio.gather(*futures) resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.transient_stake_lamports == increase_amount + stake_rent_exemption assert validator.active_stake_lamports == 0 print("Waiting for epoch to roll over") await waiter.wait_for_next_epoch(async_client) await update_stake_pool(async_client, payer, stake_pool_address) resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.last_update_epoch != 0 assert validator.transient_stake_lamports == 0 assert validator.active_stake_lamports == increase_amount # rent exemption brought back to reserve # decrease from all futures = [ decrease_validator_stake(async_client, payer, payer, stake_pool_address, validator, decrease_amount) for validator in validators ] await asyncio.gather(*futures) resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.transient_stake_lamports == decrease_amount assert validator.active_stake_lamports == increase_amount - decrease_amount print("Waiting for epoch to roll over") await waiter.wait_for_next_epoch(async_client) await update_stake_pool(async_client, payer, stake_pool_address) resp = await async_client.get_account_info(validator_list_address, commitment=Confirmed) data = resp['result']['value']['data'] validator_list = ValidatorList.decode(data[0], data[1]) for validator in validator_list.validators: assert validator.transient_stake_lamports == 0 assert validator.active_stake_lamports == increase_amount - decrease_amount
def get_token_account_address(self, ether_addr: Union[str, EthereumAddress]): sol_addr = PublicKey(ether2program(ether_addr)[0]) return get_associated_token_address(sol_addr, self.token_mint)