Getting Started
Automated Web3 Security & Compliance
Shield3 provides automated security & compliance tools for developers to protect user transactions through a customizable policy engine delivered as a custom RPC.
Reporting
All transactions are saved along with full audit trails for policy execution results. Logs can be exported to assist with compliance filing processes.
Policy Library
Shield3 offers both standard policies, and custom policies for compliance, security, and org specific rules.
Default Policy Library
The following policies are a sample of the pre-configured policies which are available to Shield3 customers.
1 - Strict / Permissive Mode
If strict mode, transactions are blocked by default except those allowed by specific policies. If permissive mode, transactions are allowed by default except those blocked by specific policies.
2 - Unverified Contracts (Block | Flag | Alert)
If enabled, interactions with unverified contracts that cannot be decoded are forbidden. User can configure this policy to result in block, flag for MFA, or permit with an alert.
3 - OFAC SDN Block Native and ERC20 Transactions
Block native transfers, ERC20 transfers, and ERC20 approvals to OFAC addresses. As part of its enforcement efforts, OFAC publishes a list of individuals and companies owned or controlled by, or acting for or on behalf of, targeted countries. It also lists individuals, groups, and entities, such as terrorists and narcotics traffickers designated under programs that are not country-specific. Collectively, such individuals and companies are called "Specially Designated Nationals" or "SDNs." Their assets are blocked and U.S. persons are generally prohibited from dealing with them.
4 - Flagged Bad Actor Block Native and ERC20
Blocks any transaction with a bad actor flagged by Shield3 or our partners. Flagged addresses include those associated with malicious behavior including phishing, address poisoning, fraud, impersonation, etc.
5 - Native Transfers Spending Limits (Block | MFA)
If enabled, transactions with native values (ex. ETH) over a customizable threshold are forbidden. User can configure this policy to result in block, or flag for MFA.
6 - ERC20 Stablecoin Transfers Spending Limits (Block | MFA)
If enabled, transfers and approvals with verified stablecoins (ex. USDC, DAI, USDT) over a customizable threshold are forbidden. User can configure this policy to result in block, or flag for MFA.
7 - DEX Token Swap Protection
If enabled, token swaps are permitted with verified token pairs. Users can customize which pairs are allowed, and set a slippage limit to prevent trades that might result in MEV exploitation.
Integration Details
Shield3 integrates as a custom RPC. Any transaction that would normally be broadcast via an Ethereum node like Infura or Alchemy first passes through Shield3 before being sent to the customer's preferred provider.
Policy Anatomy
On Shield3 the contract method allowlists can be described as a simple policy. NOTE this shows the inner workings of the policy engine, the dashboard provides a simple editor to set these parameters without needing to learn the policy language.
@name("Mint Method")
@message("Allow mint on specific contract on Mumbai")
@action("Notify")
permit(
principal,
action == Action::"0x6a627842",
resource == Address::"0xbec332e1eb3ee582b36f979bf803f98591bb9e24"
) when { context.transaction.network == Network::"0x013881" };
permit | forbid
defines the only conditions that the RPC should broadcast the transaction. Policies can be configured to either allow everything except specific conditions, or allow nothing except specific conditions.
action
Can be blank, Notify
or MFA
. This instructs the RPC what to do in the event that the transaction is allowed. Alerts and MFA requests are sent via webhooks.
principal
defines which senders this policy applies to. Principal by itself means that it applies to all senders.
action
defines which transaction types this policy applies to. In this case the function signature of mint
is used.
resource
defines which contracts this policy applies to. In this case it is restricted to the mint contract address.
when
defines additional context. In this case it is restricting the policy to transactions on the Mumbai network.
Block List Policies
Below is a sample production policy which is used to validate transactions against block lists. Customers don't have to edit or deal with this level of detail but this is included to show how it works on a more technical level.
@name("Standard ERC20 TransferFrom Block Custom List")
@dependency("shared_addresses:block_list")
@message("Allow ERC20 transfer from unless blocked sender or recipient")
forbid(
principal,
action == Action::"0x23b872dd",
resource
) when {
(((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((((context["args"])["arg_1"]) has "groups") && ((((context["args"])["arg_1"])["groups"]).contains(Group::"block_list")))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
@name("Standard ERC20 TransferFrom Block Custom List")
@message("Allow ERC20 transfer from unless blocked sender or recipient")
@dependency("shared_addresses:block_list")
forbid(
principal,
action == Action::"0x23b872dd",
resource
) when {
(((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((((context["args"])["arg_1"]) has "groups") && ((((context["args"])["arg_1"])["groups"]).contains(Group::"block_list")))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
@dependency("shared_addresses:block_list")
@message("Allow transactions unless blocked sender or recipient or contract")
@name("Address or Contract Block Custom List")
permit(
principal,
action,
resource
) when {
!(((resource has "groups") && ((resource["groups"]).contains(Group::"block_list"))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list"))))
};
@dependency("shared_addresses:block_list")
@message("Allow ERC20 transfer unless blocked sender or recipient")
@name("Standard ERC20 Transfer Block Custom List")
forbid(
principal,
action == Action::"0xa9059cbb",
resource
) when {
((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
@name("Non-Standard ERC20 Approve Block Custom List")
@message("Allow ERC20 approve unless blocked sender or recipient")
@dependency("shared_addresses:block_list")
forbid(
principal,
action == Action::"0x095ea7b3",
resource
) when {
((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
@name("Standard ERC20 Approve Block Custom List")
@message("Allow ERC20 approve unless blocked sender or spender")
@dependency("shared_addresses:block_list")
forbid(
principal,
action == Action::"0x095ea7b3",
resource
) when {
((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
@name("Non-Standard ERC20 Transfer Block Custom List")
@message("Allow ERC20 transfer unless blocked sender or recipient")
@dependency("shared_addresses:block_list")
forbid(
principal,
action == Action::"0xa9059cbb",
resource
) when {
((((context["args"])["arg_0"]) has "groups") && ((((context["args"])["arg_0"])["groups"]).contains(Group::"block_list"))) || ((principal has "groups") && ((principal["groups"]).contains(Group::"block_list")))
};
Example Requests
Shield3 provides both broadcast
and simulate
capabilities to test the policy decision for a transaction. A broadcast
call follows the JSON RPC specification for all Ethereum nodes and no additional configuration is required except using the Shield3 RPC URL. Simulate
uses a custom RPC method. The api request looks like this for a valid mint request (function data is serialized using standard eth libs)
Both simulate
and broadcast
return & record rich context about policy execution and conditions which provide detailed audit records for customers.
{
"jsonrpc": "2.0",
"method": "eth_simulateTransaction",
"params": [
"0xf8505a85e8d4a510008307a12094bec332e1eb3ee582b36f979bf803f98591bb9e24840f71b3fba46a6278420000000000000000000000000000000000000000000000000000000000000001830138818080",
"0x01B2f8877f3e8F366eF4D4F48230949123733897"
],
"id": 42
}
When we call the simulate
method with the above policy enabled on the account we get a response like this:
{
"jsonrpc": "2.0",
"result": {
"transaction": {
"id": "68ee581c-fc00-4908-9221-57b9891f189a",
"txHash": "68ee581c-fc00-4908-9221-57b9891f189a",
"status": "Simulated",
"network": "0x01",
"workflowType": "transacting",
"fromAddress": {
"address": "0x01B2f8877f3e8F366eF4D4F48230949123733897"
},
"toAddress": {
"address": "0x6aAbDD49a7F97f5242fD0Fd6938987e039827666"
},
"routingDecision": "Block",
"decoded_type": "unknown",
"decisionReasons": [
{
"policyId": "6cbf882c-f151-4241-bd73-9ac1201b5de7",
"name": "Block unknown possible contract calls",
"description": "Block transactions that might be contract calls to unverified contracts",
"policyIcon": "block",
"icon": "block",
"label": "UNKNOWN CONTRACTS",
"severity": 0,
"entryType": "reason",
"decision": "Block"
},
{
"policyId": "802ca990-23cf-4436-be76-9fc0fa0ed7b0",
"name": "OFAC SDN block native and ERC20 transactions",
"description": "Block native transfers, ERC20 transfers, and ERC20 approvals to OFAC addresses",
"policyIcon": "block",
"icon": "check",
"label": "OFAC SANCTION",
"severity": 1,
"entryType": "reason",
"decision": "Allow"
}
],
"timestamp": "2024-05-14T19:15:12.159Z",
"value": {
"native": "0"
},
"serializedTx": "0xf8658080830186a0946aabdd49a7f97f5242fd0fd6938987e03982766680b844a9059cbb0000000000000000000000006aabdd49a7f97f5242fd0fd6938987e03982766600000000000000000000000000000000000000000000000001e32b4789740000018080"
},
"decision": "Block"
},
"id": 42
}
Additional Resources
Updated 6 months ago