Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add arb owner and arb gas info actions #6

Merged
merged 48 commits into from
Mar 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
acc3596
arbowner client initial commit
spsjvc Dec 7, 2023
b08a45b
Merge branch 'main' into feat-arbowner-client
spsjvc Dec 18, 2023
f5d1c31
fix
spsjvc Dec 18, 2023
66b006e
wip
spsjvc Dec 18, 2023
c558894
change package name
spsjvc Dec 18, 2023
6fb59a1
build: add dotenv
spsjvc Dec 18, 2023
2670f05
add ci
spsjvc Dec 18, 2023
c11045a
fix
spsjvc Dec 18, 2023
981be34
Merge branch 'main' into feat-arbowner-client
spsjvc Dec 18, 2023
08bdc8f
add read contract utils
spsjvc Dec 18, 2023
6ad28f5
switch to local for test
spsjvc Dec 18, 2023
c0499fa
ayyy
spsjvc Dec 18, 2023
3d2e9b7
reorg
spsjvc Dec 18, 2023
7dacb51
organize tests
spsjvc Dec 18, 2023
3c80987
Merge branch 'ci' into feat-arbowner-client
spsjvc Dec 18, 2023
0c4aeb2
run integration in ci
spsjvc Dec 18, 2023
b5dbc69
Merge branch 'main' into ci
spsjvc Dec 18, 2023
d7e123a
update thing
spsjvc Dec 18, 2023
9085848
Merge branch 'ci' into feat-arbowner-client
spsjvc Dec 18, 2023
37da061
Merge branch 'main' into feat-arbowner-client
spsjvc Dec 18, 2023
1bf5c88
temporarily ts-ignore
spsjvc Dec 18, 2023
4c01a3c
merge test files
spsjvc Dec 18, 2023
cb34091
clean up
spsjvc Dec 18, 2023
a3b9d51
Merge branch 'main' into feat-arbowner-client
spsjvc Dec 18, 2023
02d0a5a
update branch and merge conflicts
GreatSoshiant Feb 15, 2024
71c658f
adding integration test (wip)
GreatSoshiant Feb 15, 2024
4663f3e
ci: use transfer-ownership branch
fionnachan Feb 19, 2024
aa326df
Update TokenBridgeCreator for L1-L2 bridge
TucksonDev Feb 20, 2024
6964793
Merge branch 'feat-arbowner-client' of https://github.com/OffchainLab…
GreatSoshiant Feb 20, 2024
301efa6
adding integration tests for upgrade executor
GreatSoshiant Feb 21, 2024
9e6e904
integration test for upgrade executor fixed
GreatSoshiant Feb 22, 2024
7edbd58
typo
GreatSoshiant Feb 22, 2024
f65b68e
arb gas info and setL1BaseFeeEstimateInertia test added
GreatSoshiant Feb 23, 2024
9af8c6d
Merge branch 'main' into feat-arbowner-client
GreatSoshiant Mar 4, 2024
f9b33c0
Merge branch 'main' into feat-arbowner-client
GreatSoshiant Mar 8, 2024
33591ca
Merge branch 'main' into feat-arbowner-client
GreatSoshiant Mar 19, 2024
6aac827
removing duplicate test helper
GreatSoshiant Mar 19, 2024
3883567
removing unnecessary network
GreatSoshiant Mar 19, 2024
93b2275
removing arbitrum local network from test helper
GreatSoshiant Mar 19, 2024
43d6344
getting private key from test helper
GreatSoshiant Mar 19, 2024
f201c96
nesting client extension
GreatSoshiant Mar 19, 2024
2e90810
getting l2 private key from test helper
GreatSoshiant Mar 19, 2024
f8336af
fix
spsjvc Mar 20, 2024
0972f55
remove unnecessary import
spsjvc Mar 20, 2024
f85a847
Merge branch 'main' into feat-arbowner-client
GreatSoshiant Mar 21, 2024
e1aa346
clean ups and formats
spsjvc Mar 27, 2024
9d3cd1b
fix
spsjvc Mar 27, 2024
66b4a67
clean up
spsjvc Mar 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/arbGasInfoReadContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Chain, GetFunctionArgs, PublicClient, ReadContractReturnType, Transport } from 'viem';

