Giter Site home page Giter Site logo

smart-wallet's Introduction

Smart Wallet

This repository contains code for a new, ERC-4337 compliant smart contract wallet from Coinbase.

It supports

  • Multiple owners
  • Passkey owners and Ethereum address owners
  • Cross-chain replayability for owner updates and other actions: sign once, update everywhere.

Multiple Owners

Our smart wallet supports a practically unlimited number of concurrent owners (max 2^256). Each owner can transact independently, without sign off from any other owner.

Owners are identified as bytes to allow both Ethereum address owners and passkey (Secp256r1) public key owners.

Passkey owners and Ethereum address owners

Ethereum address owners can call directly to the smart contract wallet to transact and also transact via user operations.

In the ERC-4337 context, we expect UserOperation.signature to be the ABI encoding of a SignatureWrapper struct

struct SignatureWrapper {
    uint8 ownerIndex;
    bytes signatureData;
}

Owner index identifies the owner who signed the user operation. This must be passed because secp256r1 verifiers require the public key as an input. This differs from ecrecover, which returns the signer address.

We pass an ownerIndex rather than the public key itself to optimize for calldata, which is currently the main cost driver on Ethereum layer 2 rollups, like Base.

If the signer is an Ethereum address, signatureData should be the packed ABI encoding of the r, s, and v signature values.

If the signer is a secp256r1 public key, signatureData should be the the ABI encoding of a WebAuthnAuth struct. See webauthn-sol for more details.

Cross-chain replayability

If a user changes an owner or upgrade their smart wallet, they likely want this change applied to all instances of your smart wallet, across various chains. Our smart wallet allows users to sign a single user operation which can be permissionlessly replayed on other chains.

There is a special function, executeWithoutChainIdValidation, which can only be called by the EntryPoint contract (v0.6).

In validateUserOp we check if this function is being called. If it is, we recompute the userOpHash (which will be used for signature validation) to exclude the chain ID.

Code excerpt from validateUserOp

// 0xbf6ba1fc = bytes4(keccak256("executeWithoutChainIdValidation(bytes)"))
if (userOp.callData.length >= 4 && bytes4(userOp.callData[0:4]) == 0xbf6ba1fc) {
    userOpHash = getUserOpHashWithoutChainId(userOp);
    if (key != REPLAYABLE_NONCE_KEY) {
        revert InvalidNonceKey(key);
    }
} else {
    if (key == REPLAYABLE_NONCE_KEY) {
        revert InvalidNonceKey(key);
    }
}

To help keep these cross-chain replayable user operations organized and sequential, we reserve a specific nonce key for only these user operations.

executeWithoutChainIdValidation can only be used for calls to self and can only call a whitelisted set of functions.

function executeWithoutChainIdValidation(bytes calldata data) public payable virtual onlyEntryPoint {
    bytes4 selector = bytes4(data[0:4]);
    if (!canSkipChainIdValidation(selector)) {
        revert SelectorNotAllowed(selector);
    }

    _call(address(this), 0, data);
}

canSkipChainIdValidation can be used to check which functions can be called.

Today, allowed are

  • MultiOwnable.addOwnerPublicKey
  • MultiOwnable.addOwnerAddress
  • MultiOwnable.addOwnerAddressAtIndex
  • MultiOwnable.addOwnerPublicKeyAtIndex
  • MultiOwnable.removeOwnerAtIndex
  • UUPSUpgradeable.upgradeToAndCall

Deployments

Factory and implementation are deployed via Safe Singleton Factory, which today will give the same address across 248 chains. See "Deploying" below for instructions on how to deploy to new chains.

Version Factory Address
1 0x0BA5ED0c6AA8c49038F819E587E2633c4A9F428a

Developing

After cloning the repo, run the tests using Forge, from Foundry

forge test

Deploying

To deploy on a new chain, in your .env set

#`cast wallet` name
ACCOUNT=
# Node RPC URL
RPC_URL=
# Optional Etherscan API key for contract verification
ETHERSCAN_API_KEY=

See here for more details on cast wallet.

Then run

make deploy

Influences

