Skip to content

Commit 3bafc0b

Browse files
committed
chore: register aleo token adapters
1 parent ddf83c9 commit 3bafc0b

3 files changed

Lines changed: 209 additions & 10 deletions

File tree

typescript/aleo-sdk/src/clients/provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export class AleoProvider extends AleoBase implements AltVM.IProvider {
7171

7272
async getTotalSupply(req: AltVM.ReqGetTotalSupply): Promise<bigint> {
7373
if (!req.denom) {
74-
throw new Error(`Can not get total supply of credits`);
74+
return 0n;
7575
}
7676

7777
const result = await this.aleoClient.getProgramMappingValue(

typescript/sdk/src/token/Token.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ import {
2828
TokenStandard,
2929
XERC20_STANDARDS,
3030
} from './TokenStandard.js';
31+
import {
32+
AleoHypCollateralAdapter,
33+
AleoHypSyntheticAdapter,
34+
AleoNativeTokenAdapter,
35+
} from './adapters/AleoTokenAdapter.js';
3136
import {
3237
CwHypCollateralAdapter,
3338
CwHypNativeAdapter,
@@ -173,6 +178,10 @@ export class Token implements IToken {
173178
return new RadixNativeTokenAdapter(chainName, multiProvider, {
174179
token: addressOrDenom,
175180
});
181+
} else if (standard === TokenStandard.AleoNative) {
182+
return new AleoNativeTokenAdapter(chainName, multiProvider, {
183+
token: addressOrDenom,
184+
});
176185
} else if (this.isHypToken()) {
177186
return this.getHypAdapter(multiProvider);
178187
} else if (this.isIbcToken()) {
@@ -344,6 +353,14 @@ export class Token implements IToken {
344353
return new RadixHypSyntheticAdapter(chainName, multiProvider, {
345354
token: addressOrDenom,
346355
});
356+
} else if (standard === TokenStandard.AleoHypCollateral) {
357+
return new AleoHypCollateralAdapter(chainName, multiProvider, {
358+
token: addressOrDenom,
359+
});
360+
} else if (standard === TokenStandard.AleoHypSynthetic) {
361+
return new AleoHypSyntheticAdapter(chainName, multiProvider, {
362+
token: addressOrDenom,
363+
});
347364
} else if (standard === TokenStandard.EvmM0PortalLite) {
348365
assert(
349366
collateralAddressOrDenom,

typescript/sdk/src/token/adapters/AleoTokenAdapter.ts

Lines changed: 191 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
import { AleoProvider, AleoTransaction } from '@hyperlane-xyz/aleo-sdk';
2-
import { Address, Numberish, assert } from '@hyperlane-xyz/utils';
2+
import {
3+
Address,
4+
Domain,
5+
Numberish,
6+
addressToBytes32,
7+
assert,
8+
strip0x,
9+
} from '@hyperlane-xyz/utils';
310

411
import { BaseAleoAdapter } from '../../app/MultiProtocolApp.js';
512
import { MultiProtocolProvider } from '../../providers/MultiProtocolProvider.js';
613
import { ChainName } from '../../types.js';
714
import { TokenMetadata } from '../types.js';
815

9-
import { ITokenAdapter, TransferParams } from './ITokenAdapter.js';
16+
import {
17+
IHypTokenAdapter,
18+
ITokenAdapter,
19+
InterchainGasQuote,
20+
QuoteTransferRemoteParams,
21+
TransferParams,
22+
TransferRemoteParams,
23+
} from './ITokenAdapter.js';
1024

1125
export class AleoTokenAdapter
1226
extends BaseAleoAdapter
@@ -15,6 +29,10 @@ export class AleoTokenAdapter
1529
protected provider: AleoProvider;
1630
protected tokenAddress: string;
1731

32+
protected async getDenom(): Promise<string> {
33+
return this.tokenAddress;
34+
}
35+
1836
constructor(
1937
public readonly chainName: ChainName,
2038
public readonly multiProvider: MultiProtocolProvider,
@@ -27,20 +45,35 @@ export class AleoTokenAdapter
2745
}
2846

2947
async getBalance(address: Address): Promise<bigint> {
48+
const denom = await this.getDenom();
3049
return this.provider.getBalance({
3150
address,
51+
denom,
3252
});
3353
}
3454

3555
async getMetadata(): Promise<TokenMetadata> {
36-
const nativeToken = await this.provider.getToken({
56+
const { name, symbol, decimals } = await this.provider.getToken({
3757
tokenAddress: this.tokenAddress,
3858
});
3959

60+
assert(
61+
name !== undefined,
62+
`name on radix token ${this.tokenAddress} is undefined`,
63+
);
64+
assert(
65+
symbol !== undefined,
66+
`symbol on radix token ${this.tokenAddress} is undefined`,
67+
);
68+
assert(
69+
decimals !== undefined,
70+
`divisibility on radix token ${this.tokenAddress} is undefined`,
71+
);
72+
4073
return {
41-
name: nativeToken.name,
42-
symbol: nativeToken.symbol,
43-
decimals: nativeToken.decimals,
74+
name,
75+
symbol,
76+
decimals,
4477
};
4578
}
4679

@@ -70,18 +103,167 @@ export class AleoTokenAdapter
70103
async populateTransferTx(
71104
transferParams: TransferParams,
72105
): Promise<AleoTransaction> {
106+
const denom = await this.getDenom();
107+
73108
assert(transferParams.fromAccountOwner, `no sender in transfer params`);
74109

75110
return this.provider.getTransferTransaction({
76111
signer: transferParams.fromAccountOwner,
77112
recipient: transferParams.recipient,
78-
denom: '',
113+
denom,
79114
amount: transferParams.weiAmountOrId.toString(),
80115
});
81116
}
82117

83118
async getTotalSupply(): Promise<bigint | undefined> {
84-
// Not implemented, native tokens don't have an accessible total supply
85-
return undefined;
119+
const denom = await this.getDenom();
120+
return this.provider.getTotalSupply({
121+
denom,
122+
});
123+
}
124+
}
125+
126+
export class AleoNativeTokenAdapter
127+
extends AleoTokenAdapter
128+
implements ITokenAdapter<AleoTransaction>
129+
{
130+
override async getMetadata(): Promise<TokenMetadata> {
131+
const { nativeToken } = this.multiProvider.getChainMetadata(this.chainName);
132+
assert(
133+
nativeToken,
134+
`Native token data is required for ${AleoNativeTokenAdapter.name}`,
135+
);
136+
137+
return {
138+
name: nativeToken.name,
139+
symbol: nativeToken.symbol,
140+
decimals: nativeToken.decimals,
141+
};
86142
}
87143
}
144+
145+
export class AleoHypCollateralAdapter
146+
extends AleoTokenAdapter
147+
implements IHypTokenAdapter<AleoTransaction>
148+
{
149+
constructor(
150+
public readonly chainName: ChainName,
151+
public readonly multiProvider: MultiProtocolProvider,
152+
public readonly addresses: { token: Address },
153+
) {
154+
super(chainName, multiProvider, addresses);
155+
}
156+
157+
protected async getResourceAddress(): Promise<string> {
158+
const { denom } = await this.provider.getToken({
159+
tokenAddress: this.tokenAddress,
160+
});
161+
return denom;
162+
}
163+
164+
async getDomains(): Promise<Domain[]> {
165+
const { remoteRouters } = await this.provider.getRemoteRouters({
166+
tokenAddress: this.tokenAddress,
167+
});
168+
169+
return remoteRouters.map((router) => router.receiverDomainId);
170+
}
171+
172+
async getRouterAddress(domain: Domain): Promise<Buffer> {
173+
const { remoteRouters } = await this.provider.getRemoteRouters({
174+
tokenAddress: this.tokenAddress,
175+
});
176+
177+
const router = remoteRouters.find(
178+
(router) => router.receiverDomainId === domain,
179+
);
180+
181+
if (!router) {
182+
throw new Error(`Router with domain "${domain}" not found`);
183+
}
184+
185+
return Buffer.from(strip0x(router.receiverAddress), 'hex');
186+
}
187+
188+
async getAllRouters(): Promise<Array<{ domain: Domain; address: Buffer }>> {
189+
const { remoteRouters } = await this.provider.getRemoteRouters({
190+
tokenAddress: this.tokenAddress,
191+
});
192+
193+
return remoteRouters.map((router) => ({
194+
domain: router.receiverDomainId,
195+
address: Buffer.from(strip0x(router.receiverAddress), 'hex'),
196+
}));
197+
}
198+
199+
async getBridgedSupply(): Promise<bigint | undefined> {
200+
return this.provider.getBridgedSupply({
201+
tokenAddress: this.tokenAddress,
202+
});
203+
}
204+
205+
async quoteTransferRemoteGas({
206+
destination,
207+
}: QuoteTransferRemoteParams): Promise<InterchainGasQuote> {
208+
const { denom: addressOrDenom, amount } =
209+
await this.provider.quoteRemoteTransfer({
210+
tokenAddress: this.tokenAddress,
211+
destinationDomainId: destination,
212+
});
213+
214+
return {
215+
igpQuote: {
216+
addressOrDenom,
217+
amount,
218+
},
219+
};
220+
}
221+
222+
async populateTransferRemoteTx(
223+
params: TransferRemoteParams,
224+
): Promise<AleoTransaction> {
225+
assert(params.fromAccountOwner, `no sender in remote transfer params`);
226+
227+
if (!params.interchainGas) {
228+
params.interchainGas = await this.quoteTransferRemoteGas({
229+
destination: params.destination,
230+
});
231+
}
232+
233+
const { remoteRouters } = await this.provider.getRemoteRouters({
234+
tokenAddress: this.tokenAddress,
235+
});
236+
237+
const router = remoteRouters.find(
238+
(router) => router.receiverDomainId === params.destination,
239+
);
240+
241+
if (!router) {
242+
throw new Error(
243+
`Failed to find remote router for token id and destination: ${this.tokenAddress},${params.destination}`,
244+
);
245+
}
246+
247+
if (!params.interchainGas.igpQuote?.addressOrDenom) {
248+
throw new Error(
249+
`Require denom for max fee, didn't receive and denom in the interchainGas quote`,
250+
);
251+
}
252+
253+
return this.provider.getRemoteTransferTransaction({
254+
signer: params.fromAccountOwner!,
255+
tokenAddress: this.tokenAddress,
256+
destinationDomainId: params.destination,
257+
recipient: strip0x(addressToBytes32(params.recipient)),
258+
amount: params.weiAmountOrId.toString(),
259+
customHookAddress: params.customHook,
260+
gasLimit: router.gas,
261+
maxFee: {
262+
denom: params.interchainGas.igpQuote?.addressOrDenom,
263+
amount: params.interchainGas.igpQuote?.amount.toString(),
264+
},
265+
});
266+
}
267+
}
268+
269+
export class AleoHypSyntheticAdapter extends AleoHypCollateralAdapter {}

0 commit comments

Comments
 (0)