import { arbGasInfo } from './contracts';
import { GetFunctionName } from './types/utils';

export type ArbGasInfoAbi = typeof arbGasInfo.abi;
export type ArbGasInfoFunctionName = GetFunctionName<ArbGasInfoAbi>;

export type ArbGasInfoReadContractParameters<TFunctionName extends ArbGasInfoFunctionName> = {
functionName: TFunctionName;
} & GetFunctionArgs<ArbGasInfoAbi, TFunctionName>;

export type ArbGasInfoReadContractReturnType<TFunctionName extends ArbGasInfoFunctionName> =
ReadContractReturnType<ArbGasInfoAbi, TFunctionName>;

export function arbGasInfoReadContract<
TChain extends Chain | undefined,
TFunctionName extends ArbGasInfoFunctionName,
>(
client: PublicClient<Transport, TChain>,
params: ArbGasInfoReadContractParameters<TFunctionName>,
): Promise<ArbGasInfoReadContractReturnType<TFunctionName>> {
// @ts-ignore (todo: fix viem type issue)
return client.readContract({
address: arbGasInfo.address,
abi: arbGasInfo.abi,
functionName: params.functionName,
args: params.args,
});
}
81 changes: 81 additions & 0 deletions src/arbOwnerPrepareTransactionRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import {
PublicClient,
encodeFunctionData,
EncodeFunctionDataParameters,
Address,
Chain,
Transport,
} from 'viem';

import { arbOwner } from './contracts';
import { upgradeExecutorEncodeFunctionData } from './upgradeExecutor';
import { Prettify } from './types/utils';

type ArbOwnerEncodeFunctionDataParameters = Prettify<
Omit<EncodeFunctionDataParameters<typeof arbOwner.abi, string>, 'abi'>
>;

function arbOwnerEncodeFunctionData({ functionName, args }: ArbOwnerEncodeFunctionDataParameters) {
return encodeFunctionData({
abi: arbOwner.abi,
functionName,
args,
});
}

function arbOwnerPrepareFunctionData(
params: ArbOwnerEncodeFunctionDataParameters & {
upgradeExecutor: Address | false;
},
) {
const { upgradeExecutor } = params;

if (!upgradeExecutor) {
return {
to: arbOwner.address,
data: arbOwnerEncodeFunctionData(params),
value: BigInt(0),
};
}

return {
to: upgradeExecutor,
data: upgradeExecutorEncodeFunctionData({
functionName: 'executeCall',
args: [
arbOwner.address, // target
arbOwnerEncodeFunctionData(params), // targetCallData
],
}),
value: BigInt(0),
};
}

export type ArbOwnerPrepareTransactionRequestParameters = Prettify<
ArbOwnerEncodeFunctionDataParameters & {
upgradeExecutor: Address | false;
account: Address;
}
>;

export async function arbOwnerPrepareTransactionRequest<TChain extends Chain | undefined>(
client: PublicClient<Transport, TChain>,
params: ArbOwnerPrepareTransactionRequestParameters,
) {
if (typeof client.chain === 'undefined') {
throw new Error('[arbOwnerPrepareTransactionRequest] client.chain is undefined');
}

const { to, data, value } = arbOwnerPrepareFunctionData(params);

// @ts-ignore (todo: fix viem type issue)
const request = await client.prepareTransactionRequest({
chain: client.chain,
to,
data,
value,
account: params.account,
});

return { ...request, chainId: client.chain.id };
}
30 changes: 30 additions & 0 deletions src/arbOwnerReadContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Chain, GetFunctionArgs, PublicClient, ReadContractReturnType, Transport } from 'viem';

import { arbOwnerPublic } from './contracts';
import { GetFunctionName } from './types/utils';