Much of the code in this repository started from Solady's ERC4337 implementation. We were also influenced by DaimoAccount, which pioneered using passkey signers on ERC-4337 accounts, and LightAccount.

smart-wallet's People

Contributors

lukasrosario avatar pegahcarter avatar redlikerosesss avatar stevieraykatz avatar wbnns avatar wilsoncusack avatar worm-emoji avatar xenoliss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

smart-wallet's Issues

Request: Overload the createAccount function in CoinbaseSmartWalletFactory.sol

Context

The ERC7579 standard is great because it allows third-parties to add new features and functionality to a smart account without changing the core logic. I'm assuming the Coinbase Smart Wallet support this standard or something similar at mainnet launch.

Proposal

Currently in the CoinbaseSmartWalletFactory.sol smart contract doesn't include support for enabling modules during setup.

function createAccount(bytes[] calldata owners, uint256 nonce)
        public
        payable
        virtual
        returns (CoinbaseSmartWallet account)
    {
        if (owners.length == 0) {
            revert OwnerRequired();
        }

        (bool alreadyDeployed, address accountAddress) =
            LibClone.createDeterministicERC1967(msg.value, implementation, _getSalt(owners, nonce));

        account = CoinbaseSmartWallet(payable(accountAddress));

        if (alreadyDeployed == false) {
            account.initialize(owners);
        }
    }

From a developer perspective it would be great if this function was also overloaded with calldata instructions argument so modules could be enabled during the deployment.

function createAccount(bytes[] calldata owners, uint256 nonce, bytes instructions)
        public
        payable
        virtual
        returns (CoinbaseSmartWallet account)
    {
        if (owners.length == 0) {
            revert OwnerRequired();
        }

        (bool alreadyDeployed, address accountAddress) =
            LibClone.createDeterministicERC1967(msg.value, implementation, _getSalt(owners, nonce));
         
        // 1. INSERT LOGIC FOR VALIDATING DEPLOYMENT SIGNATURES
        // 2. INSERT LOGIC FOR ENABLING MODULES

        account = CoinbaseSmartWallet(payable(accountAddress));

        if (alreadyDeployed == false) {
            account.initialize(owners);
        }
    }

As far as I understand ERC-4337 transaction bundling this could also be achieved by bundling a createAccount function call and subsequently a enableModule function call on the smart wallet directly, but I do think there is something to be said about the "developer experience" in simplifying this process.

This pattern can also be observed in the Safe smart account factory smart contracts but suffers from poor documentation and confusing to data field that uses the delegatecall functionality, which has personally lead to 6+ hours wasted debugging.

function setup(
        address[] calldata _owners,
        uint256 _threshold,
        address to,
        bytes calldata data,
        address fallbackHandler,
        address paymentToken,
        uint256 payment,
        address payable paymentReceiver
    ) external override {
        setupOwners(_owners, _threshold);
        if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler);

        setupModules(to, data); // <- LOGIC TO ENABLE SAFE MODULES

        if (payment > 0) {
            handlePayment(payment, 0, 1, paymentToken, paymentReceiver);
        }
        emit SafeSetup(msg.sender, _owners, _threshold, to, fallbackHandler);
    }

Considerations

Allowing modules to be enabled during smart account creation without an additional authorization step introduces a "griefing" attack by allowing a "bad actor" to create a smart account on behalf of a user with a "malicious" module already enabled.

In a world with MEV and public mempools it's easy to front-run a smart account setup process with callback data for enabling arbitrary logic if module authorization is absent from the calldata.

Because of this the first step is authorize the setup with a signature by the owner(s) before completing the deployment process, which is why the "INSERT LOGIC FOR VALIDATING DEPLOYMENT SIGNATURES" comment is included in example overloaded function.

tl;dr

The proposed changes would make available two function calls:

  • createAccount(bytes[] calldata owners, uint256 nonce)
  • createAccount(bytes[] calldata owners, uint256 nonce, bytes instructions)

One for a vanilla deployment and another for authorized deployment with pre-enabled modules adhering to the ERC-7579 standard.

Bug[high]: Users may be blocked from adding owners.

Summary

A user may unintentionally get blocked from adding new owners.

Description

