Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.67% covered (success)
91.67%
33 / 36
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
SPLTokenActions
91.67% covered (success)
91.67%
33 / 36
0.00% covered (danger)
0.00%
0 / 1
8.04
0.00% covered (danger)
0.00%
0 / 1
 getOrCreateAssociatedTokenAccount
91.67% covered (success)
91.67%
33 / 36
0.00% covered (danger)
0.00%
0 / 1
8.04
1<?php
2
3namespace Attestto\SolanaPhpSdk\Programs\SplToken\Actions;
4
5use Attestto\SolanaPhpSdk\Connection;
6use Attestto\SolanaPhpSdk\Exceptions\AccountNotFoundException;
7use Attestto\SolanaPhpSdk\Exceptions\GenericException;
8use Attestto\SolanaPhpSdk\Exceptions\InputValidationException;
9use Attestto\SolanaPhpSdk\Exceptions\InvalidIdResponseException;
10use Attestto\SolanaPhpSdk\Exceptions\MethodNotFoundException;
11use Attestto\SolanaPhpSdk\Exceptions\TokenInvalidAccountOwnerError;
12use Attestto\SolanaPhpSdk\Exceptions\TokenInvalidMintError;
13use Attestto\SolanaPhpSdk\Exceptions\TokenOwnerOffCurveError;
14use Attestto\SolanaPhpSdk\Keypair;
15use Attestto\SolanaPhpSdk\Programs\SplToken\State\Account;
16use Attestto\SolanaPhpSdk\PublicKey;
17use Attestto\SolanaPhpSdk\Transaction;
18use Attestto\SolanaPhpSdk\Util\Commitment;
19use Attestto\SolanaPhpSdk\Util\ConfirmOptions;
20use Attestto\SolanaPhpSdk\Util\Signer;
21use Exception;
22use Psr\Http\Client\ClientExceptionInterface;
23use function Attestto\SolanaPhpSdk\Programs\SplToken\getAccount;
24
25trait SPLTokenActions {
26
27    /**
28     * @param Connection $connection
29     * @param Signer|Keypair $payer
30     * @param PublicKey $mint
31     * @param PublicKey $owner
32     * @param boolean $allowOwnerOffCurve
33     * @param Commitment|null $commitment
34     * @param ConfirmOptions $confirmOptions
35     * @param PublicKey $programId
36     * @param PublicKey $associatedTokenProgramId
37     * @return mixed
38     * @throws AccountNotFoundException
39     * @throws ClientExceptionInterface
40     * @throws InputValidationException
41     * @throws TokenInvalidAccountOwnerError
42     * @throws TokenInvalidMintError
43     * @throws TokenOwnerOffCurveError
44     * @throws GenericException
45     * @throws InvalidIdResponseException
46     * @throws MethodNotFoundException
47     * @throws \SodiumException
48     */
49    public function getOrCreateAssociatedTokenAccount(
50        Connection     $connection,
51        mixed          $payer,
52        PublicKey      $mint,
53        PublicKey      $owner,
54        bool           $allowOwnerOffCurve = true,
55        Commitment     $commitment = null,
56        ConfirmOptions $confirmOptions = null,
57        PublicKey      $programId = new PublicKey(self::TOKEN_PROGRAM_ID),
58        PublicKey      $associatedTokenProgramId = new PublicKey(self::ASSOCIATED_TOKEN_PROGRAM_ID)
59    ): Account
60    {
61
62        $associatedToken = $this->getAssociatedTokenAddressSync(
63            $mint,
64            $owner,
65            $allowOwnerOffCurve,
66            $programId,
67            $associatedTokenProgramId
68        );
69        $ata = $associatedToken->toBase58();
70        try {
71            $account = Account::getAccount($connection, $associatedToken, $commitment, $programId);
72        } catch (Exception $error) {
73            if ($error instanceof AccountNotFoundException || $error instanceof TokenInvalidAccountOwnerError) {
74                try {
75                    $transaction = new Transaction();
76                    $transaction->add(
77                        $this->createAssociatedTokenAccountInstruction(
78                            $payer->getPublicKey(),
79                            $associatedToken,
80                            $owner,
81                            $mint,
82                            $programId,
83                            $associatedTokenProgramId
84                        )
85                    );
86                    if (!$confirmOptions) $confirmOptions = new ConfirmOptions();
87                    $transaction->feePayer = $payer->getPublicKey();
88                    $txnHash = $connection->sendTransaction( $transaction, [$payer]);
89                } catch (Exception $error) {
90                    // Ignore all errors
91                    // Account Exists but is not funded
92                    throw $error;
93                }
94
95                $account = Account::getAccount($connection, $associatedToken, $commitment, $programId);
96            } else {
97                throw $error;
98            }
99        }
100
101        if ($account->mint != $mint) throw new TokenInvalidMintError(
102            $account->mint->toBase58() . ' != ' . $mint->toBase58()
103        );
104        if ($account->owner != $owner) throw new TokenInvalidAccountOwnerError(
105            $account->owner->toBase58() . ' != ' . $owner->toBase58()
106        );
107
108        return $account;
109    }
110
111
112
113
114
115}