export type ArbOwnerPublicAbi = typeof arbOwnerPublic.abi;
export type ArbOwnerPublicFunctionName = GetFunctionName<ArbOwnerPublicAbi>;

export type ArbOwnerReadContractParameters<TFunctionName extends ArbOwnerPublicFunctionName> = {
functionName: TFunctionName;
} & GetFunctionArgs<ArbOwnerPublicAbi, TFunctionName>;

export type ArbOwnerReadContractReturnType<TFunctionName extends ArbOwnerPublicFunctionName> =
ReadContractReturnType<ArbOwnerPublicAbi, TFunctionName>;

export function arbOwnerReadContract<
TChain extends Chain | undefined,
TFunctionName extends ArbOwnerPublicFunctionName,
>(
client: PublicClient<Transport, TChain>,
params: ArbOwnerReadContractParameters<TFunctionName>,
): Promise<ArbOwnerReadContractReturnType<TFunctionName>> {
// @ts-ignore (todo: fix viem type issue)
return client.readContract({
address: arbOwnerPublic.address,
abi: arbOwnerPublic.abi,
functionName: params.functionName,
args: params.args,
});
}
6 changes: 6 additions & 0 deletions src/contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
arbOwnerPublicConfig,
rollupCreatorConfig,
tokenBridgeCreatorConfig,
arbGasInfoConfig,
} from './generated';

export const erc20 = {
Expand All @@ -17,6 +18,11 @@ export const arbOwner = {
address: Object.values(arbOwnerConfig.address)[0],
} as const;

export const arbGasInfo = {
...arbGasInfoConfig,
address: Object.values(arbGasInfoConfig.address)[0],
} as const;

export const arbOwnerPublic = {
...arbOwnerPublicConfig,
address: Object.values(arbOwnerPublicConfig.address)[0],
Expand Down
23 changes: 23 additions & 0 deletions src/decorators/arbGasInfoPublicActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Transport, Chain, PublicClient } from 'viem';

import {
arbGasInfoReadContract,
ArbGasInfoFunctionName,
ArbGasInfoReadContractParameters,
ArbGasInfoReadContractReturnType,
} from '../arbGasInfoReadContract';

export type ArbGasInfoPublicActions<TChain extends Chain | undefined = Chain | undefined> = {
arbGasInfoReadContract: <TFunctionName extends ArbGasInfoFunctionName>(
args: ArbGasInfoReadContractParameters<TFunctionName>,
) => Promise<ArbGasInfoReadContractReturnType<TFunctionName>>;
};

export function arbGasInfoPublicActions<
TTransport extends Transport = Transport,
TChain extends Chain | undefined = Chain | undefined,
>(client: PublicClient<TTransport, TChain>): ArbGasInfoPublicActions<TChain> {
return {
arbGasInfoReadContract: (args) => arbGasInfoReadContract(client, args),
};
}
122 changes: 122 additions & 0 deletions src/decorators/arbOwnerPublicActions.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { it, expect } from 'vitest';
import { createPublicClient, http } from 'viem';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';

import { nitroTestnodeL2 } from '../chains';
import { arbOwnerPublicActions } from './arbOwnerPublicActions';
import { getNitroTestnodePrivateKeyAccounts } from '../testHelpers';

// l2 owner private key
const devPrivateKey = getNitroTestnodePrivateKeyAccounts().l2RollupOwner.privateKey;

const owner = privateKeyToAccount(devPrivateKey);
const randomAccount = privateKeyToAccount(generatePrivateKey());

const client = createPublicClient({
chain: nitroTestnodeL2,
transport: http(),
}).extend(arbOwnerPublicActions);

it('successfully fetches network fee receiver', async () => {
const result = await client.arbOwnerReadContract({
functionName: 'getNetworkFeeAccount',
});

expect(result).toEqual(owner.address);
});

it('succesfully fetches chain owners', async () => {
const result = await client.arbOwnerReadContract({
functionName: 'getAllChainOwners',
});

expect(result).toContain(owner.address);
});

it('succesfully adds chain owner', async () => {
const isOwnerInitially = await client.arbOwnerReadContract({
functionName: 'isChainOwner',
args: [randomAccount.address],
});

// assert account is not already an owner
expect(isOwnerInitially).toEqual(false);

const transactionRequest = await client.arbOwnerPrepareTransactionRequest({
functionName: 'addChainOwner',
args: [randomAccount.address],
upgradeExecutor: false,
account: owner.address,
});

// submit tx to add chain owner
await client.sendRawTransaction({
serializedTransaction: await owner.signTransaction(transactionRequest),
});

const isOwner = await client.arbOwnerReadContract({
functionName: 'isChainOwner',
args: [randomAccount.address],
});

// assert account is now owner
expect(isOwner).toEqual(true);
});

it('succesfully removes chain owner', async () => {
const isOwnerInitially = await client.arbOwnerReadContract({
functionName: 'isChainOwner',
args: [randomAccount.address],
});

// assert account is an owner
expect(isOwnerInitially).toEqual(true);

const transactionRequest = await client.arbOwnerPrepareTransactionRequest({
functionName: 'removeChainOwner',
args: [randomAccount.address],
upgradeExecutor: false,
account: owner.address,
});

// submit tx to remove chain owner
await client.sendRawTransaction({
serializedTransaction: await owner.signTransaction(transactionRequest),
});

const isOwner = await client.arbOwnerReadContract({
functionName: 'isChainOwner',
args: [randomAccount.address],
});

// assert account is no longer chain owner
expect(isOwner).toEqual(false);
});

it('succesfully updates infra fee receiver', async () => {
const initialInfraFeeReceiver = await client.arbOwnerReadContract({
functionName: 'getInfraFeeAccount',
});

// assert account is not already infra fee receiver
expect(initialInfraFeeReceiver).not.toEqual(randomAccount.address);

const transactionRequest = await client.arbOwnerPrepareTransactionRequest({
functionName: 'setInfraFeeAccount',
args: [randomAccount.address],
upgradeExecutor: false,
account: owner.address,
});

// submit tx to update infra fee receiver
await client.sendRawTransaction({
serializedTransaction: await owner.signTransaction(transactionRequest),
});

const infraFeeReceiver = await client.arbOwnerReadContract({
functionName: 'getInfraFeeAccount',
});

// assert account is now infra fee receiver
expect(infraFeeReceiver).toEqual(randomAccount.address);
});
33 changes: 33 additions & 0 deletions src/decorators/arbOwnerPublicActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Transport, Chain, PrepareTransactionRequestReturnType, PublicClient } from 'viem';