When adding an owner, the nextOwnerIndex is incremented. However, when removing an owner, nextOwnerIndex remains the same. Once 255 owners have been added, a user is unable to add owners because of the uint8 overflow within _addOwner(). This limitation will still exist even after owners have been removed, as nextOwnerIndex will still be 255.

bug: missing 0 checks

We should add validations within addOwnerAddress() and addOwnerPublicKey() to require that the owner != 0.

Passkey signatures failing for some hashes

I was running tests on a fork of the smart wallet and getting errors for some tests.

I was following the same signing procedure as in this repo, and eventually found that the signature malleability check in WebAuthn-Sol was returning the error due to s being too large.

This test shows that for some hashes the values returned from vm.signP256 are causing the problem. I added a test testValidateSignatureWithPasskeySignerWithSCheck which passes when we take the compliment of s.

Is this something that should be handled by signP256? Maybe I have misunderstood what webAuthn.messageHash should be and that is causing the wrong signatures?

No CI

I propose adding a CI pipeline so that any local work of the repo can be guaranteed to build. The current commit (5bad101) breaks on build, slowing down development time for internal team and public contributors.

Request/Discuss: Multi-Dimensional Nonces

One of my favorite parts of the ERC-4337 specification is the flexibility of nonces.

As we all know EOA wallets are required to use a single nonce and increment that nonce every time a transaction is submitted. And generally speaking smart accounts (i.e. Safe) have adopted that approach for smart contract wallets, even though technically it's not required.

But the ERC-4337 specifically points out that trend does not to be followed.

In Ethereum protocol, the sequential transaction nonce value is used as a replay protection method as well as to determine the valid order of transaction being included in blocks.

It also contributes to the transaction hash uniqueness, as a transaction by the same sender with the same nonce may not be included in the chain twice.

However, requiring a single sequential nonce value is limiting the senders’ ability to define their custom logic with regard to transaction ordering and replay protection.

Instead of sequential nonce we implement a nonce mechanism that uses a single uint256 nonce value in the UserOperation, but treats it as two values:

  • 192-bit “key”
  • 64-bit “sequence”

https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support

Given the trend towards "intents" and having the need to potentially execute transactions out of order and based on different constraints, I wanted to surface the conversation of potentially supporting multiple nonce types in the Coinbase Smart Wallet.

As an example I'm including a link to a "smart transaction" prototype that lets a users choose from multiple nonce types while still using a single packed 32 byte word.

  • Standard Nonce
  • Multi-Dimensional Nonce
  • Time Nonce

https://github.com/district-labs/smart-transactions-v0/blob/main/contracts/intentify/src/nonce/NonceManager.sol

tl;dr

Not being required to use a sequential nonce could open up some interesting opportunities for the blockchain user experience. So mainly starting this conversation, while the Coinbase smart wallet is still in active development.

  • How can the UX being improved by using a non-standard nonce?
  • Is supporting multiple nonce types in the Coinbase smart wallet worth it?
  • Could these nonce features be added as a module?

feat: admin vs. owner access control

There should be a separation of roles between who is allowed to call add owner (admin) vs. who is a owner. Not everyone who has rights to calling the wallet may necessarily need rights to add/remove owners.

Request/Discuss: Weighted Signers

Today most smart accounts implementations treat every signer as equal, which generally makes sense for multi-sigs where each user is expected to be an unique individual and wants equal signing rights.

But I question that design constraint as it relates smart accounts, which are designed for a single person to use across multiple environments and contexts.

For example the Light smart account implementation by @shunkakinoki includes the ability to add weights to each signer.

https://light.so/0xFbd80Fe5cE1ECe895845Fd131bd621e2B6A1345F/owners

image

The weights give certain accounts increased/decreased permissions when it comes to authorizing transactions.

For example if the smart account has a threshold of 2/N it would require two accounts with a weight of 1 or a single account with a weight of 2 to authorize a transaction.

I think this starts to get especially interesting especially when you assign "transaction rules" around different signing thresholds and account weights.

For example maybe there is a spending limit of 1,000 USDC every 14 days for accounts with a weight of 1 and thus don't require additional signatures to confirm the transaction, but for any transaction that moving 1,000+ USDC it would require a signature from multiple accounts.

