Skip to content

Commit 80e6b16

Browse files
committed
rate limits
1 parent a69d8ad commit 80e6b16

File tree

9 files changed

+284
-173
lines changed

9 files changed

+284
-173
lines changed

evm/ts/src/ethers-contracts/multiTokenNtt/1_1_0/MultiTokenNtt.sol/MultiTokenNtt.ts

+36
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ export interface MultiTokenNttInterface extends Interface {
121121
| "initialize"
122122
| "isPaused"
123123
| "migrate"
124+
| "overrideLocalAsset"
124125
| "owner"
125126
| "pauser"
126127
| "rateLimitDuration"
@@ -129,6 +130,7 @@ export interface MultiTokenNttInterface extends Interface {
129130
| "setOutboundLimit"
130131
| "setPeer"
131132
| "tokenImplementation"
133+
| "tokenProxyCreationCode"
132134
| "transfer(address,uint256,uint16,uint256,bytes32,bytes32,bool,bytes)"
133135
| "transfer(address,uint256,uint16,uint256,bytes32)"
134136
| "transferETH(uint256,uint16,uint256,bytes32)"
@@ -224,6 +226,10 @@ export interface MultiTokenNttInterface extends Interface {
224226
): string;
225227
encodeFunctionData(functionFragment: "isPaused", values?: undefined): string;
226228
encodeFunctionData(functionFragment: "migrate", values?: undefined): string;
229+
encodeFunctionData(
230+
functionFragment: "overrideLocalAsset",
231+
values: [TokenIdStruct, AddressLike]
232+
): string;
227233
encodeFunctionData(functionFragment: "owner", values?: undefined): string;
228234
encodeFunctionData(functionFragment: "pauser", values?: undefined): string;
229235
encodeFunctionData(
@@ -250,6 +256,10 @@ export interface MultiTokenNttInterface extends Interface {
250256
functionFragment: "tokenImplementation",
251257
values?: undefined
252258
): string;
259+
encodeFunctionData(
260+
functionFragment: "tokenProxyCreationCode",
261+
values?: undefined
262+
): string;
253263
encodeFunctionData(
254264
functionFragment: "transfer(address,uint256,uint16,uint256,bytes32,bytes32,bool,bytes)",
255265
values: [
@@ -348,6 +358,10 @@ export interface MultiTokenNttInterface extends Interface {
348358
decodeFunctionResult(functionFragment: "initialize", data: BytesLike): Result;
349359
decodeFunctionResult(functionFragment: "isPaused", data: BytesLike): Result;
350360
decodeFunctionResult(functionFragment: "migrate", data: BytesLike): Result;
361+
decodeFunctionResult(
362+
functionFragment: "overrideLocalAsset",
363+
data: BytesLike
364+
): Result;
351365
decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result;
352366
decodeFunctionResult(functionFragment: "pauser", data: BytesLike): Result;
353367
decodeFunctionResult(
@@ -371,6 +385,10 @@ export interface MultiTokenNttInterface extends Interface {
371385
functionFragment: "tokenImplementation",
372386
data: BytesLike
373387
): Result;
388+
decodeFunctionResult(
389+
functionFragment: "tokenProxyCreationCode",
390+
data: BytesLike
391+
): Result;
374392
decodeFunctionResult(
375393
functionFragment: "transfer(address,uint256,uint16,uint256,bytes32,bytes32,bool,bytes)",
376394
data: BytesLike
@@ -764,6 +782,12 @@ export interface MultiTokenNtt extends BaseContract {
764782

765783
migrate: TypedContractMethod<[], [void], "nonpayable">;
766784

785+
overrideLocalAsset: TypedContractMethod<
786+
[token: TokenIdStruct, localToken: AddressLike],
787+
[void],
788+
"nonpayable"
789+
>;
790+
767791
owner: TypedContractMethod<[], [string], "view">;
768792

769793
pauser: TypedContractMethod<[], [string], "view">;
@@ -796,6 +820,8 @@ export interface MultiTokenNtt extends BaseContract {
796820

797821
tokenImplementation: TypedContractMethod<[], [string], "view">;
798822

823+
tokenProxyCreationCode: TypedContractMethod<[], [string], "view">;
824+
799825
"transfer(address,uint256,uint16,uint256,bytes32,bytes32,bool,bytes)": TypedContractMethod<
800826
[
801827
token: AddressLike,
@@ -959,6 +985,13 @@ export interface MultiTokenNtt extends BaseContract {
959985
getFunction(
960986
nameOrSignature: "migrate"
961987
): TypedContractMethod<[], [void], "nonpayable">;
988+
getFunction(
989+
nameOrSignature: "overrideLocalAsset"
990+
): TypedContractMethod<
991+
[token: TokenIdStruct, localToken: AddressLike],
992+
[void],
993+
"nonpayable"
994+
>;
962995
getFunction(
963996
nameOrSignature: "owner"
964997
): TypedContractMethod<[], [string], "view">;
@@ -999,6 +1032,9 @@ export interface MultiTokenNtt extends BaseContract {
9991032
getFunction(
10001033
nameOrSignature: "tokenImplementation"
10011034
): TypedContractMethod<[], [string], "view">;
1035+
getFunction(
1036+
nameOrSignature: "tokenProxyCreationCode"
1037+
): TypedContractMethod<[], [string], "view">;
10021038
getFunction(
10031039
nameOrSignature: "transfer(address,uint256,uint16,uint256,bytes32,bytes32,bool,bytes)"
10041040
): TypedContractMethod<

evm/ts/src/ethers-contracts/multiTokenNtt/1_1_0/factories/MultiTokenNtt.sol/MultiTokenNtt__factory.ts

+44-1
Large diffs are not rendered by default.

evm/ts/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ registerProtocol(_platform, "MultiTokenNtt", EvmMultiTokenNtt);
99

1010
export * as ethers_contracts from "./ethers-contracts/index.js";
1111
export * from "./ntt.js";
12+
export * from "./multiTokenNtt.js";
13+
export * from "./trimmedAmount.js";

evm/ts/src/multiTokenNtt.ts

+72-46
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
TokenAddress,
1515
TokenId,
1616
toNative,
17+
toUniversal,
1718
universalAddress,
1819
} from "@wormhole-foundation/sdk-definitions";
1920
import type { EvmChains, EvmPlatformType } from "@wormhole-foundation/sdk-evm";
@@ -30,6 +31,7 @@ import {
3031
MultiTokenNtt,
3132
Ntt,
3233
NttTransceiver,
34+
TrimmedAmount,
3335
} from "@wormhole-foundation/sdk-definitions-ntt";
3436
import { ethers, type Provider } from "ethers";
3537
import { EvmNttWormholeTranceiver } from "./ntt.js";
@@ -39,6 +41,11 @@ import {
3941
loadAbiVersion,
4042
MultiTokenNttManagerBindings,
4143
} from "./multiTokenNttBindings.js";
44+
import {
45+
decodeTrimmedAmount,
46+
EncodedTrimmedAmount,
47+
untrim,
48+
} from "./trimmedAmount.js";
4249

4350
export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
4451
implements MultiTokenNtt<N, C>
@@ -318,46 +325,68 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
318325
);
319326
}
320327

321-
async getCurrentOutboundCapacity(): Promise<bigint> {
322-
// return await this.manager.getCurrentOutboundCapacity();
323-
throw new Error("Not implemented");
328+
async getCurrentOutboundCapacity(localToken: TokenId): Promise<bigint> {
329+
const { chain, address } = await this.getOriginalToken(localToken);
330+
331+
return await this.manager.getCurrentOutboundCapacity({
332+
chainId: toChainId(chain),
333+
tokenAddress: address.toUint8Array(),
334+
});
324335
}
325336

326-
async getOutboundLimit(): Promise<bigint> {
327-
//const encoded: EncodedTrimmedAmount = (
328-
// await this.manager.getOutboundLimitParams()
329-
//).limit;
330-
//const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded);
331-
//const tokenDecimals = await this.getTokenDecimals();
337+
async getOutboundLimit(localToken: TokenId): Promise<bigint> {
338+
const { chain, address } = await this.getOriginalToken(localToken);
332339

333-
//return untrim(trimmedAmount, tokenDecimals);
334-
throw new Error("Not implemented");
340+
const encoded: EncodedTrimmedAmount = (
341+
await this.manager.getOutboundLimitParams({
342+
chainId: toChainId(chain),
343+
tokenAddress: address.toUint8Array(),
344+
})
345+
).limit;
346+
347+
const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded);
348+
const tokenDecimals = await this.getTokenDecimals(localToken);
349+
350+
return untrim(trimmedAmount, tokenDecimals);
335351
}
336352

337353
async getCurrentInboundCapacity(
338-
originalToken: TokenId,
354+
originalToken: MultiTokenNtt.OriginalTokenId,
339355
fromChain: Chain
340356
): Promise<bigint> {
341-
if (isNative(originalToken.address))
342-
throw new Error("Native token not supported");
343357
return await this.manager.getCurrentInboundCapacity(
344358
{
345-
chainId: toChainId(fromChain),
346-
tokenAddress: originalToken.address.toUniversalAddress().toUint8Array(),
359+
chainId: toChainId(originalToken.chain),
360+
tokenAddress: originalToken.address.toUint8Array(),
347361
},
348362
toChainId(fromChain)
349363
);
350364
}
351365

352-
async getInboundLimit(fromChain: Chain): Promise<bigint> {
353-
//const encoded: EncodedTrimmedAmount = (
354-
// await this.manager.getInboundLimitParams(toChainId(fromChain))
355-
//).limit;
356-
//const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded);
357-
//const tokenDecimals = await this.getTokenDecimals();
366+
async getInboundLimit(
367+
originalToken: MultiTokenNtt.OriginalTokenId,
368+
fromChain: Chain
369+
): Promise<bigint | null> {
370+
const localToken = await this.getLocalToken(originalToken);
371+
if (localToken === null) return null; // Token not yet created
372+
373+
const encoded: EncodedTrimmedAmount = (
374+
await this.manager.getInboundLimitParams(
375+
{
376+
chainId: toChainId(originalToken.chain),
377+
tokenAddress: originalToken.address.toUint8Array(),
378+
},
379+
toChainId(fromChain)
380+
)
381+
).limit;
382+
383+
const trimmedAmount: TrimmedAmount = decodeTrimmedAmount(encoded);
384+
if (trimmedAmount.amount === 0n && trimmedAmount.decimals === 0)
385+
return null;
358386

359-
//return untrim(trimmedAmount, tokenDecimals);
360-
throw new Error("Not implemented");
387+
const tokenDecimals = await this.getTokenDecimals(localToken);
388+
389+
return untrim(trimmedAmount, tokenDecimals);
361390
}
362391

363392
async getRateLimitDuration(): Promise<bigint> {
@@ -395,21 +424,29 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
395424
yield this.createUnsignedTx(tx, "Ntt.completeInboundQueuedTransfer");
396425
}
397426

398-
async getOriginalToken(localToken: TokenId): Promise<TokenId> {
427+
async getOriginalToken(
428+
localToken: TokenId
429+
): Promise<MultiTokenNtt.OriginalTokenId> {
399430
const [tokenId] = await this.manager.getTokenId(
400431
localToken.address.toString()
401432
);
402-
return Wormhole.tokenId(toChain(tokenId.chainId), tokenId.tokenAddress);
433+
434+
const chain = toChain(tokenId.chainId);
435+
const address = toUniversal(chain, tokenId.tokenAddress);
436+
437+
return {
438+
chain,
439+
address,
440+
};
403441
}
404442

405443
// This will return null if the token is not yet created
406-
async getLocalToken(originalToken: TokenId): Promise<TokenId | null> {
407-
if (isNative(originalToken.address))
408-
throw new Error("Native token not supported");
409-
444+
async getLocalToken(
445+
originalToken: MultiTokenNtt.OriginalTokenId
446+
): Promise<TokenId | null> {
410447
const localToken = await this.manager.getToken({
411448
chainId: toChainId(originalToken.chain),
412-
tokenAddress: originalToken.address.toUniversalAddress().toUint8Array(),
449+
tokenAddress: originalToken.address.toUint8Array(),
413450
});
414451

415452
if (localToken === ethers.ZeroAddress) return null;
@@ -423,14 +460,11 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
423460
}
424461

425462
async calculateLocalTokenAddress(
426-
originalToken: TokenId,
463+
originalToken: MultiTokenNtt.OriginalTokenId,
427464
tokenName: string,
428465
tokenSymbol: string,
429466
tokenDecimals: number
430467
): Promise<TokenAddress<C>> {
431-
if (isNative(originalToken.address))
432-
throw new Error("Native token not supported");
433-
434468
const tokenImplementation = await this.manager.tokenImplementation();
435469

436470
const initializeSelector = ethers.id("initialize(string,string,uint8)");
@@ -445,28 +479,20 @@ export class EvmMultiTokenNtt<N extends Network, C extends EvmChains>
445479
initializeSelector.slice(0, 10),
446480
coder.encode(
447481
["string", "string", "uint8"],
448-
// name and symbol cannot be longer than 32 bytes
449-
// TODO: this assumes ascii
450482
[tokenName.slice(0, 32), tokenSymbol.slice(0, 32), tokenDecimals]
451483
),
452484
]),
453485
]
454486
);
455487

456-
// TODO: we should fetch this from on-chain somehow?
457-
// type(ERC1967Proxy).creationCode;
458-
const proxyBytecode =
459-
"0x60806040526040516104e13803806104e1833981016040819052610022916102de565b61002e82826000610035565b50506103fb565b61003e83610061565b60008251118061004b5750805b1561005c5761005a83836100a1565b505b505050565b61006a816100cd565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606100c683836040518060600160405280602781526020016104ba60279139610180565b9392505050565b6001600160a01b0381163b61013f5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b6060600080856001600160a01b03168560405161019d91906103ac565b600060405180830381855af49150503d80600081146101d8576040519150601f19603f3d011682016040523d82523d6000602084013e6101dd565b606091505b5090925090506101ef868383876101f9565b9695505050505050565b60608315610268578251600003610261576001600160a01b0385163b6102615760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610136565b5081610272565b610272838361027a565b949350505050565b81511561028a5781518083602001fd5b8060405162461bcd60e51b815260040161013691906103c8565b634e487b7160e01b600052604160045260246000fd5b60005b838110156102d55781810151838201526020016102bd565b50506000910152565b600080604083850312156102f157600080fd5b82516001600160a01b038116811461030857600080fd5b60208401519092506001600160401b038082111561032557600080fd5b818501915085601f83011261033957600080fd5b81518181111561034b5761034b6102a4565b604051601f8201601f19908116603f01168101908382118183101715610373576103736102a4565b8160405282815288602084870101111561038c57600080fd5b61039d8360208301602088016102ba565b80955050505050509250929050565b600082516103be8184602087016102ba565b9190910192915050565b60208152600082518060208401526103e78160408501602087016102ba565b601f01601f19169190910160400192915050565b60b1806104096000396000f3fe608060405236601057600e6013565b005b600e5b601f601b6021565b6058565b565b600060537f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc546001600160a01b031690565b905090565b3660008037600080366000845af43d6000803e8080156076573d6000f35b3d6000fdfea2646970667358221220a2c581c6f59f8c322a89fe1c7cb21b56cf367c966e2b04f8b38bf4488beca08d64736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564";
488+
const creationCode = await this.manager.tokenProxyCreationCode();
460489

461-
const initCode = ethers.concat([proxyBytecode, constructorArgs]);
490+
const initCode = ethers.concat([creationCode, constructorArgs]);
462491
const initCodeHash = ethers.keccak256(initCode);
463492

464493
const salt = ethers.solidityPackedKeccak256(
465494
["uint16", "bytes32"],
466-
[
467-
toChainId(originalToken.chain),
468-
originalToken.address.toUniversalAddress().toUint8Array(),
469-
]
495+
[toChainId(originalToken.chain), originalToken.address.toUint8Array()]
470496
);
471497

472498
// The address where the token will be deployed

evm/ts/src/ntt.ts

+6-37
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ import {
4242
NttTransceiverBindings,
4343
loadAbiVersion,
4444
} from "./bindings.js";
45+
import {
46+
decodeTrimmedAmount,
47+
EncodedTrimmedAmount,
48+
TrimmedAmount,
49+
untrim,
50+
} from "./trimmedAmount.js";
4551

4652
export class EvmNttWormholeTranceiver<N extends Network, C extends EvmChains>
4753
implements
@@ -649,40 +655,3 @@ export class EvmNtt<N extends Network, C extends EvmChains>
649655
);
650656
}
651657
}
652-
653-
type EncodedTrimmedAmount = bigint; // uint72
654-
655-
type TrimmedAmount = {
656-
amount: bigint;
657-
decimals: number;
658-
};
659-
660-
function decodeTrimmedAmount(encoded: EncodedTrimmedAmount): TrimmedAmount {
661-
const decimals = Number(encoded & 0xffn);
662-
const amount = encoded >> 8n;
663-
return {
664-
amount,
665-
decimals,
666-
};
667-
}
668-
669-
function untrim(trimmed: TrimmedAmount, toDecimals: number): bigint {
670-
const { amount, decimals: fromDecimals } = trimmed;
671-
return scale(amount, fromDecimals, toDecimals);
672-
}
673-
674-
function scale(
675-
amount: bigint,
676-
fromDecimals: number,
677-
toDecimals: number
678-
): bigint {
679-
if (fromDecimals == toDecimals) {
680-
return amount;
681-
}
682-
683-
if (fromDecimals > toDecimals) {
684-
return amount / 10n ** BigInt(fromDecimals - toDecimals);
685-
} else {
686-
return amount * 10n ** BigInt(toDecimals - fromDecimals);
687-
}
688-
}

0 commit comments

Comments
 (0)