Esempio n. 1
0
    def test_create_without_account_holder_auth(self):
        keys = [priv.public_key for priv in generate_keys(3)]

        create_instructions, addr = self._generate_create(keys[0], keys[1], keys[2])
        create_assoc_instruction, assoc = token.create_associated_token_account(keys[0], keys[1], keys[2])
        txs = [
            solana.Transaction.new(
                keys[0],
                create_instructions[:3],
            ),
            solana.Transaction.new(
                keys[0],
                [
                    create_assoc_instruction,
                    token.set_authority(assoc, assoc, token.AuthorityType.CLOSE_ACCOUNT, new_authority=keys[0]),
                ]
            )
        ]

        for idx, tx in enumerate(txs):
            creations, payments = parse_transaction(tx)
            assert len(creations) == 1
            assert len(payments) == 0

            if idx == 0:
                # Randomly generated in _generate_create
                assert creations[0].owner
                assert creations[0].address == addr
            else:
                assert creations[0].owner == keys[1]
                assert creations[0].address == assoc
Esempio n. 2
0
    def _create_solana_account(
        self, private_key: PrivateKey, commitment: Commitment, subsidizer: Optional[PrivateKey] = None
    ):
        config = self._internal_client.get_service_config()
        if not config.subsidizer_account.value and not subsidizer:
            raise NoSubsidizerError()

        subsidizer_id = (subsidizer.public_key if subsidizer else
                         PublicKey(config.subsidizer_account.value))

        instructions = []
        if self._app_index > 0:
            m = AgoraMemo.new(1, TransactionType.NONE, self._app_index, b'')
            instructions.append(memo.memo_instruction(base64.b64encode(m.val).decode('utf-8')))

        create_instruction, addr = token.create_associated_token_account(
            subsidizer_id,
            private_key.public_key,
            PublicKey(config.token.value))
        instructions.append(create_instruction)
        instructions.append(token.set_authority(
            addr,
            private_key.public_key,
            token.AuthorityType.CLOSE_ACCOUNT,
            new_authority=subsidizer_id,
        ))
        transaction = solana.Transaction.new(subsidizer_id, instructions)

        recent_blockhash_resp = self._internal_client.get_recent_blockhash()
        transaction.set_blockhash(recent_blockhash_resp.blockhash.value)
        transaction.sign([private_key])
        if subsidizer:
            transaction.sign([subsidizer])

        self._internal_client.create_solana_account(transaction, commitment)
Esempio n. 3
0
    def test_from_json_invalid(self):
        with pytest.raises(ValueError) as e:
            CreateAccountRequest.from_json({})
        assert 'solana_transaction' in str(e)

        keys = [key.public_key for key in generate_keys(4)]
        tx = solana.Transaction.new(keys[0], [
            token.transfer(
                keys[1],
                keys[2],
                keys[3],
                20,
            ),
        ])

        with pytest.raises(ValueError) as e:
            CreateAccountRequest.from_json(
                {'solana_transaction': base64.b64encode(tx.marshal())})
        assert 'unexpected payments' in str(e)

        tx = solana.Transaction.new(keys[0], [])
        with pytest.raises(ValueError) as e:
            CreateAccountRequest.from_json(
                {'solana_transaction': base64.b64encode(tx.marshal())})
        assert 'expected exactly 1 creation' in str(e)

        create_assoc_instruction1, assoc1 = token.create_associated_token_account(
            keys[0], keys[1], keys[2])
        create_assoc_instruction2, assoc2 = token.create_associated_token_account(
            keys[0], keys[1], keys[2])
        tx = solana.Transaction.new(keys[0], [
            create_assoc_instruction1,
            token.set_authority(assoc1,
                                assoc1,
                                token.AuthorityType.CLOSE_ACCOUNT,
                                new_authority=keys[0]),
            create_assoc_instruction2,
            token.set_authority(assoc2,
                                assoc2,
                                token.AuthorityType.CLOSE_ACCOUNT,
                                new_authority=keys[0]),
        ])
        with pytest.raises(ValueError) as e:
            CreateAccountRequest.from_json(
                {'solana_transaction': base64.b64encode(tx.marshal())})
        assert 'expected exactly 1 creation' in str(e)
