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

Update readme deployment #39

Closed
wants to merge 15 commits into from
Closed
25 changes: 19 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
ETHERSCAN_API_KEY=
PRIVATE_KEY=
SETTLEMENT=0x9008D19f58AAbD9eD0D60971565AA8510560ab41
# CLI
ETH_RPC_URL=http://erigon.dappnode:8545
SAFE=
TWAP=
COMPOSABLE_COW=
PRIVATE_KEY=

# Forge deployment scripts:
SETTLEMENT=0x9008D19f58AAbD9eD0D60971565AA8510560ab41 # GPv2Settlement contract to use for constructor initialisation.
# ETHERSCAN_API_KEY=
# Forge single order submission scripts:
# SAFE=
# TWAP=
# COMPOSABLE_COW=

# Tenderly Local Tests
NETWORK=5 # Network to test. 1: Mainnet, 5: Goerli, 100: xDai
# NODE_URL_1=
# NODE_URL_5=
# NODE_URL_100=
# NODE_USER_100=
# NODE_PASSWORD_100=

25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ tenderly actions deploy

| Contact Name | Ethereum Mainnet | Goerli | Gnosis Chain |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `ComposableCoW` | [0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738](https://etherscan.io/address/0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738) | [0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738](https://goerli.etherscan.io/0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738) | [0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738](https://gnosisscan.io/address/0xF487887DA5a4b4e3eC114FDAd97dc0F785d72738) |
| `ComposableCoW` | [0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74](https://etherscan.io/address/0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74) | [0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74](https://goerli.etherscan.io/0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74) | [0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74](https://gnosisscan.io/address/0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74) |
| `TWAP` | [0x910d00a310f7Dc5B29FE73458F47f519be547D3d](https://etherscan.io/address/0x910d00a310f7Dc5B29FE73458F47f519be547D3d) | [0x910d00a310f7Dc5B29FE73458F47f519be547D3d](https://goerli.etherscan.io/0x910d00a310f7Dc5B29FE73458F47f519be547D3d) | [0x910d00a310f7Dc5B29FE73458F47f519be547D3d](https://gnosisscan.io/address/0x910d00a310f7Dc5B29FE73458F47f519be547D3d) |
| `CurrentBlockTimestampFactory` | [0x0899c7DC280363d263Cc954506134F249CceC4a5](https://etherscan.io/address/0x0899c7DC280363d263Cc954506134F249CceC4a5) | [0x0899c7DC280363d263Cc954506134F249CceC4a5](https://goerli.etherscan.io/0x0899c7DC280363d263Cc954506134F249CceC4a5) | [0x0899c7DC280363d263Cc954506134F249CceC4a5](https://gnosisscan.io/address/0x0899c7DC280363d263Cc954506134F249CceC4a5) |
| `CurrentBlockTimestampFactory` | [0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc](https://etherscan.io/address/0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc) | [0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc](https://goerli.etherscan.io/0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc) | [0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc](https://gnosisscan.io/address/0x52eD56Da04309Aca4c3FECC595298d80C2f16BAc) |
| `GoodAfterTime` | TBD | TBD | TBD |
| `PerpetualStableSwap` | TBD | TBD | TBD |
| `TradeAboveThreshold` | TBD | TBD | TBD |
Expand Down Expand Up @@ -294,3 +294,24 @@ For local integration testing, including the use of [Tenderly Actions](#Tenderly
source .env
SAFE="address here" forge script script/submit_SingleOrder.s.sol:SubmitSingleOrder --rpc-url http://127.0.0.1:8545 --broadcast
```

#### Local test for Tenderly Web3 Actions

Make sure you setup the environment (so you have your own `.env` file).

Decide in which network you want to run the actions and provide the additional parameters for that network. For example:

```ini
NETWORK=100
NODE_URL_100=https://your-rpc-endpoint
NODE_USER_100=optionally-provide-user-if-auth-is-required
NODE_PASSWORD_100=optionally-provide-password-if-auth-is-required
```

```bash
# Build Actions
yarn build:actions

# Run actions locally, so it starts to checking for new blocks, and executing the actions to create Composable Cow orders)
yarn start:actions
```
19 changes: 19 additions & 0 deletions actions/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
"build": "tsc"
},
"devDependencies": {
"@tenderly/actions-test": "^0.0.13",
"@typechain/ethers-v5": "^10.2.0",
"@types/node": "^18.16.3",
"@tenderly/actions-test": "^0.0.13",
"ts-node": "^10.9.1",
"typechain": "^8.1.1"
"typechain": "^8.1.1",
"dotenv": "^16.3.1"
},
"dependencies": {
"@cowprotocol/contracts": "^1.4.0",
"@tenderly/actions": "^0.0.13",
"axios": "^1.4.0",
"axios": "^1.4.0",
"ethers": "^5.7.2",
"node-fetch": "2",
"typescript": "^5.0.4"
Expand Down
16 changes: 4 additions & 12 deletions actions/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ export const addContract: ActionFn = async (context: Context, event: Event) => {

// Load the registry
const registry = await Registry.load(context, transactionEvent.network);
console.log(
`Current registry: ${JSON.stringify(
Array.from(registry.ownerOrders.entries())
)}`
);

// Process the logs
transactionEvent.logs.forEach((log) => {
Expand Down Expand Up @@ -79,11 +74,6 @@ export const addContract: ActionFn = async (context: Context, event: Event) => {
}
}
});
console.log(
`Updated registry: ${JSON.stringify(
Array.from(registry.ownerOrders.entries())
)}`
);
await registry.write();
};

Expand All @@ -105,7 +95,7 @@ export const add = async (
if (registry.ownerOrders.has(owner)) {
const conditionalOrders = registry.ownerOrders.get(owner);
console.log(
`adding conditional order ${params} to already existing contract ${owner}`
`[register:add] Adding conditional order ${params} to already existing contract ${owner}`
);
let exists: boolean = false;
// Iterate over the conditionalOrders to make sure that the params are not already in the registry
Expand All @@ -127,7 +117,9 @@ export const add = async (
});
}
} else {
console.log(`adding conditional order ${params} to new contract ${owner}`);
console.log(
`[register:add] Adding conditional order ${params} to new contract ${owner}`
);
registry.ownerOrders.set(
owner,
new Set([{ params, proof, orders: new Map(), composableCow }])
Expand Down
27 changes: 21 additions & 6 deletions actions/test/run_local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,34 @@ import {
import { checkForAndPlaceOrder } from "../watch";
import { addContract } from "../register";
import { ethers } from "ethers";
import assert = require("assert");
import { getProvider } from "../utils";

require("dotenv").config();

const main = async () => {
const testRuntime = new TestRuntime();

const node_url = process.env["ETH_RPC_URL"];
if (!node_url) {
throw "Please specify your node url via the ETH_RPC_URL env variable";
// The web3 actions fetches the node url and computes the API based on the current chain id
const network = process.env.NETWORK;
assert(network, "network is required");

// Add secrets from local env (.env) for current network
const envNames = [
`NODE_URL_${network}`,
`NODE_USER_${network}`,
`NODE_PASSWORD_${network}`,
];
for (const name of envNames) {
const envValue = process.env[name];
if (envValue) {
await testRuntime.context.secrets.put(name, envValue);
}
}

// The web3 actions fetches the node url and computes the API based on the current chain id
const provider = new ethers.providers.JsonRpcProvider(node_url);
// Get provider
const provider = await getProvider(testRuntime.context, network);
const { chainId } = await provider.getNetwork();
await testRuntime.context.secrets.put(`NODE_URL_${chainId}`, node_url);

provider.on("block", async (blockNumber) => {
// Block watcher for creating new orders
Expand Down
72 changes: 72 additions & 0 deletions actions/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Context } from "@tenderly/actions";
import assert = require("assert");

import { ethers } from "ethers";
import { ConnectionInfo, Logger } from "ethers/lib/utils";
import { OrderStatus } from "./register";

async function getSecret(key: string, context: Context): Promise<string> {
const value = await context.secrets.get(key);
assert(value, `${key} secret is required`);

return value;
}

export async function getProvider(
context: Context,
network: string
): Promise<ethers.providers.Provider> {
Logger.setLogLevel(Logger.levels.DEBUG);

const url = await getSecret(`NODE_URL_${network}`, context);
const user = await getSecret(`NODE_USER_${network}`, context).catch(
() => undefined
);
const password = await getSecret(`NODE_PASSWORD_${network}`, context).catch(
() => undefined
);
const providerConfig: ConnectionInfo =
user && password
? {
url,
// TODO: This is a hack to make it work for HTTP endpoints (while we don't have a HTTPS one for Gnosis Chain), however I will delete once we have it
headers: {
Authorization: getAuthHeader({ user, password }),
},
// user: await getSecret(`NODE_USER_${network}`, context),
// password: await getSecret(`NODE_PASSWORD_${network}`, context),
}
: { url };

return new ethers.providers.JsonRpcProvider(providerConfig);
}

function getAuthHeader({ user, password }: { user: string; password: string }) {
return "Basic " + Buffer.from(`${user}:${password}`).toString("base64");
}

export function apiUrl(network: string): string {
switch (network) {
case "1":
return "https://api.cow.fi/mainnet";
case "5":
return "https://api.cow.fi/goerli";
case "100":
return "https://api.cow.fi/xdai";
case "31337":
return "http://localhost:3000";
default:
throw "Unsupported network";
}
}

export function formatStatus(status: OrderStatus) {
switch (status) {
case OrderStatus.FILLED:
return "FILLED";
case OrderStatus.SUBMITTED:
return "SUBMITTED";
default:
return `UNKNOWN (${status})`;
}
}
Loading