Skip to content

Commit bd6d114

Browse files
Merge pull request #205 from infinitybase/lb/feat/deploy-script
feat(contracts): add script to deploy contracts
2 parents 35fc1be + d3fe6e7 commit bd6d114

7 files changed

Lines changed: 221 additions & 22 deletions

File tree

biome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
},
1313
"linter": {
1414
"enabled": true,
15+
"ignore": ["scripts/**"],
1516
"rules": {
1617
"recommended": true,
1718
"correctness": {
@@ -49,7 +50,6 @@
4950
"ignore": [
5051
".vscode",
5152
".idea",
52-
"scripts/**",
5353
"node_modules/**",
5454
".turbo/**",
5555
"build/**",

docker/fuel-core/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# We should be supporting always the same fuel-core version as the fuels (ts-sdk)
88
# https://github.com/FuelLabs/fuels-ts/blob/master/internal/fuel-core/VERSION
9-
FROM ghcr.io/fuellabs/fuel-core:v0.40.0
9+
FROM ghcr.io/fuellabs/fuel-core:v0.44.0
1010

1111
# dependencies
1212
ENV DEBIAN_FRONTEND=noninteractive

packages/contracts/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand --silent",
1818
"build": "tsup",
1919
"build:sway": "pnpm fuels build",
20-
"contracts:start": "ts-node scripts/construct-contracts.ts"
20+
"contracts:start": "dotenv -e .env -- ts-node scripts/construct-contracts.ts",
21+
"contracts:deploy": "dotenv -e .env -- ts-node scripts/deploy.ts"
2122
},
2223
"keywords": [],
2324
"author": "",

packages/contracts/scripts/construct-contracts.ts

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
1-
import { getContractId, Manager, Nft, Registry, Resolver } from '../src';
1+
import { Manager, Nft, Registry, Resolver, getContractId } from '../src';
22
import { logger, setup } from './utils';
33

4-
const main = async () => {
5-
const { provider, wallet } = await setup();
6-
7-
const managerId = getContractId(provider.url, 'manager');
8-
const resolverId = getContractId(provider.url, 'resolver');
9-
const registryId = getContractId(provider.url, 'registry');
10-
const nftId = getContractId(provider.url, 'nft');
11-
12-
const manager = new Manager(managerId, wallet);
13-
const resolver = new Resolver(resolverId, wallet);
14-
const registry = new Registry(registryId, wallet);
4+
export const constructNft = async (wallet: any, registryId: string) => {
5+
const nftId = getContractId(wallet.provider.url, 'nft');
156
const nft = new Nft(nftId, wallet);
167

178
try {
18-
const { value: nftOwner } = await manager.functions.owner().get();
9+
const { value: nftOwner } = await nft.functions.owner().get();
1910

2011
// @ts-ignore
2112
if (nftOwner === 'Uninitialized') {
2213
const nftConstruct = await nft.functions
2314
.constructor(
2415
{ Address: { bits: wallet.address.toB256() } },
25-
{ ContractId: { bits: registryId } },
16+
{ ContractId: { bits: registryId } }
2617
)
2718
.call();
2819
await nftConstruct.waitForResult();
@@ -44,6 +35,13 @@ const main = async () => {
4435
}
4536
}
4637

38+
return nftId;
39+
};
40+
41+
export const constructManager = async (wallet: any, registryId: string) => {
42+
const managerId = getContractId(wallet.provider.url, 'manager');
43+
const manager = new Manager(managerId, wallet);
44+
4745
try {
4846
const { value: managerOwner } = await manager.functions.owner().get();
4947

@@ -52,7 +50,7 @@ const main = async () => {
5250
const managerConstruct = await manager.functions
5351
.constructor(
5452
{ Address: { bits: wallet.address.toB256() } },
55-
{ ContractId: { bits: registryId } },
53+
{ ContractId: { bits: registryId } }
5654
)
5755
.call();
5856
await managerConstruct.waitForResult();
@@ -74,6 +72,13 @@ const main = async () => {
7472
}
7573
}
7674

75+
return managerId;
76+
};
77+
78+
export const constructResolver = async (wallet: any, managerId: string) => {
79+
const resolverId = getContractId(wallet.provider.url, 'resolver');
80+
const resolver = new Resolver(resolverId, wallet);
81+
7782
try {
7883
const resolverConstruct = await resolver.functions
7984
.constructor({ bits: managerId })
@@ -88,12 +93,23 @@ const main = async () => {
8893
}
8994
}
9095

96+
return resolverId;
97+
};
98+
99+
export const constructRegistry = async (
100+
wallet: any,
101+
managerId: string,
102+
nftId: string
103+
) => {
104+
const registryId = getContractId(wallet.provider.url, 'registry');
105+
const registry = new Registry(registryId, wallet);
106+
91107
try {
92108
const registryConstruct = await registry.functions
93109
.constructor(
94110
{ bits: wallet.address.toB256() },
95111
{ bits: managerId },
96-
{ bits: nftId },
112+
{ bits: nftId }
97113
)
98114
.call();
99115
await registryConstruct.waitForResult();
@@ -105,6 +121,19 @@ const main = async () => {
105121
logger.error('Registry construct failed', e);
106122
}
107123
}
124+
125+
return registryId;
126+
};
127+
128+
const main = async () => {
129+
const { provider, wallet } = await setup();
130+
131+
const registryId = getContractId(provider.url, 'registry');
132+
133+
const nftId = await constructNft(wallet, registryId);
134+
const managerId = await constructManager(wallet, registryId);
135+
await constructResolver(wallet, managerId);
136+
await constructRegistry(wallet, managerId, nftId);
108137
};
109138

110139
main()
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import {
2+
type Account,
3+
type ContractFactory,
4+
type Provider,
5+
Src14OwnedProxy,
6+
Src14OwnedProxyFactory,
7+
ZeroBytes32,
8+
} from 'fuels';
9+
import {
10+
type Contracts,
11+
ManagerFactory,
12+
NftFactory,
13+
RegistryFactory,
14+
ResolverFactory,
15+
getContractId,
16+
} from '../src';
17+
import { logger, setContractId, setup } from './utils';
18+
19+
type DeployConfig = {
20+
contract: {
21+
name: Contracts;
22+
factory: ContractFactory;
23+
configurableConstants?: Record<any, any>;
24+
};
25+
provider: Provider;
26+
wallet: Account;
27+
};
28+
29+
const deployContractWithProxy = async (config: DeployConfig) => {
30+
const { provider, wallet, contract } = config;
31+
32+
logger.info(`[${contract.name}] Deploying new instance...`);
33+
const { contractId, waitForResult: waitForDeploy } =
34+
await contract.factory.deploy({
35+
configurableConstants: contract.configurableConstants,
36+
});
37+
await waitForDeploy();
38+
39+
logger.info(`[${contract.name}] Checking has proxy instance...`);
40+
const proxyAddress = getContractId(provider.url, contract.name);
41+
const addressType = await provider.getAddressType(
42+
proxyAddress ?? ZeroBytes32
43+
);
44+
const isDeployed = addressType === 'Contract';
45+
46+
if (!isDeployed) {
47+
logger.info(`[${contract.name}] Deploying proxy...`);
48+
const proxyDeployment = await Src14OwnedProxyFactory.deploy(wallet, {
49+
configurableConstants: {
50+
INITIAL_TARGET: { bits: contractId },
51+
INITIAL_OWNER: {
52+
Initialized: { Address: { bits: wallet.address.toB256() } },
53+
},
54+
},
55+
});
56+
57+
const { contract: proxy } = await proxyDeployment.waitForResult();
58+
const { waitForResult } = await proxy.functions.initialize_proxy().call();
59+
await waitForResult();
60+
61+
logger.success(
62+
`Proxy for ${contract.name} deployed! Id: ${proxy.id.toB256()}`
63+
);
64+
const proxyAddress = proxy.id.toB256();
65+
setContractId(provider.url, contract.name, proxyAddress);
66+
return proxy.id.toString();
67+
}
68+
69+
logger.info(`[${contract.name}] Has proxy instance! Setting target...`);
70+
const proxy = new Src14OwnedProxy(proxyAddress, wallet);
71+
const { waitForResult } = await proxy.functions
72+
.set_proxy_target({ bits: contractId })
73+
.call();
74+
await waitForResult();
75+
logger.success(
76+
`[${contract.name}] Target set! Proxy: ${proxy.id.toB256()} Target: ${contractId}`
77+
);
78+
return proxy.id.toString();
79+
};
80+
81+
const deployContract = async (config: DeployConfig) => {
82+
const { provider, contract } = config;
83+
84+
logger.info(`Deploying ${contract.name}...`);
85+
const { contractId, waitForResult: waitForDeploy } =
86+
await contract.factory.deploy({
87+
configurableConstants: contract.configurableConstants,
88+
});
89+
await waitForDeploy();
90+
91+
logger.success(`${contract.name} deployed! Id: ${contractId}`);
92+
setContractId(provider.url, contract.name, contractId);
93+
};
94+
95+
const main = async () => {
96+
const { wallet, provider } = await setup();
97+
98+
await deployContractWithProxy({
99+
wallet,
100+
provider,
101+
contract: {
102+
name: 'registry',
103+
factory: new RegistryFactory(wallet),
104+
},
105+
});
106+
107+
await deployContractWithProxy({
108+
wallet,
109+
provider,
110+
contract: {
111+
name: 'manager',
112+
factory: new ManagerFactory(wallet),
113+
},
114+
});
115+
116+
await deployContract({
117+
wallet,
118+
provider,
119+
contract: {
120+
name: 'resolver',
121+
factory: new ResolverFactory(wallet),
122+
},
123+
});
124+
125+
await deployContract({
126+
wallet,
127+
provider,
128+
contract: {
129+
name: 'nft',
130+
factory: new NftFactory(wallet),
131+
},
132+
});
133+
};
134+
135+
main()
136+
.then(() => {
137+
logger.success('Done!');
138+
process.exit(0);
139+
})
140+
.catch((error) => {
141+
logger.error('Construct failed!', error);
142+
process.exit(1);
143+
});

packages/contracts/scripts/utils.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
import fs from 'node:fs';
2+
import path from 'node:path';
13
import dotenv from 'dotenv';
24
import { Provider, Wallet } from 'fuels';
5+
import { type Contracts, type NetworkKeys, resolveNetwork } from '../src';
6+
import contracts from '../src/artifacts/contracts-fuel.json';
37

48
dotenv.config({
59
path: '../.env',
@@ -12,6 +16,28 @@ export const logger = {
1216
warn: (...data: any) => console.log(`❌ `, ...data),
1317
};
1418

19+
export const setContractId = <N extends NetworkKeys>(
20+
provider: string,
21+
contract: Contracts,
22+
contractId: string
23+
) => {
24+
const network = resolveNetwork(provider) as N;
25+
if (!contracts[network]) {
26+
contracts[network] = {
27+
manager: '',
28+
registry: '',
29+
resolver: '',
30+
nft: '',
31+
};
32+
}
33+
34+
contracts[network]![contract] = contractId;
35+
fs.writeFileSync(
36+
path.join(__dirname, '..', 'src', './artifacts/contracts-fuel.json'),
37+
JSON.stringify(contracts, null, 2)
38+
);
39+
};
40+
1541
export const requireEnv = (name: string) => {
1642
const value = process.env[name];
1743
if (!value) {
@@ -32,7 +58,7 @@ export const setup = async () => {
3258
`Setup
3359
Provider: ${providerUrl}
3460
Wallet: ${wallet.address.toB256()}
35-
Balance: ${balance.format()} ETH`,
61+
Balance: ${balance.format()} ETH`
3662
);
3763

3864
return { provider, wallet };

packages/contracts/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import contracts from './artifacts/contracts-fuel.json';
22

33
export type NetworkKeys = keyof typeof contracts;
4-
type ContractKeys<N extends NetworkKeys> = keyof (typeof contracts)[N];
4+
export type Contracts = 'manager' | 'registry' | 'resolver' | 'nft';
55

66
const DEFAULT_NETWORK: NetworkKeys = 'testnet';
77

@@ -23,7 +23,7 @@ export const resolveNetwork = (provider: string) => {
2323

2424
export const getContractId = <N extends NetworkKeys>(
2525
provider: string,
26-
contract: ContractKeys<N>
26+
contract: Contracts
2727
) => {
2828
const network = resolveNetwork(provider) as N;
2929
return contracts[network]?.[contract];

0 commit comments

Comments
 (0)