tl;dr

Having equally weighted signers in a multi-sig is a popular approach for smart accounts today. But it's worth questioning if that design constraint is worth keeping as move into the era of smart account for individuals.

  • How can weighted accounts improve the smart account experience?
  • Is it worth also exploring "transaction rules" around different signing thresholds?
  • Can these features be added as a module, instead of the core smart account logic?

Discussion: W3C Decentralized Identity Support

Opening up this issue to start the conversation around how the Coinbase Smart Wallet can natively support W3C decentralized identifiers and verifiable credentials.

Context

For the most part it feels like the Ethereum ecosystem has mostly "poo-pooed" on the idea of decentralized identity if it's not onchain. And while I certainly understand that perspective, I still believe there is a lot of benefit to exploring and possibly supporting the W3C decentralized identifiers and verifiable credentials in a future smart account stack.

Early on in Ethereum's history the uPort team created an EVM based decentralized identifier standard.

Arguably it was (wayyy) to early in the smart account evolution to matter, but those foundations ultimately became what is Account Abstraction today i.e. created and popularized the "meta-transactions" standard allowing third-parties to pay gas costs for users.

I mention this because as Coinbase helps usher in a new era of smart accounts, I believe it's worth looking to the past for inspiration and ideas that may be worth bringing into the future.

Where do we stand today with decentralized identity?

As of today the did:pkh standard has received the most adoption. Why? It's simple, allows any Ethereum PK to become a DID and doesn't require a ton of technical infrastructure to support.

But the did:pkh standard has some serious limitations. it's not possible to rotate keys, update the did document, and thus you really can't rely on it for a long-running decentralized identity or take full advantage of DID capabilities.

Proposal

Several months ago the "Decentralized Identity System" proposal and prototype was published on Github.

did:dis Proposal: https://github.com/decentralized-identity-system/did-dis
Safe Module Implementation: https://github.com/decentralized-identity-system/safe-did-dis

The did:dis proposal outlines how to natively support the W3C decentralized identifier and verifiable credential standard in EVM based smart accounts - overcoming the problems inherit to uPort's original designs (paying gas to update the DID) by using the Cross-Chain Interoperability Protocol (EIP-3668) to support offchain lookups for a user managed DID document.

┌──────┐                                          ┌────────┐ ┌───────────────────┐
│Client│                                          │Contract│ │Identity Hub @ url │
└──┬───┘                                          └───┬────┘ └──────┬────────────┘
   │                                                  │             │
   │ did(...)                                         │             │
   ├─────────────────────────────────────────────────►│             │
   │                                                  │             │
   │ revert OffchainData(sender, urls, callData,      │             │
   │                     callbackFunction, extraData) │             │
   │◄─────────────────────────────────────────────────┤             │
   │                                                  │             │
   │ HTTP request (sender, callData)                  │             │
   ├──────────────────────────────────────────────────┼────────────►│
   │                                                  │             │
   │ Response (result)                                │             │
   │◄─────────────────────────────────────────────────┼─────────────┤
   │                                                  │             │
   │ document(result, extraData)                      │             │
   ├─────────────────────────────────────────────────►│             │
   │                                                  │             │
   │ answer                                           │             │
   │◄─────────────────────────────────────────────────┤             │
   │                                                  │             │

Similar to Farcaster it takes a "sufficiently decentralized" approach by intertwining onchain and offchain infrastructure to achieve a desired objective: scalable identity primitive that uses a blockchain as thin trust layer.

Technical Considerations

For the most part natively supporting the W3C decentralized identifiers and verifiable credential in a smart account can be handled in module and is not required to be a part of the core smart account logic.

So similar to the Safe multi-sig setup it would be great if the CoinbaseSmartWalletFactory.sol can also be passed calldata to enable a module in the createAccount(bytes[] calldata owners, uint256 nonce) function. Given the the nature of "transaction bundling" in ERC-4337 this can probably also be achieved in two separate transactions confirmed during a single block, but for simplicities sake it might make sense to overload that function with the ability to enable modules using the ERC-7579 standard.

