Skip to content

Commit c0ed83d

Browse files
committed
add tx based v2 auth
1 parent 1a4614e commit c0ed83d

File tree

7 files changed

+147
-10
lines changed

7 files changed

+147
-10
lines changed
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,32 @@ import {
44
Authenticator,
55
Ed25519TokenBodyParser,
66
TokenParser,
7+
TokenSigner,
78
} from '@dialectlabs/sdk';
89

9-
import { SolanaSignMessageV2TokenValidator } from './solana-sign-message-v2-token-validator';
1010
import { SolanaSignMessageV2TokenGenerator } from './solana-sign-message-v2-token-generator';
11-
import type { SolanaEd25519TokenSigner } from '../ed25519/solana-ed25519-token-signer';
11+
import { SolanaV2TokenValidator } from '../solana-v2-token-validator';
1212

1313
export class SolanaSignMessageV2AuthenticationFacadeFactory extends AuthenticationFacadeFactory {
1414
constructor(
15-
private readonly tokenSigner: SolanaEd25519TokenSigner,
15+
private readonly tokenSigner: TokenSigner,
1616
private readonly baseUrl: string,
1717
) {
1818
super();
1919
}
2020

21-
static createAuthenticator(baseUrl: string): Authenticator {
21+
static createAuthenticator(): Authenticator {
2222
return new Authenticator(
2323
new TokenParser(new Ed25519TokenBodyParser()),
24-
new SolanaSignMessageV2TokenValidator(baseUrl),
24+
new SolanaV2TokenValidator(),
2525
);
2626
}
2727

2828
get(): AuthenticationFacade {
2929
return new AuthenticationFacade(
3030
this.tokenSigner,
3131
new SolanaSignMessageV2TokenGenerator(this.tokenSigner, this.baseUrl),
32-
SolanaSignMessageV2AuthenticationFacadeFactory.createAuthenticator(
33-
this.baseUrl,
34-
),
32+
SolanaSignMessageV2AuthenticationFacadeFactory.createAuthenticator(),
3533
);
3634
}
3735
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {
2+
AuthenticationFacade,
3+
AuthenticationFacadeFactory,
4+
Authenticator,
5+
Ed25519TokenBodyParser,
6+
TokenParser,
7+
} from '@dialectlabs/sdk';
8+
9+
import { SolanaSignTxV2TokenGenerator } from './solana-sign-tx-v2-token-generator';
10+
import { SolanaV2TokenValidator } from '../solana-v2-token-validator';
11+
import type { SolanaEd25519TokenSigner } from '../../ed25519/solana-ed25519-token-signer';
12+
13+
export class SolanaSignTxV2AuthenticationFacadeFactory extends AuthenticationFacadeFactory {
14+
constructor(
15+
private readonly tokenSigner: SolanaEd25519TokenSigner,
16+
private readonly baseUrl: string,
17+
) {
18+
super();
19+
}
20+
21+
static createAuthenticator(): Authenticator {
22+
return new Authenticator(
23+
new TokenParser(new Ed25519TokenBodyParser()),
24+
new SolanaV2TokenValidator(),
25+
);
26+
}
27+
28+
get(): AuthenticationFacade {
29+
return new AuthenticationFacade(
30+
this.tokenSigner,
31+
new SolanaSignTxV2TokenGenerator(this.tokenSigner, this.baseUrl),
32+
SolanaSignTxV2AuthenticationFacadeFactory.createAuthenticator(),
33+
);
34+
}
35+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
bytesFromBase64,
3+
jsonParseFromBase64,
4+
type Token,
5+
TokenGenerator,
6+
type TokenSigner,
7+
} from '@dialectlabs/sdk';
8+
import axios from 'axios';
9+
10+
export class SolanaSignTxV2TokenGenerator extends TokenGenerator {
11+
constructor(signer: TokenSigner, private readonly v2BaseUrl: string) {
12+
super(signer);
13+
}
14+
15+
override async generate(): Promise<Token> {
16+
const prepareResponse = await axios.post<{ transaction: string }>(
17+
`${this.v2BaseUrl}/v2/auth/solana-tx/prepare`,
18+
{ walletAddress: this.signer.subject },
19+
);
20+
21+
const transactionBase64 = prepareResponse.data.transaction;
22+
23+
const { signature } = await this.signer.sign(
24+
Buffer.from(transactionBase64, 'base64'),
25+
);
26+
27+
const tokenResponse = await axios.post<{ token: string }>(
28+
`${this.v2BaseUrl}/v2/auth/solana-tx/verify`,
29+
{
30+
transaction: Buffer.from(signature).toString('base64'),
31+
},
32+
);
33+
34+
const tokenStr = tokenResponse.data.token;
35+
36+
const [base64Header, base64Body, base64Signature] = tokenStr.split('.');
37+
if (!base64Header || !base64Body || !base64Signature) {
38+
throw new Error('Invalid token format from backend');
39+
}
40+
41+
return {
42+
rawValue: tokenStr,
43+
header: jsonParseFromBase64(base64Header),
44+
body: jsonParseFromBase64(base64Body),
45+
signature: bytesFromBase64(base64Signature),
46+
base64Header,
47+
base64Body,
48+
base64Signature,
49+
};
50+
}
51+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { DialectSolanaWalletAdapterWrapper } from '../../../wallet-adapter/dialect-solana-wallet-adapter-wrapper';
2+
import type {
3+
AccountAddress,
4+
PublicKey,
5+
TokenSigner,
6+
TokenSignerResult,
7+
} from '@dialectlabs/sdk';
8+
import { DIALECT_BLOCKCHAIN_SDK_TYPE_SOLANA } from '../../../sdk/constants';
9+
import { VersionedTransaction } from '@solana/web3.js';
10+
11+
export const SOLANA_TX_TOKEN_SIGNER_ALG = `${DIALECT_BLOCKCHAIN_SDK_TYPE_SOLANA}-v2-tx`;
12+
13+
export abstract class SolanaTxSigner implements TokenSigner {
14+
readonly alg = SOLANA_TX_TOKEN_SIGNER_ALG;
15+
16+
abstract subject: AccountAddress;
17+
abstract subjectPublicKey: PublicKey;
18+
19+
abstract sign(payload: Uint8Array): Promise<TokenSignerResult>;
20+
}
21+
22+
export class DialectWalletAdapterSolanaTxSigner extends SolanaTxSigner {
23+
constructor(
24+
readonly dialectWalletAdapter: DialectSolanaWalletAdapterWrapper,
25+
) {
26+
super();
27+
}
28+
29+
get subject(): AccountAddress {
30+
return this.dialectWalletAdapter.publicKey.toBase58();
31+
}
32+
33+
get subjectPublicKey(): PublicKey {
34+
return this.dialectWalletAdapter.publicKey;
35+
}
36+
37+
async sign(payload: Uint8Array): Promise<TokenSignerResult> {
38+
const tx = VersionedTransaction.deserialize(payload);
39+
const signedTx = await this.dialectWalletAdapter.signTransaction(tx);
40+
41+
return {
42+
payload,
43+
signature: signedTx.serialize(),
44+
};
45+
}
46+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { TokenHeader } from '@dialectlabs/sdk';
22
import { TokenValidator } from '@dialectlabs/sdk';
33

4-
export class SolanaSignMessageV2TokenValidator extends TokenValidator {
4+
export class SolanaV2TokenValidator extends TokenValidator {
55
constructor() {
66
super();
77
}

packages/blockchain-sdk-solana/src/sdk/sdk.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import { SolanaEd25519AuthenticationFacadeFactory } from '../auth/ed25519/solana
1212
import { DialectWalletAdapterSolanaEd25519TokenSigner } from '../auth/ed25519/solana-ed25519-token-signer';
1313
import { SolanaTxAuthenticationFacadeFactory } from '../auth/tx/solana-tx-authentication-facade-factory';
1414
import { DialectWalletAdapterSolanaTxTokenSigner } from '../auth/tx/solana-tx-token-signer';
15-
import { SolanaSignMessageV2AuthenticationFacadeFactory } from '../auth/sign-message-v2/solana-sign-message-v2-authentication-facade-factory';
15+
import { SolanaSignMessageV2AuthenticationFacadeFactory } from '../auth/v2/sign-message/solana-sign-message-v2-authentication-facade-factory';
1616
import { DIALECT_BLOCKCHAIN_SDK_TYPE_SOLANA } from './constants';
17+
import { SolanaSignTxV2AuthenticationFacadeFactory } from '../auth/v2/sign-tx/solana-sign-tx-v2-authentication-facade-factory';
1718

1819
export interface SolanaConfigProps {
1920
wallet: DialectSolanaWalletAdapter;
@@ -108,6 +109,12 @@ Solana settings:
108109
config.dialectCloud.v2Url,
109110
);
110111
}
112+
if (solanaConfig.wallet.canSignTransaction()) {
113+
return new SolanaSignTxV2AuthenticationFacadeFactory(
114+
new DialectWalletAdapterSolanaTxTokenSigner(solanaConfig.wallet),
115+
config.dialectCloud.v2Url,
116+
);
117+
}
111118
}
112119
throw new IllegalArgumentError('Unsupported authentication');
113120
}

0 commit comments

Comments
 (0)