# Build Secure Onchain Apps with Server Wallets V2 (Python Walkthrough) > A hands-on guide to automating wallet management, enforcing policies, and sponsoring gas with Coinbase Developer Platform (CDP). **Published by:** [HeimLabs](https://paragraph.com/@heimlabs/) **Published on:** 2025-11-04 **Categories:** web3, server, wallets, cdp, coinbase **URL:** https://paragraph.com/@heimlabs/build-secure-onchain-apps-with-server-wallets-v2-python-walkthrough ## Content IntroductionToday, let’s talk about a common pain point in the blockchain ecosystem. If you want your users to enjoy a web2-like experience in an onchain application, you have to hide all the complexities, such as managing wallets, enforcing compliance rules, and sometimes even sponsoring gas. Doing all this securely and at scale is tough. That’s where Server Wallets from Coinbase Developer Platform (CDP) come in. They let you create and manage wallets programmatically, send transactions, enforce policies, and sponsor gas all through secure APIs. You can focus on your app logic while CDP handles the cryptography and infrastructure. In our previous video, we covered how CDP secures private keys and how the wallet infrastructure works behind the scenes. This time, we’re going hands-on with Python SDK (also available in TypeScript).What You’ll BuildBy the end of this walkthrough, you’ll be able to:⚙ Set up the CDP SDK and securely manage environment variables🔑 Create new Ethereum accounts and import existing ones💸 Send transactions and fetch balances🧩 Enforce policies with both failing and successful examples⛽ Enable gas sponsorship for seamless, gasless UX(Watch the Full Video here) Step-by-Step WalkthroughStep 1: SDK SetupCreate a requirements.txtfile and add these inside it:cdp-sdk>=0.0.1 python-dotenv>=1.0.0 web3>=6.0.0 cryptography>=41.0.0 eth-account>=0.13.0Then run this below command in your terminal:pip install -r requirements.txtThen we’ll create a reusable singleton instance of the CDP client inside utils.py# Singleton CDP client instance _cdp_instance = None async def get_cdp_client() -> CdpClient: """ Get or create a singleton CDP client instance """ global _cdp_instance if _cdp_instance is None: # Verify environment variables api_key_id = os.getenv('CDP_API_KEY_ID') api_key_secret = os.getenv('CDP_API_KEY_SECRET') wallet_secret = os.getenv('CDP_WALLET_SECRET') if not all([api_key_id, api_key_secret, wallet_secret]): raise ValueError("Missing required environment variables. Please check your .env file.") _cdp_instance = CdpClient() return _cdp_instanceStep 2: Create and Import AccountsCreating, fetching, or importing accounts is very straightforward with server wallets You can create an account usingcdp = await get_cdp_client() # Create Alice — a new account timestamp = datetime.now().strftime(“%Y%m%d%H%M%S”) alice = await cdp.evm.create_or_get_account(name=f”demo-account-new-20251001002758") print(f”Alice: {alice.address}”)To import an account using an existing private key# Import Bob — from private key bob_key = BOB_PRIVATE_KEY[2:] if BOB_PRIVATE_KEY.startswith(‘0x’) else BOB_PRIVATE_KEY # Calculate the expected address from the private key eth_account = Account.from_key(BOB_PRIVATE_KEY) expected_address = eth_account.address bob = await cdp.evm.import_account( private_key=bob_key, name=f”bob-{timestamp}” ) print(f”Bob: {bob.address}”)Step 3: Send a Transaction & Fetch BalancesYou can use evm.send_transactionfrom the cdp client to initialise a transactiontx_response = await cdp.evm.send_transaction( address=alice.address, transaction=TransactionRequestEIP1559( to=bob.address, value=w3.to_wei(amount_eth, “ether”), ), network=NETWORK, )And in the same way to fetch the balance of the user we use list_token_balancesas belowbalances = await cdp.evm.list_token_balances( address=address, network=NETWORK )This will provide the entire list of tokens the user is holding, and can be parsed as followif balances: balance_list = balances.balances if hasattr(balances, ‘balances’) else balances print(f”{address}:”) for balance in balance_list: symbol = balance.token.symbol if hasattr(balance, ‘token’) else ‘ETH’ if hasattr(balance, ‘amount’) and hasattr(balance.amount, ‘amount’): amount = balance.amount.amount decimals = balance.amount.decimals if hasattr(balance.amount, ‘decimals’) else 18 readable_amount = amount / (10 ** decimals) print(f” {symbol}: {readable_amount}”) return balancesStep 4: Enforce PoliciesCDP Server Wallets allow you to attach policies that define allowed actions or spending limits. For example, a policy might restrict transfers above a threshold or to certain addresses. You can enable this from your CDP dashboard by editing an existing template or writing your own custom rules.Once a policy is created, try to test with a transaction and your transaction will fail with an API error if in case it violates the policy. This can play a key role in compliance and operational safety.Step 5: Sponsor GasTo deliver a true web2-like experience, CDP lets you sponsor gas fees for your users by abstracting all the complexities of managing a paymaster.You can enable sponsorship through your CDP console under onchain tool > paymaster or click hereOnce you enable it, you’ll get the Paymaster URL, which should be passed as a parameter for gasless txn in the code.Before we jump into the gasless txn, there’s an important to thing to note, that is gasless txn works only with smart accounts so it’s important to create one, and CDP let’s you do that with a single line of code using their get_or_create_smart_accountfunction. But these smart accounts needs an owner account which is a EOA. Here’s how we create smart accountsasync def _get_or_create_smart_account(cdp: Any, name: str, display_name: str) -> Any: try: owner = await cdp.evm.get_or_create_account(name=name) account = await cdp.evm.get_or_create_smart_account(name=name, owner=owner) print(f”{display_name}: {account.address}”) return account except Exception as e: print(f”x Failed to create: {str(e)}”) raise async def create_smart_accounts() -> Tuple[Any, Any]: cdp = await get_cdp_client() alice = await _get_or_create_smart_account(cdp, “alice”, “Alice”) bob = await _get_or_create_smart_account(cdp, “bob”, “Bob”) return alice, bobThis makes transactions feel instant and free from the user’s perspective, while you control limits via policy.Step 6: Bringing them all togetherYou can call all these function in main function such as thisasync def main(): “”” Main orchestration function “”” try: # Create accounts alice, bob = await create_accounts() # Initial balances print(“\nInitial Balances:”) await fetch_balance(alice.address) await fetch_balance(bob.address) # Send transaction print(“\nSending Transaction:”) await send_tokens(alice, bob, amount_eth=0.001) # Final balances print(“\nFinal Balances:”) await fetch_balance(alice.address) await fetch_balance(bob.address) except Exception as e: print(f”Error: {str(e)}”) import traceback traceback.print_exc() finally: await close_cdp_client()Security & Best PracticesWhen working with Server Wallets, keep these best practices in mind:🔒 Always load secrets from environment variables — never hardcode keys🔁 Rotate wallet secrets regularly🧾 Redact API keys and private key material in logs🧱 Keep access scoped and audit permissions frequentlyAdditional FeaturesBeyond what we built today, Server Wallets V2 also support:🧠 Smart accounts for account abstraction and batching🔄 Token swaps for direct ERC-20 swaps🧰 Spend permissions for granular, scoped access🏢 Managed mode for team-scale infrastructureThese are optional but powerful tools as your app grows.ConclusionYou’ve just built and tested Server Wallets V2 with Python — from setup to transactions, policy enforcement, and gas sponsorship. You now have a secure, programmable wallet infrastructure ready for production. For deeper docs and SDK examples, visit the official Coinbase Developer Platform documentation. And follow HeimLabs for more technical walkthroughs, tutorials, and hands-on guides for Web3 developers.ResourcesCDP DocsCoinbase Developer Docs - Coinbase Developer DocumentationExplore our API & SDK references, demos, and guides for building onchain apps.https://docs.cdp.coinbase.comPython SDK ReferenceGitHub - coinbase/cdp-sdk-pythonContribute to coinbase/cdp-sdk-python development by creating an account on GitHub.https://github.comHeimLabsHeimLabs | Trusted Blockchain Solutions ProviderRevolutionize your business with HeimLabs' blockchain development solutions. Our expert team offers end-to-end services for smart contracts, DApps & more.https://www.heimlabs.comClap it up if this saved you time! Follow HeimLabs for unapologetically practical Web3 dev content. Twitter, LinkedIn. ## Publication Information - [HeimLabs](https://paragraph.com/@heimlabs/): Publication homepage - [All Posts](https://paragraph.com/@heimlabs/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@heimlabs): Subscribe to updates - [Twitter](https://twitter.com/heimlabs): Follow on Twitter - [Farcaster](https://farcaster.xyz/heimlabs): Follow on Farcaster