But... the current did:dis proposal does require updating the Factory contract to also be a DID resolver and support counterfactual instantiation of DID document without having to deploy a smart wallet on a specific network.

Example of a constructed did:dis identifier.

did:dis:8453:0x1111111111111111111111111111111111111111:0x9999999999999999999999999999999999999999

CHAIN_ID = 8453
RESOLVER = 0x1111111111111111111111111111111111111111
ACCOUNT = 0x9999999999999999999999999999999999999999

The CHAIN_ID is used locate the RESOLVER smart contract, which in turn uses the EIP-3668 standard to fetch a DID document via an offchain Identity Hub managed by the ACCOUNT even if a smart account hasn't been deployed.

Designed so users can first start a decentralized identity then progressively convert it into a smart account. The reasoning for this is outlined in the very length post about a "meta-strategy for onboarding a million users".

https://hackmd.io/@kames/progressive-commitment-thresholds

tl;dr

The W3C decentralized identifiers and verifiable credentials standard are powerful primitives.

Since the Coinbase Smart Wallet is likely to be one of the dominant smart account implementations I think it's worthwhile to ask if and how the stack can also give users access to privacy preserving decentralized identity primitives

While I did write and create the did:dis proposal/prototypes, so smart accounts can natively support these standards I'm not necessarily promoting them as the "right" answer, but more-so referencing it as a way to think about intertwining onchain/offchain APIs for a scalable solution that can meet the future demands of a decentralized internet.

In fact if the RESOLVER element was stripped from the did:dis standard proposal DID support could be completely handled in a module and not require any updates to any of the core Coinbase Smart Wallet logic.

Discussion: Low-Level Account Authorization Delegation

I want to share a unique approach to account authorization delegation that I think is particularly interesting when combined with Coinbase's focus on PassKeys as a primary signing method.

Given the recent comments about the starting an audit next week I don't think these type of features make sense in the core smart account logic but rather as a module or more specifically a second smart account this is an owner of the primary Coinbase smart wallet.

So this is mainly presented as a "hack" for how to use the Coinbase PassKey and smart account infrastructure to add low-level account authorization delegation capabilities to the user signing flows.

The Context

Generally speaking when an account is given permissions/authorizations to perform operations onchain it comes in the form of a smart contract update where the authorization is created using a transaction. Most notably the ERC20 "permit" standard being an exception to this rule.

The concept I'm sharing takes the "permit" concept and takes it to it's furthest conclusion.

A generalized rules/conditions framework for authorizing third-party execution of any public smart contract function call.

More specifically the https://github.com/delegatable/delegatable-sol smart contract delegation framework.

The frameworks draws inspiration from an Object capability model which is a computer security model for permissions sharing in decentralized systems.

It allows accounts to delegate fine-tuned permissions/authorizations across the entire EVM protocol space. It does so by embedding rules/conditions/enforcers inside of calldata that can be recursively delegated to third-party accounts using offchain signatures.

The signing process uses the EIP712 standard. Meaning any EVM based account can utilize these delegation capabilities.

The current documentation is a little old, but still includes a better overview of the unique approach works.

https://delegatable.org/docs/why

The Hack

Given the the upcoming audit this type of functionality probably isn't well suited for the core smart account logic, but having a generalized account authorization delegation is still super desirable from a security perspective and for experimental capabilities like a generalized "intents" framework, so it would be great to find a way to do this inside of the Coinbase Smart Wallet Stack - specifically with PassKeys as the primary signing mechanism.

My first thoughts on what this could realistically look like, is the owner of the primary smart account is a Passkey and second smart account with these extended delegation capabilities. The owner of the second account would be a PassKey, capable of signing ERC712 signatures and counterfactually authorizing sub-accounts to execute transactions as the primary wallet without requiring an explicit onchain transaction to grant authority.

account-authority-delegation

I think this model has a couple of interesting qualities:

  1. Pairs well in a world with lots of PassKeys and the need for layered security.
  2. Well suited for authorizing single use or recurring transactions in commerce based applications i.e. pull model vs push model.
  3. In a world with lots of rollups (100s or 1000s) counterfactual account authorization delegation scales exceptionally well and is likely a great addition to the recently proposed "multichain KV database" by re-introducing single-chain account authorizations without altering/undermining the core owner/proof model.

