-
create env file from .env.l2.sample
cp .env.l2.sample .env
-
replace ETHEREUM_NODE_URL
-
create secure admin
docker exec -it safe-transaction-service-web-1 python [manage.py](http://manage.py/) createsuperuser
-
login at http://localhost:8000/admin
-
add custom Proxy Factories and Master Copies (L2)
-
click the
Add
link forWeb hooks
-
Ignore the
Address
field -
Set the
Url
field tohttp://your-config-gateway-url/cgw/v1/chains/{chainId}/hooks/events
and replace{chainId}
with the corresponding chainId -
Set the
Authorization
field toBasic <AUTH_TOKEN>
, where<AUTH_TOKEN>
corresponds to the value ofAUTH_TOKEN
in thecontainer_env_files/cgw.env
file of safe-infrastructure repository -
Optionally: Add the Safe Master Copy of your network at
http://localhost:8000/admin/history/safemastercopy
, whereversion
corresponds to the version of your deployed Safe Master Copy. Check L2 if it concerns the Safe L2 version. This is required for chains that were not added to safe-eth-py
-
CGW_FLUSH_TOKEN inside container_env_files/cfg.env and AUTH_TOKEN inside container_env_files/cgw.env should be same, and set them to a secure one
-
Set RPC_NODE_URL inside .env to your blockchain node url, preferable to have in https
cp .env.sample .env
-
create secure admin
docker compose up docker compose exec cfg-web python src/manage.py createsuperuser --noinput
-
login at http://localhost:8000/cfg/admin
-
add chainInfo, You can do this in the admin interface of the Safe Config service:
http://localhost:8000/cfg/admin/chains/chain/add/
-
Remember to edit your
ChainInfo
json fieldstransaction_service_uri
andvpc_transaction_service_uri
to point to your local instance of the transaction service. The values should behttp://your-transaction-service-url
since we have the frontend separate we’d need to proxy the requests to avoid cors erros to secure it we can update the origin to only the frontend url
const http = require('http');
const httpProxy = require('http-proxy');
const cors = require('cors');
const corsOptions = {
origin: '*', // Adjust this to allow requests from specific origins
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
optionsSuccessStatus: 204,
};
const targetUrl = 'http://localhost:8000'; // The local service URL
const proxy = httpProxy.createProxyServer({});
const server = http.createServer((req, res) => {
// Log the incoming request if needed
console.log(`Proxying request: ${req.method} ${req.url}`);
req.headers['origin'] = 'http://localhost:8000';
req.headers['referer'] = 'http://localhost:8000/';
// Proxy the request to the local service
proxy.web(req, res, { target: targetUrl });
res.setHeader('Access-Control-Allow-Origin', corsOptions.origin);
res.setHeader('Access-Control-Allow-Methods', corsOptions.methods);
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
// Handle preflight request
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
});
// Use the cors middleware
// server.use(cors(corsOptions));
const PORT = 8383; // Port for your proxy server to listen on
server.listen(PORT, () => {
console.log(`Proxy server is listening on port ${PORT}`);
});
# https://github.com/KyleAMathews/docker-nginx/blob/master/nginx.conf
# https://linode.com/docs/web-servers/nginx/configure-nginx-for-optimized-performance/
# https://github.com/denji/nginx-tuning
worker_processes auto;
events {
worker_connections 10000; # increase if you have lots of clients
# accept_mutex on; # set to 'on' if nginx worker_processes > 1
use epoll; # to enable for Linux 2.6+
}
http {
include mime.types;
# fallback in case we can't determine a type
default_type application/octet-stream;
sendfile on;
upstream app_server {
server 127.0.0.1:8383 fail_timeout=0;
keepalive 32;
}
upstream app {
server 127.0.0.1:8080 fail_timeout=0;
keepalive 32;
}
server {
access_log off;
charset utf-8;
server_name api.wagmilabz.com;
keepalive_timeout 75s;
keepalive_requests 100000;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
gzip_min_length 10000;
gzip_comp_level 6;
# text/html is always included by default
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/javascript text/xml application/xml application/rss+xml application/atom+xml application/rdf+xml;
gzip_disable "MSIE [1-6]\.";
# allow the server to close connection on non responding client, this will free up memory
reset_timedout_connection on;
# Redirect http to https
if ($http_x_forwarded_proto = 'http') {
return 301 https://$host$request_uri;
}
location / {
proxy_pass http://app/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
add_header Front-End-Https on;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
# They default to 60s. Increase to avoid WORKER TIMEOUT in web container
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
location /cgw/ {
proxy_pass http://app_server/cgw/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
add_header Front-End-Https on;
# we don't want nginx trying to do something clever with
# redirects, we set the Host: header above already.
proxy_redirect off;
# They default to 60s. Increase to avoid WORKER TIMEOUT in web container
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/api.wagmilabz.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/api.wagmilabz.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = api.wagmilabz.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name api.wagmilabz.com;
keepalive_timeout 75s;
return 404; # managed by Certbot
}}
-
update src/hooks/coreSDK/safeCoreSDK.ts like this
export const initSafeSDK = async ({ provider, chainId, address, version, implementationVersionState, implementation, }: SafeCoreSDKProps): Promise<Safe | undefined> => { const safeVersion = version ?? (await Gnosis_safe__factory.connect(address, provider).VERSION()) let isL1SafeMasterCopy = false // chainId === chains.eth // If it is an official deployment we should still initiate the safeSDK // if (!isValidMasterCopy(implementationVersionState)) { // const masterCopy = implementation // const safeL1Deployment = getSafeSingletonDeployment({ network: chainId, version: safeVersion }) // const safeL2Deployment = getSafeL2SingletonDeployment({ network: chainId, version: safeVersion }) // isL1SafeMasterCopy = masterCopy === safeL1Deployment?.networkAddresses[chainId] // const isL2SafeMasterCopy = masterCopy === safeL2Deployment?.networkAddresses[chainId] // // Unknown deployment, which we do not want to support // if (!isL1SafeMasterCopy && !isL2SafeMasterCopy) { // return Promise.resolve(undefined) // } // } // Legacy Safe contracts if (isLegacyVersion(safeVersion)) { isL1SafeMasterCopy = true } const contractNetworks: ContractNetworksConfig = { '1998': { // safeMasterCopyAddress: '0xc6d15fC421c1EabF496D71aDd33A44d826191BC8', safeMasterCopyAddress: '0x4585475D8d683Fdc01b029A9B39c1eAe5edA2038', safeProxyFactoryAddress: '0xe3Bfe3823CC975E7976D14e7aA38f8D4b40E9126', multiSendAddress: '0x2DB50Ca9819Dc9181767A3541783edf3C3Cd4a64', multiSendCallOnlyAddress: '0x09A5a915b4fF1EB27E33FA43612735E5aBe0872E', fallbackHandlerAddress: '0x86dBab4Aab8f10cc22BDAb42322CBf2f9098480E', signMessageLibAddress: '0x9c362B55510BdE08D525327149BEeB837d774268', createCallAddress: '0xf87B12365B1fEa9B5CFe5Ceebd2e07A9f1dd4FA9', }, } return Safe.create({ ethAdapter: createReadOnlyEthersAdapter(provider), safeAddress: address, isL1SafeMasterCopy, contractNetworks, }) }
-
similarly in src/services/contracts/safeContracts.ts add customContractAddress for
- getReadOnlyGnosisSafeContract → ethAdapter.getSafeContract
- getMultiSendCallOnlyContract → ethAdapter.getMultiSendCallOnlyContract
- getReadOnlyMultiSendCallOnlyContract → ethAdapter.getMultiSendCallOnlyContract
- getReadOnlyProxyFactoryContract → ethAdapter.getSafeProxyFactoryContract
- getReadOnlyFallbackHandlerContract → ethAdapter.getCompatibilityFallbackHandlerContract
- getReadOnlySignMessageLibContract → ethAdapter.getSignMessageLibContract
transaction-service: 4.25.1
config-service: 2.63.1
config-gateway-service: 1.4.0
safe-wallet-web (frontend): 1.18.0
note: correct versions should be set in order for application to work properly, setup assumes L2 version is used so use Safe Master L2 in order for indexing to work properly