Esempio n. 4
0
def _generate_create_tx() -> Tuple[solana.Transaction, PublicKey, PublicKey]:
    keys = [key.public_key for key in generate_keys(2)]
    create_assoc_instruction, assoc = token.create_associated_token_account(
        _SIGNING_KEY.public_key, keys[0], keys[1])
    return solana.Transaction.new(_SIGNING_KEY.public_key, [
        create_assoc_instruction,
        token.set_authority(assoc,
                            assoc,
                            token.AuthorityType.CLOSE_ACCOUNT,
                            new_authority=_SIGNING_KEY.public_key),
    ]), keys[0], assoc
Esempio n. 5
0
    def _gen_create_tx():
        private_key = PrivateKey.random()
        create_instruction, addr = token.create_associated_token_account(
            _subsidizer, private_key.public_key, _token)

        return solana.Transaction.new(_subsidizer, [
            create_instruction,
            token.set_authority(
                addr,
                private_key.public_key,
                token.AuthorityType.CLOSE_ACCOUNT,
                new_authority=_subsidizer,
            )
        ])
Esempio n. 6
0
    def test_create_without_close_authority(self):
        keys = [priv.public_key for priv in generate_keys(3)]

        create_instructions, addr = self._generate_create(keys[0], keys[1], keys[2])
        create_assoc_instruction, assoc = token.create_associated_token_account(keys[0], keys[1], keys[2])
        txs = [
            solana.Transaction.new(
                keys[0],
                create_instructions[:2],
            ),
            solana.Transaction.new(
                keys[0],
                [
                    create_assoc_instruction,
                ],
            )
        ]

        for tx in txs:
            with pytest.raises(ValueError) as e:
                parse_transaction(tx)
            assert 'SetAuthority(Close)' in str(e)
Esempio n. 7
0
    def merge_token_accounts(
        self, private_key: PrivateKey, create_associated_account: bool, commitment: Optional[Commitment] = None,
        subsidizer: Optional[PrivateKey] = None,
    ) -> Optional[bytes]:
        commitment = commitment if commitment else self._default_commitment

        existing_accounts = self._internal_client.resolve_token_accounts(private_key.public_key, True)
        if len(existing_accounts) == 0 or (len(existing_accounts) == 1 and not create_associated_account):
            return None

        dest = existing_accounts[0].account_id
        instructions = []
        signers = [private_key]

        config = self._internal_client.get_service_config()
        if not config.subsidizer_account.value and not subsidizer:
            raise NoSubsidizerError()

        if subsidizer:
            subsidizer_id = subsidizer.public_key
            signers.append(subsidizer)
        else:
            subsidizer_id = PublicKey(config.subsidizer_account.value)

        if create_associated_account:
            create_instruction, assoc = token.create_associated_token_account(
                subsidizer_id,
                private_key.public_key,
                PublicKey(config.token.value),
            )
            if existing_accounts[0].account_id.raw != assoc.raw:
                instructions.append(create_instruction)
                instructions.append(token.set_authority(
                    assoc,
                    private_key.public_key,
                    token.AuthorityType.CLOSE_ACCOUNT,
                    new_authority=subsidizer_id))
                dest = assoc
            elif len(existing_accounts) == 1:
                return None

        for existing_account in existing_accounts:
            if existing_account.account_id == dest:
                continue

            instructions.append(token.transfer(
                existing_account.account_id,
                dest,
                private_key.public_key,
                existing_account.balance,
            ))

            # If no close authority is set, it likely means we don't know it, and can't make any assumptions
            if not existing_account.close_authority:
                continue

            # If the subsidizer is the close authority, we can include the close instruction as they will be ok with
            # signing for it
            #
            # Alternatively, if we're the close authority, we are signing it.
            should_close = False
            for a in [private_key.public_key, subsidizer_id]:
                if existing_account.close_authority == a:
                    should_close = True
                    break

            if should_close:
                instructions.append(token.close_account(
                    existing_account.account_id,
                    existing_account.close_authority,
                    existing_account.close_authority,
                ))

        transaction = solana.Transaction.new(subsidizer_id, instructions)

        result = self._sign_and_submit_solana_tx(signers, transaction, commitment)
        if result.errors and result.errors.tx_error:
            raise result.errors.tx_error

        return result.tx_id