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 35 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
40 changes: 40 additions & 0 deletions .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,46 @@ jobs:
- name: Test
run: yarn test:unit

test-integration:
GreatSoshiant marked this conversation as resolved.
Show resolved Hide resolved
name: Test (Integration)
runs-on: ubuntu-latest
needs: install
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: 18

- name: Restore node_modules
uses: OffchainLabs/actions/node-modules/restore@main

- name: Set up the local node
uses: OffchainLabs/actions/run-nitro-test-node@main

- name: Generate
run: yarn generate
with:
nitro-testnode-ref: transfer-ownership
# Use simple mode
no-simple: false
# RollupCreator on L1 is deployed by default
# RollupCreator on L2 is deployed with --l3node
l3-node: true
# L3 node with custom fee token when using --l3-fee-token
args: --l3-fee-token

- name: Copy .env
run: cp ./.env.example ./.env

- name: Build
run: yarn build

- name: Test
run: yarn test:integration

test-integration:
name: Test (Integration)
runs-on: ubuntu-latest
Expand Down
120 changes: 120 additions & 0 deletions examples/arb-owner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Chain, createPublicClient, http } from 'viem';
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
import { arbitrumSepolia } from 'viem/chains';
import {
createRollupPrepareConfig,
prepareChainConfig,
createRollupPrepareTransactionRequest,
createRollupPrepareTransactionReceipt,
arbOwnerPublicActions,
} from '@arbitrum/orbit-sdk';
import { generateChainId } from '@arbitrum/orbit-sdk/utils';

function sanitizePrivateKey(privateKey: string): `0x${string}` {
if (!privateKey.startsWith('0x')) {
return `0x${privateKey}`;
}

return privateKey as `0x${string}`;
}

function withFallbackPrivateKey(privateKey: string | undefined): `0x${string}` {
if (typeof privateKey === 'undefined') {
return generatePrivateKey();
}

return sanitizePrivateKey(privateKey);
}

function getBlockExplorerUrl(chain: Chain) {
return chain.blockExplorers?.default.url;
}

if (typeof process.env.DEPLOYER_PRIVATE_KEY === 'undefined') {
throw new Error(
`Please provide the "DEPLOYER_PRIVATE_KEY" environment variable`
);
}

// load or generate a random batch poster account
const batchPosterPrivateKey = withFallbackPrivateKey(
process.env.BATCH_POSTER_PRIVATE_KEY
);
const batchPoster = privateKeyToAccount(batchPosterPrivateKey).address;

// load or generate a random validator account
const validatorPrivateKey = withFallbackPrivateKey(
process.env.VALIDATOR_PRIVATE_KEY
);
const validator = privateKeyToAccount(validatorPrivateKey).address;

// set the parent chain and create a public client for it
const parentChain = arbitrumSepolia;
const publicClient = createPublicClient({
chain: parentChain,
transport: http(),
}).extend(arbOwnerPublicActions);

// load the deployer account
const deployer = privateKeyToAccount(
sanitizePrivateKey(process.env.DEPLOYER_PRIVATE_KEY)
);

async function main() {
const publicClient = createPublicClient({
chain: arbitrumSepolia,
transport: http(),
}).extend(arbOwnerPublicActions);

publicClient.arbOwnerPrepareTransactionRequest({
functionName: 'setL1BaseFeeEstimateInertia',
args: [BigInt(0)],
account: deployer.address,
});

// generate a random chain id
const chainId = generateChainId();

// create the chain config
const chainConfig = prepareChainConfig({
chainId,
arbitrum: {
InitialChainOwner: deployer.address,
DataAvailabilityCommittee: true,
},
});

// prepare the transaction for deploying the core contracts
const request = await createRollupPrepareTransactionRequest({
params: {
config: createRollupPrepareConfig({
chainId: BigInt(chainId),
owner: deployer.address,
chainConfig,
}),
batchPoster,
validators: [validator],
nativeToken: '0xf861378b543525ae0c47d33c90c954dc774ac1f9', // $ARB
},
account: deployer.address,
publicClient: publicClient,
});

// sign and send the transaction
const txHash = await publicClient.sendRawTransaction({
serializedTransaction: await deployer.signTransaction(request),
});

// get the transaction receipt after waiting for the transaction to complete
const txReceipt = createRollupPrepareTransactionReceipt(
await publicClient.waitForTransactionReceipt({ hash: txHash })
);

console.log(
`Deployed in ${getBlockExplorerUrl(parentChain)}/tx/${
txReceipt.transactionHash
}`
);
}

main();
13 changes: 13 additions & 0 deletions examples/arb-owner/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "arb-owner",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "tsc --outDir dist && node ./dist/index.js"
},
"devDependencies": {
"@types/node": "^20.9.0",
"typescript": "^5.2.2"
}
}
4 changes: 4 additions & 0 deletions examples/arb-owner/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../tsconfig.base.json",
"include": ["./**/*"]
}
29 changes: 29 additions & 0 deletions src/arbGasInfoReadContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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<TFunctionName extends ArbGasInfoFunctionName>(
client: PublicClient<Transport>,
params: ArbGasInfoReadContractParameters<TFunctionName>,
): Promise<ArbGasInfoReadContractReturnType<TFunctionName>> {
//
// todo: fix this weird type issue
// @ts-ignore
return client.readContract({
address: arbGasInfo.address,
abi: arbGasInfo.abi,
functionName: params.functionName,
args: params.args,
});
}
91 changes: 91 additions & 0 deletions src/arbOwnerPrepareTransactionRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
PublicClient,
encodeFunctionData,
EncodeFunctionDataParameters,
Address,
PrepareTransactionRequestReturnType,
zeroAddress,
Chain,
Transport,
Abi,
} from 'viem';

import { arbOwner } from './contracts';
import { upgradeExecutorEncodeFunctionData } from './upgradeExecutor';
import { GetFunctionName, 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
const request = await client.prepareTransactionRequest({
chain: client.chain,
to,
data,
value,
account: params.account,
});

return { ...request, chainId: client.chain.id };
}
39 changes: 39 additions & 0 deletions src/arbOwnerReadContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
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<
TFunctionName extends ArbOwnerPublicFunctionName
>(
client: PublicClient<Transport>,
params: ArbOwnerReadContractParameters<TFunctionName>
): Promise<ArbOwnerReadContractReturnType<TFunctionName>> {
//
// todo: fix this weird type issue
// @ts-ignore
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
24 changes: 24 additions & 0 deletions src/decorators/arbGasInfoPublicActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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 {
// @ts-ignore
arbGasInfoReadContract: (args) => arbGasInfoReadContract(client, args),
};
}
Loading