Skip to content

Commit

Permalink
Generate ABIs and docs page
Browse files Browse the repository at this point in the history
  • Loading branch information
noisekit committed Aug 18, 2023
1 parent 76fb434 commit 9b26ffd
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 64 deletions.
23 changes: 20 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,31 @@ jobs:
- checkout
- yarn-install
- run: yarn workspaces foreach --topological-dev --verbose run build:ts
- run: yarn docgen

- run:
name: "Generate docs for each contract"
command: yarn workspaces foreach --verbose run docgen
- run:
name: "Generate combined smart-contracts.md"
command: yarn workspace @synthetixio/docgen run docgen:contracts
- run:
name: "Generate ABIs for each supported network"
command: yarn workspace @synthetixio/docgen run abis
- run:
name: "Generate combined addresses-+-abis.md"
command: yarn workspace @synthetixio/docgen run docgen:abis

- store_artifacts:
path: "docs/smart-contracts.md"
destination: "smart-contracts.md"
path: "docs"
destination: "."

- run:
working_directory: ~/synthetix-gitbook-v3
name: "Update docs and push to smart-contracts branch"
command: |
cp ~/synthetix-v3/docs/smart-contracts.md ./for-developers/smart-contracts.md
cp ~/synthetix-v3/docs/addresses-+-abis.md ./for-developers/addresses-+-abis.md
cp ~/synthetix-v3/docs/abis/*.json ./for-developers/abis/
STATUS=$(git status)
if [[ $STATUS == *"nothing to commit, working tree clean"* ]]; then
Expand All @@ -54,6 +69,8 @@ jobs:
git config --global user.name Noisekit
git add ./for-developers/smart-contracts.md
git add ./for-developers/addresses-+-abis.md
git add ./for-developers/abis
git commit -m "Update Smart Contracts"
git push --set-upstream --force origin smart-contracts
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@
"publish:dev": "lerna publish --force-publish --canary --dist-tag dev --preid dev.$(git rev-parse --short HEAD)",
"publish-contracts": "yarn workspaces foreach --verbose run publish-contracts",
"prepublishOnly": "node ./prepublishOnly.js",
"docgen": "yarn workspaces foreach --verbose run docgen && yarn docgen:contracts",
"docgen:contracts": "yarn workspace @synthetixio/docgen docgen:contracts",
"docgen": "yarn docgen:contracts && yarn docgen:abis",
"docgen:contracts": "yarn workspaces foreach --verbose run docgen && yarn workspace @synthetixio/docgen run docgen:contracts",
"docgen:abis": "yarn workspace @synthetixio/docgen run abis && yarn workspace @synthetixio/docgen run docgen:abis",
"subgraphgen": "yarn workspaces foreach --verbose run subgraphgen"
},
"devDependencies": {
Expand Down
3 changes: 3 additions & 0 deletions utils/docgen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
abis/
docs/
deployments/
257 changes: 199 additions & 58 deletions utils/docgen/abis.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,47 @@ const { inspect } = require('@usecannon/cli');
const fs = require('fs/promises');
const prettier = require('prettier');

const CHAIN_IDS = [1, 5, 10, 420, 84531, 11155111];
const PROXIES = {
CoreProxy: 'SynthetixCore',
AccountProxyCore: 'snxAccountNFT',
AccountProxyPerps: 'PerpsAccountNFT',
Proxy: 'OracleManager',
USDProxy: 'snxUSDToken',
SpotMarketProxy: 'SpotMarket',
PerpsMarketProxy: 'PerpsMarket',
};

function deepFind(obj, key) {
if (key in obj) return obj[key];

for (let i = 0; i < Object.keys(obj).length; i++) {
if (typeof obj[Object.keys(obj)[i]] === 'object') {
let result = deepFind(obj[Object.keys(obj)[i]], key);
if (result) return result;
}
}
const CHAIN_IDS = [1, 5, 10, 420, 80001, 84531, 11155111];

function noop() {}

return null;
function etherscanLink(chain, address) {
switch (chain) {
case 1:
return `https://etherscan.io/address/${address}`;
case 5:
return `https://goerli.etherscan.io/address/${address}`;
case 11155111:
return `https://sepolia.etherscan.io/address/${address}`;
case 10:
return `https://optimistic.etherscan.io/address/${address}`;
case 420:
return `https://goerli-optimism.etherscan.io/address/${address}`;
case 80001:
return `https://mumbai.polygonscan.com/address/${address}`;
case 84531:
return `https://goerli.basescan.org/address/${address}`;
}
}

function noop() {}
function chainName(chain) {
switch (chain) {
case 1:
return 'Mainnet';
case 5:
return 'Goerli';
case 11155111:
return 'Sepolia';
case 10:
return 'Optimism';
case 420:
return 'Optimistic Goerli';
case 80001:
return 'Polygon Mumbai';
case 84531:
return 'Base Goerli';
}
}

function overrideStdoutWrite(callback = noop) {
const _write = process.stdout.write;
Expand All @@ -54,48 +70,173 @@ function overrideConsole(callback = noop) {
};
}

async function fetchDeployments(chainId) {
const unhookStdout = overrideStdoutWrite();
const unhookConsole = overrideConsole();
const deployments = await inspect('synthetix-omnibus', chainId, 'main', true);
unhookStdout();
unhookConsole();
return deployments;
}

async function run() {
await fs.mkdir(`${__dirname}/abis`, { recursive: true });
await fs.mkdir(`${__dirname}/docs`, { recursive: true });
await fs.mkdir(`${__dirname}/deployments`, { recursive: true });
const prettierOptions = JSON.parse(await fs.readFile(`${__dirname}/../../.prettierrc`, 'utf8'));

const prettyJson = (obj) =>
prettier.format(JSON.stringify(obj, null, 2), { parser: 'json', ...prettierOptions });

for (const chainId of CHAIN_IDS) {
const unhookStdout = overrideStdoutWrite();
const unhookConsole = overrideConsole();
const jsonOutput = await inspect('synthetix-omnibus', chainId, 'main', true);
unhookStdout();
unhookConsole();

const files = Object.entries(PROXIES)
.map(([proxyKey, proxyName]) => {
if (proxyKey.startsWith('AccountProxy')) {
const getCoreAccountProxy = proxyKey === 'AccountProxyCore';
const specificJsonOutput = getCoreAccountProxy
? jsonOutput.state['provision.system']
: jsonOutput.state['provision.perpsFactory']?.artifacts?.imports?.perpsFactory;
if (specificJsonOutput) {
const abi = deepFind(specificJsonOutput, 'AccountProxy');
if (abi) {
return { chainId, proxyKey, proxyName, abi };
}
}
} else {
const abi = deepFind(jsonOutput, proxyKey);
if (abi) {
return { chainId, proxyKey, proxyName, abi };
}
}
})
.filter(Boolean);

for (const { chainId, proxyName, abi } of files) {
const filename = `./abis/${chainId}-${proxyName}.json`;
console.log('Writing', filename);
console.log(`Fetching deployments for "${chainName(chainId)} - ${chainId}"`);
const deployments = await fetchDeployments(chainId);
if (!deployments) {
console.log(`No deployments for "${chainName(chainId)} - ${chainId}"`);
continue;
}
await fs.writeFile(`./deployments/${chainId}.json`, prettyJson(deployments), 'utf8');

await fs.writeFile(`./docs/${chainId}.md`, `## ${chainName(chainId)}\n\n`, 'utf8');
await fs.appendFile(`./docs/${chainId}.md`, `Chain ID: ${chainId}\n\n`, 'utf8');
await fs.appendFile(`./docs/${chainId}.md`, '| System | Address | ABI |\n', 'utf8');
await fs.appendFile(`./docs/${chainId}.md`, '| --- | --- | --- |\n', 'utf8');
const system = deployments?.state?.['provision.system']?.artifacts?.imports?.system;
if (system) {
console.log(`Writing ${chainId}-SynthetixCore.json`);
await fs.writeFile(
`./abis/${chainId}-SynthetixCore.json`,
prettyJson(system.contracts.CoreProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| Synthetix Core | [${system.contracts.CoreProxy.address}](${etherscanLink(
chainId,
system.contracts.CoreProxy.address
)}) | [View/Download](./abis/${chainId}-SynthetixCore.json) |\n`,
'utf8'
);

console.log(`Writing ${chainId}-snxAccountNFT.json`);
await fs.writeFile(
`./abis/${chainId}-snxAccountNFT.json`,
prettyJson(system.contracts.AccountProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| snxAccount NFT | [${system.contracts.AccountProxy.address}](${etherscanLink(
chainId,
system.contracts.AccountProxy.address
)}) | [View/Download](./abis/${chainId}-snxAccountNFT.json) |\n`,
'utf8'
);

console.log(`Writing ${chainId}-snxUSDToken.json`);
await fs.writeFile(
`./abis/${chainId}-snxUSDToken.json`,
prettyJson(system.contracts.USDProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| snxUSD Token | [${system.contracts.USDProxy.address}](${etherscanLink(
chainId,
system.contracts.USDProxy.address
)}) | [View/Download](./abis/${chainId}-snxUSDToken.json) |\n`,
'utf8'
);

const { oracle_manager: oracleManager } = system.imports;
if (oracleManager) {
console.log(`Writing ${chainId}-OracleManager.json`);
await fs.writeFile(
`./abis/${chainId}-OracleManager.json`,
prettyJson(oracleManager.contracts.Proxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| Oracle Manager | [${oracleManager.contracts.Proxy.address}](${etherscanLink(
chainId,
oracleManager.contracts.Proxy.address
)}) | [View/Download](./abis/${chainId}-OracleManager.json) |\n`,
'utf8'
);
}
}

const spotFactory =
deployments?.state?.['provision.spotFactory']?.artifacts?.imports?.spotFactory;
if (spotFactory) {
console.log(`Writing ${chainId}-SpotMarket.json`);
await fs.writeFile(
`./abis/${chainId}-SpotMarket.json`,
prettyJson(spotFactory.contracts.SpotMarketProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| Spot Market | [${spotFactory.contracts.SpotMarketProxy.address}](${etherscanLink(
chainId,
spotFactory.contracts.SpotMarketProxy.address
)}) | [View/Download](./abis/${chainId}-SpotMarket.json) |\n`,
'utf8'
);
}

const perpsFactory =
deployments?.state?.['provision.perpsFactory']?.artifacts?.imports?.perpsFactory;
if (perpsFactory) {
console.log(`Writing ${chainId}-PerpsMarket.json`);
await fs.writeFile(
`./abis/${chainId}-PerpsMarket.json`,
prettyJson(perpsFactory.contracts.PerpsMarketProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| Perps Market | [${perpsFactory.contracts.PerpsMarketProxy.address}](${etherscanLink(
chainId,
perpsFactory.contracts.PerpsMarketProxy.address
)}) | [View/Download](./abis/${chainId}-PerpsMarket.json) |\n`,
'utf8'
);

console.log(`Writing ${chainId}-PerpsAccountNFT.json`);
await fs.writeFile(
filename,
prettier.format(JSON.stringify(abi, null, 2), {
parser: 'json',
...prettierOptions,
}),
`./abis/${chainId}-PerpsAccountNFT.json`,
prettyJson(perpsFactory.contracts.AccountProxy),
'utf8'
);
await fs.appendFile(
`./docs/${chainId}.md`,
`| Perps Market Account NFT | [${
perpsFactory.contracts.AccountProxy.address
}](${etherscanLink(
chainId,
perpsFactory.contracts.AccountProxy.address
)}) | [View/Download](./abis/${chainId}-PerpsAccountNFT.json) |\n`,
'utf8'
);
}

console.log(`Writing ${chainId}.md`);
// SNX token
const configureSnxCollateral =
deployments?.state?.['invoke.configureSnxCollateral']?.artifacts?.txns
?.configureSnxCollateral;
const [snxCollateralConfiguredEvent] =
configureSnxCollateral?.events?.CollateralConfigured ?? [];
const [snxAddress] = snxCollateralConfiguredEvent?.args ?? [];
if (snxAddress) {
await fs.appendFile(
`./docs/${chainId}.md`,
`| SNX Token | [${snxAddress}](${etherscanLink(
chainId,
snxAddress
)}) | _ERC-20 compliant_ |\n`,
'utf8'
);
}
Expand Down
9 changes: 9 additions & 0 deletions utils/docgen/addresses-+-abis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Addresses + ABIs

See the [synthetix-deployments](https://github.com/synthetixio/synthetix-deployments) GitOps repository for more information.

To download the Addresses + ABIs for Synthetix via the command line, you can run the following command:

```bash
npx @usecannon/cli inspect synthetix-omnibus --write-deployments ./deployments --chain-id <CHAIN_ID>
```
37 changes: 37 additions & 0 deletions utils/docgen/docgen-abis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/bash

echo "Docgen ABIs..."

ROOT=$(yarn workspace synthetix-v3 exec pwd)
OUT="$ROOT/docs/addresses-+-abis.md"
mkdir -p $ROOT/docs
rm -rf $ROOT/docs/abis
rm -rf $OUT
touch $OUT

cat "./addresses-+-abis.md" > $OUT

cat ./docs/1.md >> $OUT
echo "" >> $OUT

cat ./docs/5.md >> $OUT
echo "" >> $OUT

cat ./docs/11155111.md >> $OUT
echo "" >> $OUT

cat ./docs/10.md >> $OUT
echo "" >> $OUT

cat ./docs/420.md >> $OUT
echo "" >> $OUT

cat ./docs/80001.md >> $OUT
echo "" >> $OUT

cat ./docs/84531.md >> $OUT
echo "" >> $OUT

cp -r ./abis $ROOT/docs/abis

echo "OK Docgen ABIs"
Loading

0 comments on commit 9b26ffd

Please sign in to comment.