Code Monkey home page Code Monkey logo

social-connect's Introduction

SocialConnect

For Dev Setup see CONTRIBUTING.MD

SocialConnect is an open source protocol that maps off-chain personal identifiers (such as phone numbers, twitter handles, etc.) to on-chain account addresses. This enables a convenient and interoperable user experience for use cases such as:

  • payments - send money directly to your friend's phone number!
  • social discovery - find someone's account based on their twitter!
  • any other identity applications!

Here is a short demo of a payment from a Kaala wallet user to a Libera wallet user, with only a phone number:

image

Introduction to SocialConnect

Introduction to SocialConnect

๐Ÿ›  How it Works

SocialConnect uses a federated model, meaning that anyone has the power to be an issuer of attestation mappings. Issuers have the freedom to decide how to verify that the user actually has ownership of their identifier. After verification, issuers register the mapping as an attestation to the on-chain smart contract registry. Attestations are stored under the issuer that registered them. When looking up attestations, we then have to decide which issuers are trusted.

Here are some active issuers verifying and registering attestations:

Issuer Name Address
Kaala 0x6549aF2688e07907C1b821cA44d6d65872737f05 (mainnet)
Libera 0x388612590F8cC6577F19c9b61811475Aa432CB44 (mainnet) 0xe3475047EF9F9231CD6fAe02B3cBc5148E8eB2c8 (alfajores)

Off-chain identifiers, originally in plaintext, are obfuscated before they are used in on-chain attestations to ensure user privacy and security. This is done with the help of the Oblivious Decentralized Identifier Service (ODIS). The details of the obfuscation process and how to interact with ODIS are described in the docs about privacy.

Want a more profound understanding?

We've made a mini-series to explain you:

๐Ÿง‘โ€๐Ÿ’ป Quickstart

The following steps use the Celo ContractKit to quickly set you up to play around with the protocol. If you would like to use a different library instead, please refer to the example scripts.

  1. Add the @celo/identity package into your project.

    npm install @celo/identity
  2. Set up your issuer (read "Authentication" section in privacy.md), which is the account registering attestations. When a user requests for the issuer to register an attestation, the issuer should verify somehow that the user owns their identifier (ex. SMS verification for phone number identifiers).

    import { newKit } from "@celo/contractkit";
    
    // the issuer is the account that is registering the attestation
    let ISSUER_PRIVATE_KEY;
    
    // create alfajores contractKit instance with the issuer private key
    const kit = await newKit("https://alfajores-forno.celo-testnet.org");
    kit.addAccount(ISSUER_PRIVATE_KEY);
    const issuerAddress =
        kit.web3.eth.accounts.privateKeyToAccount(ISSUER_PRIVATE_KEY).address;
    kit.defaultAccount = issuerAddress;
    
    // information provided by user, issuer should confirm they do own the identifier
    const userPlaintextIdentifier = "+12345678910";
    const userAccountAddress = "0x000000000000000000000000000000000000user";
    
    // time at which issuer verified the user owns their identifier
    const attestationVerifiedTime = Date.now();
  3. Check and top up quota for querying ODIS if necessary.

    import { OdisUtils } from "@celo/identity";
    import { AuthSigner } from "@celo/identity/lib/odis/query";
    
    // authSigner provides information needed to authenticate with ODIS
    const authSigner: AuthSigner = {
        authenticationMethod: OdisUtils.Query.AuthenticationMethod.WALLET_KEY,
        contractKit: kit,
    };
    // serviceContext provides the ODIS endpoint and public key
    const serviceContext = OdisUtils.Query.getServiceContext(
        OdisContextName.ALFAJORES
    );
    
    // check existing quota on issuer account
    const { remainingQuota } = await OdisUtils.Quota.getPnpQuotaStatus(
        issuerAddress,
        authSigner,
        serviceContext
    );
    
    // if needed, approve and then send payment to OdisPayments to get quota for ODIS
    if (remainingQuota < 1) {
        const stableTokenContract = await kit.contracts.getStableToken();
        const odisPaymentsContract = await kit.contracts.getOdisPayments();
        const ONE_CENT_CUSD_WEI = 10000000000000000;
        await stableTokenContract
            .increaseAllowance(odisPaymentsContract.address, ONE_CENT_CUSD_WEI)
            .sendAndWaitForReceipt();
        const odisPayment = await odisPaymentsContract
            .payInCUSD(issuerAddress, ONE_CENT_CUSD_WEI)
            .sendAndWaitForReceipt();
    }
  4. Derive the obfuscated identifier from your plaintext identifier. Refer to documentation on the ODIS SDK for detailed explanations on these parameters and steps.

    // get obfuscated identifier from plaintext identifier by querying ODIS
    const { obfuscatedIdentifier } =
        await OdisUtils.Identifier.getObfuscatedIdentifier(
            userPlaintextIdentifier,
            OdisUtils.Identifier.IdentifierPrefix.PHONE_NUMBER,
            issuerAddress,
            authSigner,
            serviceContext
        );
  5. Register an attestation mapping between the obfuscated identifier and an account address in the FederatedAttestations contract. This attestation is associated under the issuer. See docs for more info.

    const federatedAttestationsContract =
        await kit.contracts.getFederatedAttestations();
    
    // upload identifier <-> address mapping to onchain registry
    await federatedAttestationsContract
        .registerAttestationAsIssuer(
            obfuscatedIdentifier,
            userAccountAddress,
            attestationVerifiedTime
        )
        .send();
  6. Look up the account addresses owned by an identifier, as attested by the issuers that you trust (in this example only your own issuer), by querying the FederatedAttestations contract. See docs for more info.

    const attestations = await federatedAttestationsContract.lookupAttestations(
        obfuscatedIdentifier,
        [issuerAddress]
    );
    
    console.log(attestations.accounts);