A generalized account authorization delegation protocol is still a relatively unsolved problem in the EVM space, but potentially adds a lot of benefits in terms of scaling the blockchain user experience.

The Why

The dominance of PassKeys in the smart wallet flow I think make it an exceptionally good fit to experiment with low-level account authorization delegation and finding the best practices for making a scalable onchain payments network.

With Coinbase's strong focus on payments and Base's attention to creators and commerce this type of approach seems like a nice fit, because it can emulate features found in things like traditional credit card payment networks: automated recurring payments and layered security practices.

tl;dr

I don't think account authorization delegation capabilities necessarily belong in the core smart wallet, but would love to see support for this unique EIP712 signing flow integrated into the Coinbase PassKey signing flow and bolted on at the smart contract level via a third-party.

Smart contract consultation

I have a bytecode of a contract transaction on Coinbase, and I can find the contract on Ethereum, but I cannot find the corresponding ABI information for the contract. As a result, I am unable to decode the transaction content. Can you provide the ABI information, or does Coinbase have a corresponding API that can be called for this purpose?

Smart contract address : 0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43

Transaction bytecode:
0xca350aa60000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000003d090000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000
a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000bb49af4efe13a71306f38614d7ee9b96a3143410000000000000000000000000000000000000000000000000000000000542a8bc000000000000000000000000
a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000aefde148d87b2ecedb2a7fdef8ddcea4fa96e8ad000000000000000000000000000000000000000000000000000000000a3248eb000000000000000000000000
a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000db946e8437fe68038d238c5dc3f2e887a81b350c000000000000000000000000000000000000000000000000000000001da28470000000000000000000000000
a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000002ab40224a25f1f42e3609c682cd3e3fce62a66ad000000000000000000000000000000000000000000000000000000012a05f200000000000000000000000000
a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000bf59510774e2c64b12b067c7cf35fa5a1c594311000000000000000000000000000000000000000000000000000000012eb50d4c000000000000000000000000
dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000023866a9d84638b951e494b7f91a953d0a8e58988000000000000000000000000000000000000000000000000000000000efdbcf0000000000000000000000000
dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000d44efcd7dbffb24ec84e5477e00c7de9be0424eb000000000000000000000000000000000000000000000000000000001d769cb7000000000000000000000000
dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000002d5409ded062030bd6abe1e2096c826786994253000000000000000000000000000000000000000000000000000000008695e71a000000000000000000000000
dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000004ecc9f6724008cb9febe894f73ddb70b32c540ce000000000000000000000000000000000000000000000000000000008821b5d2000000000000000000000000
dac17f958d2ee523a2206206994597c13d831ec700000000000000000000000050a8646633e17102431a2cd4b434bb6b3f6dc90a00000000000000000000000000000000000000000000000000000003766d4e9b000000000000000000000000
464ebe77c293e473b48cfe96ddcf88fcf7bfdac0000000000000000000000000d6eb1293ad25dbfa297c4f36bc84ed6f441077b9000000000000000000000000000000000000000000000068158dfd0e42e91c00000000000000000000000000
9e46a38f5daabe8683e10793b06749eef7d733d100000000000000000000000095ef9a234f8415a2de36b70b477ee444777ccba2000000000000000000000000000000000000000000003a68d1ad103e542e9400000000000000000000000000
9e46a38f5daabe8683e10793b06749eef7d733d1000000000000000000000000f14af9cc75a483b27ddbb5e1a95f0374a6b4b8e200000000000000000000000000000000000000000000463fc2ab8f11d56a9400000000000000000000000000
95ad61b0a150d79219dcf64e1e6cc01f0b64c4ce000000000000000000000000b74d68ddd7454908d853592fa6185d8435017caf000000000000000000000000000000000000000000005aeea12bde87d3a17c00000000000000000000000000
514910771af9ca656af840dff83e8264ecf986ca0000000000000000000000001850c9b73458350df56ab62a2cb91fabbd951b3c0000000000000000000000000000000000000000000000011a45208ed9c93400

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.