import {
arbOwnerReadContract,
ArbOwnerPublicFunctionName,
ArbOwnerReadContractParameters,
ArbOwnerReadContractReturnType,
} from '../arbOwnerReadContract';
import {
arbOwnerPrepareTransactionRequest,
ArbOwnerPrepareTransactionRequestParameters,
} from '../arbOwnerPrepareTransactionRequest';

export type ArbOwnerPublicActions<TChain extends Chain | undefined = Chain | undefined> = {
arbOwnerReadContract: <TFunctionName extends ArbOwnerPublicFunctionName>(
args: ArbOwnerReadContractParameters<TFunctionName>,
) => Promise<ArbOwnerReadContractReturnType<TFunctionName>>;

arbOwnerPrepareTransactionRequest: (
args: ArbOwnerPrepareTransactionRequestParameters,
) => Promise<PrepareTransactionRequestReturnType<TChain> & { chainId: number }>;
};

export function arbOwnerPublicActions<
TTransport extends Transport = Transport,
TChain extends Chain | undefined = Chain | undefined,
>(client: PublicClient<TTransport, TChain>): ArbOwnerPublicActions<TChain> {
return {
arbOwnerReadContract: (args) => arbOwnerReadContract(client, args),

arbOwnerPrepareTransactionRequest: (args) => arbOwnerPrepareTransactionRequest(client, args),
};
}
Loading
Loading