๐Ÿš€ Examples

Type
ContractKit
EthersJS (v5)
web3.js
NextJS based web app (Phone Number)
NextJS based templated
React Native App (Phone Number)
NextJS based web app (Twitter)
Server side NextJS (Twitter)

The Runtime Environments section shows instructions for using SocialConnect with:

image

๐Ÿ“„ Documentation

For a deeper dive under the hood and specific implementation details, check out the documentation of the protocol for details on how to interact with the on-chain registry, privacy for how identifiers are obfuscated, and key-setup to setup your role keys to interact with the protocol.

๐Ÿค Get In Touch

Interested in Integrating SocialConnect, get in touch by filling this form.

๐Ÿ“ฃ Feedback

SocialConnect is in beta! Help us improve by sharing feedback on your experience in the Github Discussion section. You can also open an issue or a PR directly on this repo.

FAQ

What is a "plainTextIdentifier"?

plainTextIdentifier is any string of text that a user can use to identify other user.

Phone number, Twitter handle, GitHub username anything that makes it easier to represent an evm based address.

For example:- Alice's phone number: +12345678901

What is an "obfuscatedIdentifier"?

Identifier that is used on-chain, to which the account address is mapped and used by dApps to lookup. It preserve the privacy of the user by not revealing the underlying plainTextIdentifier. Used for on-chain attestations, obtained by hashing the plaintext identifier, identifier prefix, and pepper using this schema: sha3(sha3({prefix}://{plaintextIdentifier})__{pepper}).

What is an "identifier prefix"?

Identifier Prefix is used to differentiate users having same plainTextIdentifier for different purposes and composability.

For example:- Consider Alice having same username on both Twitter and Github, alicecodes.

How do we differentiate between Alice verified using Twitter and Github?
This where prefix comes into play, the plainTextIdentifier alicecodes can be represented as twitter://alicecodes and github://alicecodes this helps differentiate whether Alice was verified using Twitter or Github.

Moreover, it also helps in composability if dApps follow a standard and use prefix then the corresponding obsfuscatedIdentifier will be the same thus making it easier for dApps to lookup identifier verified by other issuers.

You can keep an eye on prefixes suggested by us here.

What is a "pepper"?

pepper is a unique secret, obtained by taking the first 13 characters of the sha256 hash of the unblinded signature

What is a "unblinded signature"?

Obtained by unblinding the signature returned by ODIS which is the combined output, comprised of signature by ODIS signers.

What is an Issuer?

Issuer is an entity that is willing to take the overhead of verifying a user's ownership of an identifier.

Does Issuer need to pay for gas?

For lookup there is no requirement for gas, assuming that the obfuscatedIdentifier to be used for lookup is available.

For registering attestations it is optional, once the obfuscatedIdentifier is obtained issuer can decide whether to just sign the attestation and provide it back to the user which will then use its own funds for gas for registering itself or the issuer can perform the transaction which will require the issuer to pay for gas.

Does Issuer need to have ODIS quota?

Yes, Issuer needs to have ODIS Quota to register and lookup users.

What is cost to register a user? With 10 cUSD worth of ODIS quota you can attest 10,000 users!
Can I just lookup users and not register them? Yes, you can lookup users under other Issuers. By doing this, you are trusting that the Issuer took care about verifying that the identifier does actually belong to the user.

You might want to do this if you don't want to create a registry of your own and use an already existing registry created by other Issuers.

Can anyone become an Issuer? Yes, SocialConnect is open for all. Anyone can become an Issuer
What are some security & trust assumptions differences between the ASv1 vs. Social Connect?
ASv1 SocialConnect
Phone number verified by 3 randomly selected validators Phone number verified by issuer (no guarantee about authenticity or quality of verification), app developers choose who to trust
Single root of trust = Collective of Validators Many roots of trust = Respective attestation issuer that verified phone number
What's the best way to map an address returned by lookupAttestations to the issuer?
function lookupAttestations(bytes32 identifier, address[] calldata trustedIssuers)
    external
    view
    returns (
      uint256[] memory countsPerIssuer,
      address[] memory accounts,
      address[] memory signers,
      uint64[] memory issuedOns,
      uint64[] memory publishedOns
    )

lookupAttestations returns 4 arrays, depending on the order trustedIssuers was provided respectively the return values are returned.

For example:-

if trustedIssuers = [I1, I2, ...] then countsPerIssuer = [CI1, CI2, ...] where CIx = number of accounts attested under the Xth issuer

Is there a convention for phone number format?

Yes, the SDK function getObfuscatedIdentifier will only accept E164 formatted phone numbers.

social-connect's People

Contributors

aaronmgdr avatar alecps avatar alvarof2 avatar annakaz avatar ashishb avatar aslawson avatar bowd avatar carterqw2 avatar cmcewen avatar codyborn avatar critesjosh avatar eelanagaraj avatar etuleu avatar gastonponti avatar gnardini avatar i1skn avatar jcortejoso avatar jeanregisser avatar jmrossy avatar m-chrzan avatar martinvol avatar mrsmkl avatar nambrot avatar pedro-clabs avatar pedro-vk avatar soloseng avatar tarikbellamine avatar timmoreton avatar tkporter avatar yorhodes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

social-connect's Issues

Update examples repo in docs

  • add a README about how to run the scripts
  • remove private keys from scripts
  • Add .env file
  • Refactor example-scripts package to have a /src

Update ODIS runbook

Once Combiner is migrated to K8s #65 and is relying on Prometheus Metrics we should update the ODIS runbook to reflect all changes made preparing for MiniPay.

document SocialConnect wishlist

Compile list of all SocialConnect feature requests that are not related to performance, reliability or maintainability (e.g. cross-chain, OdisPayments multisig, etc.) See list below

Tasks

  1. 3 of 3
    stale

Deprecate ODIS Combiner log based monitoring and alerting

Once we are comfortable relying fully on prometheus metrics in the Combiner, we should delete all the old dashboards, alerts and log based metrics. We may also consider cleaning up logging in the code.

Tasks

No tasks being tracked yet.

Update ODIS to use backup full nodes

  • The ODIS signer and combiner currently have no logic for configuring a full node as backup that will automatically be used whenever there is a persistent issue with the primary full node.
  • Currently, ODIS operators need to manually reconfigure their full node provider to point to a new URL in order to use a backup full node.
  • Because nearly all ODIS signers and the combiner are using Forno as their primary full node, a Forno outage would currently take down the entire system until a majority of signers could reconfigure

Audit Signer test coverage

  • Make sure ODIS Signer has test coverage on all new features added during MiniPay preparation
  • Add tests where missing
  • Bump test coverage requirements if possible

OdisPayments balance distribution design doc

  • Collect requirements and define desired end result
  • Consider deploying a new multisig contract shared by ODIS operators
  • (Bonus) Consider also adding logic to OdisPayments contract to make it easier to change the price of ODIS queries without affecting past purchases.

Move SocialConnect packages into new repo (out of monorepo)

Context

I propose moving

phone number privacy packages + identity + encrypted backup to all to a new repo. (social connect)

these all depend on each other and depend on some other celo packages but other packages do not depend on them.

This will make releasing social connect easier, make celo sdks releasing simpler, and provide a home base for social connect which will help developers use that project more easily,

Source: This large issue:

ODIS MiniPay Launch Follow-up

Catch all Epic for tasks identified while preparing for the MiniPay launch. Contains sub-epics. Should be split up as needed once MiniPay context is no longer useful for planning.

Add more specific error messages on signer DB and key version errors in /sign endpoint

Currently, errors thrown due to DB update failures and key errors in /sign logic will default to the outer error handler and send a 500 UNKNOWN ERROR. Ideally, we would like to make this more specific in order to have a better sense of what's going wrong from the combiner when receiving a lot of these errors.

This is unfortunately not trivial; some challenges/things to keep in mind around this:

  • we currently default to the outer handler to take advantage of automatic transaction rollback logic
    • manually adding rollback logic is possible but gets very tricky very quickly (and we have concerns that this will make the code less maintainable & susceptible to adding in hard-to-detect edge cases and bugs when making changes in the future)
      • this may be the best way to go, but we should add test cases to minimize the risk of making changes that break the rollback logic
  • we could do something like try/catching errors that are thrown in specific blocks, throwing standardized errors, and then pattern matching in the outer handler but it's also not ideal to add in a bunch of try/catch/re-throwing for the same errors

This ticket should explore and implement the best option & add the necessary test cases for this.

Get ODIS logger to show accurate serviceName in integration tests

Our logger middleware sets a field in our structured logs called serviceName. This is particularly useful for integration tests, where the signer and combiner produce logs side by side and it is difficult to know which service a given log is coming from. However, right now the loggerMiddleware unintelligently uses the name of the service to which the given test file belongs, rather than the actual service producing the log. We should fix the way that serviceName is fetched/set in the loggerMiddleware so that we can tell the difference between signer and combiner logs during development.
https://github.com/celo-org/celo-monorepo/blob/79c6bdbe530cf872de6a63d0567a407172298cc6/packages/phone-number-privacy/combiner/src/server.ts#L37

Fix ODIS alert dashboard links

  • When you are paged for an alert, the link to see the dashboard the alert is based off of no longer works.
  • This is because the original alerts were created from dashboards, but those dashboards have been duplicated, updated and replaced.
  • Either remove this link from alert pages or reconnect alerts with the most recent dashboards based on whatever is most maintainable

ODIS Combiner to Prometheus

  • Prometheus metrics are much easier to add / update than log based metrics
  • The signer also uses prometheus metrics, so this will simplify our monitoring / alerting considerably

Consider adding caching for replayed requests to Combiner

  • Goal is to prevent replayed / retried requests from making a round trip to each signer.
  • This would mostly be done via an in-memory cache, rather than a DB
  • Should be prioritized based on how many replayed requests we are seeing post MiniPay launch

Add Prometheus metrics to ODIS Combiner code

  • Add prometheus metrics everywhere log-based metrics are currently used
  • Aim to mimic log based metrics, should document any changes
  • Do not change metric related logging for now
  • Add metrics to track latency between first and last signer response

Audit ODIS Combiner test coverage

  • Make sure ODIS Combiner has test coverage on all new features added during MiniPay preparation
  • Add tests where missing
  • Bump test coverage requirements if possible

ODIS Combiner to K8s

  • Standardize ODIS operations as the Combiner and Signer will be hosted the same way
  • Allow Combiner to use prometheus metrics
  • Possibly solve 500...503 errors returned by Signers that could be caused by Combiner instances being torn down while http connections with signers are open

Tasks

  1. alecps
  2. alecps alvarof2
  3. 3 of 3
    alecps
  4. alecps

Implement example code snippets that show how to use escrow.sol

  • Currently addressing the feedback to show code snippets for how to use the escrow contract instead of function signatures
  • To make sure the code snippets work and to make it as easy as possible for users, I'm putting together a sample script (like Josh did) here: https://github.com/0xarthurxyz/escrow-payment/blob/main/index.ts
  • This is todo as part of: #20

Todos:

  • Private key based option (no attestations)
    • Alice computes paymentId and secret
    • Alice makes transfer() call
    • Alice makes revoke() call
    • Bob makes withdraw() call
  • Phone number base option (with ASv1 attestations)
    • Alice queries Bob's identifier
      • currently stuck trying to query ODIS pepper
    • Alice computes paymentId and secret using identifier

Test and release ODIS Combiner to K8s

Tasks

Ingest ODIS Combiner logs in Grafana Cloud

Current state: We are currently exporting log based metrics defined in GCP to Grafana, but not the logs themselves.

Desired state: The combiner logs should be fully exported to grafana for consistency with the Signers and other services. We should redefine the existing log based metrics natively within grafana once this migration is complete.

Open questions: Should we just migrate the combiner infra to K8s? If so, this ticket will become obsolete as the logs will be exported in the same way that the Signer logs are exported.

Update ODIS READMEs

The ODIS READMEs are out of date and should be updated to reflect latest state post MiniPay launch, Combiner migration to k8s, and split from celo-monorepo

Refactor error handling in ODIS 2.0.0

There are several places in the refactored ODIS codebase where:

  • try/catches are used for control flow in a way that can make debugging slightly more challenging by suppressing unexpected errors
  • errors are "guessed at" but may also convolute what's actually going on (i.e. by suppressing the real error and guessing at the wrong error)
    • handling based on thrown errors in some cases does not check the error value types/differentiate in the logic based on the thrown error

This ticket should take a closer look at the error handling in ODIS and consider refactoring this more thoroughly. Consider:

  • How readable are the existing logs?
  • Have we had to debug any incidents or weird behavior? How could error handling be improved to make future debugging experiences better?
  • How readable/understandable is the existing control flow, especially in terms of where errors are thrown/suppressed?

Relevant Discussions from ODIS 2.0.0 PR

Consider how to treat discrepancies in success and version fields of signer responses

Currently, signer responses received by the combiner are filtered for successes in CombineAction. Consider whether we want to handle discrepancies in the success and version fields of responses differently

The combiner response separation also makes it difficult to: process/use returned domainState or quotaStatus in the case that a PNP or domain /sign call failed with an out-of-quota and signer responses. Ideally, we would want to process & return quota returned from those responses to give users more information about these failures.

Refactoring this is likely a more involved change and will require additional testing.

Update Celo Docs to reflect ASv2

Remove outdated information (e.g. ASv1)

Networks > Nodes > Run a Node >

Validators >

Validators > Run a Validator >

Ref:

Other:

  • high level overview landing page for ASv2 located in celo docs
  • adapt from original design doc
  • link to ASv2 repo for code examples and integration level docs

Implement replay handling for domain requests

The domainRequests table is currently unused but should be used to handle replays of requests according to the behavior defined here.

Additional context re: primary key & migrations

In order to make the migrations work for MySQL, we changed the migration to set the timestamp field in the domainRequests table nonnullable (Relevant PR). Since this bug was found after some (mostly postgres) setups had already run the older migrations, we added an additional migration to ensure that the constraint was non-null. (Weird additional finding: for our postgres DB setups, even with the nullable field, postgres had silently enforced the non-nullable constraint anyways, so this additional migration should not have actually changed anything but is more of a safeguard to ensure the same DB schema state across setups.)

When implementing replay handling, the PK should be revisited. If any difficulties arise in the table setups, it may be easiest to drop domainRequests and re-add it in the correct format, since it isn't being used anywhere.

Optimize ODIS geolocation

Tasks

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.