A PolyesterEnvironment describes one deployment of Polyester: its API, WebSocket, and RPC
endpoints, the chain, the account-abstraction infrastructure, and the venue contracts. Every
client, signer, and session is created against an environment.
The built-in testnet
import { POLYESTER_TESTNET_ENVIRONMENT } from "@polyester/sdk";| Field | Value |
|---|---|
name | polyester-testnet |
apiUrl | https://api-devnet.polyester.ai |
websocketUrl | wss://api-devnet.polyester.ai |
rpcUrl | https://rpc.polyester.tech |
chain.id | 888168 (Polyester Chain Testnet) |
Defining an environment
import { createPolyesterEnvironment } from "@polyester/sdk";
const environment = createPolyesterEnvironment({
name: "my-environment",
apiUrl: "https://api.example.com",
websocketUrl: "wss://api.example.com",
rpcUrl: "https://rpc.example.com",
chain: { /* a viem Chain */ },
accountAbstraction: {
bundlerUrl: "https://bundler.example.com",
paymasterUrl: "https://paymaster.example.com",
entryPoint: { address: "0x…", version: "0.7" },
safe: {
version: "1.4.1",
safeProxyFactoryAddress: "0x…",
safeSingletonAddress: "0x…",
safeModuleSetupAddress: "0x…",
safe4337ModuleAddress: "0x…",
multiSendAddress: "0x…",
},
},
contracts: { tradingGatewayAddress: "0x…" },
});createPolyesterEnvironment validates and normalizes everything up front, then freezes the
result:
- URLs must parse and use the right scheme; plain
http:/ws:is allowed only forlocalhost. - Addresses are checksummed; invalid addresses throw a
ConfigurationError. - The entry point version must be
0.7. - The chain's default RPC is rewritten to
rpcUrl, so viem clients derived from the environment agree with it.
Misconfiguration fails at startup with a precise message — never at request time.
Why account abstraction is in here
Polyester accounts are Safe smart accounts. The accountAbstraction block pins the exact Safe
deployment (proxy factory, singleton, 4337 module, …) used to derive account addresses
deterministically. The account signer and smart-account helpers read these fields, which is why
the same owner key always maps to the same Polyester account — and why the block is part of the
environment rather than a helper option.
The fingerprint
Every environment gets a fingerprint: a hash over its endpoints, chain id, account-abstraction
config, and contracts. It answers one question cheaply: "were these two things created for the
same environment?"
The SDK uses it to fail fast instead of misbehaving subtly:
- An
AccountSignerrecords the fingerprint it was derived for; the browser client refuses a signer from a different environment. - Stored sessions are fingerprint-bound; a testnet token is never presented to another environment's API.
- Smart-account instances are checked against the client's environment before sending user operations.
Treat environments as singletons in your app: define once, import everywhere. Since the object is frozen and validated, sharing it is safe.