{"id":25296064,"url":"https://github.com/selfkeyfoundation/selfkey-main-contracts","last_synced_at":"2025-06-13T08:05:52.692Z","repository":{"id":90560263,"uuid":"176475539","full_name":"SelfKeyFoundation/selfkey-main-contracts","owner":"SelfKeyFoundation","description":null,"archived":false,"fork":false,"pushed_at":"2020-09-05T18:55:36.000Z","size":365,"stargazers_count":0,"open_issues_count":6,"forks_count":2,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2025-06-13T08:04:13.116Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SelfKeyFoundation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-19T09:31:54.000Z","updated_at":"2020-09-07T05:39:16.000Z","dependencies_parsed_at":null,"dependency_job_id":"77750fcf-7780-48f0-b49e-797128c5fb4e","html_url":"https://github.com/SelfKeyFoundation/selfkey-main-contracts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SelfKeyFoundation/selfkey-main-contracts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SelfKeyFoundation%2Fselfkey-main-contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SelfKeyFoundation%2Fselfkey-main-contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SelfKeyFoundation%2Fselfkey-main-contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SelfKeyFoundation%2Fselfkey-main-contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SelfKeyFoundation","download_url":"https://codeload.github.com/SelfKeyFoundation/selfkey-main-contracts/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SelfKeyFoundation%2Fselfkey-main-contracts/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259606868,"owners_count":22883556,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-13T02:55:32.811Z","updated_at":"2025-06-13T08:05:52.653Z","avatar_url":"https://github.com/SelfKeyFoundation.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# selfkey-main-contracts\n\nSmart contracts implementing core functionality of the SelfKey network.\n\n* `develop` — [![codecov](https://codecov.io/gh/SelfKeyFoundation/selfkey-main-contracts/branch/develop/graph/badge.svg)](https://codecov.io/gh/SelfKeyFoundation/selfkey-main-contracts)\n* `master` — [![codecov](https://codecov.io/gh/SelfKeyFoundation/selfkey-main-contracts/branch/master/graph/badge.svg)](https://codecov.io/gh/SelfKeyFoundation/selfkey-main-contracts)\n\n## Overview\n\nTo date, there are 2 smart contracts implemented as part of the SelfKey main project:\n\n* SelfKeyMain.sol\n* PaymentSplitter.sol\n\n### SelfKeyMain.sol\n\n`SelfKeyMain` is designed to provide on-chain support for general functionality specific to the SelfKey\nplatform, such as affiliate and vendor registration. Also, it works as a central address directory that other\ncontracts or applications can query.\n\n`SelfkeyMain` implements the `WhitelistedRole` pattern by OpenZeppelin. i.e. there are 2 permissioning levels:\n\n* `WhitelistedAdmin`: can manage whitelisted addresses and execute methods with `onlyWhitelistAdmin` modifier.\n* `Whitelisted`: can execute methods with `onlyWhitelisted` modifier.\n\nDirectory operations such as adding or changing addresses can be performed by `onlyWhitelistAdmin`. Methods for\nmanaging vendors and affiliates can be executed by `onlyWhitelisted`.\n\nThis contract interacts with [SelfKey DID Ledger](https://github.com/SelfKeyFoundation/selfkey-did-ledger).\n\n#### SelfKeyMain Method Interface\n\nThe following functions are implemented by the SelfKeyMain contract:\n\n**As address directory:**\n\n* `setAddress(bytes32 key, address _address)` (onlyWhitelistAdmin)\n* `getAddress(bytes32 key)`\n\n**Access management (onlyWhitelisted):**\n\n* `registerAffiliate(bytes32 affiliateID)`\n* `registerVendor(bytes32 vendorID)`\n* `removeAffiliate(bytes32 affiliateID)`\n* `removeVendor(bytes32 vendorID)`\n* `addAffiliateConnection(bytes32 user, bytes32 affiliate) public onlyWhitelisted`\n* `removeAffiliateConnection(bytes32 user) public onlyWhitelisted`\n\n**DIDLedger middleware:**\n\n* `createDID(bytes32 affiliateID) returns (bytes32)`\n* `resolveDID(bytes32 did) returns (address)`\n\n**Note:** Although transactions can be made directly on the DID Ledger, creating DIDs through the `SelfKeyMain`\nserves the purpose of potential connecting to an affiliate, and this functionality might be improved to create\nmore complex identity setups (e.g. ERC725) before creating the DID on the ledger.\n\n**This contract is planned to be upgradable via ZeppelinOS, yet the current version (1.0.0) still doesn't implement upgradability.**\n\n### PaymentSplitter.sol\n\n`PaymentSplitter` is a contract that receives a payment from a sender DID to a recipient DID. It checks for\npossible affiliate relationships stored on the `SelfKeyMain` instance, and performs splitting of funds\naccording to percentages specified by the caller. _Service providers have to check if the payment and\naffiliate splitting were done correctly_.\n\n#### Payment pre-conditions\n\n* Sender must `approve` the payments contract to spend the required amount of tokens.\n* Sender, recipient and potential affiliates must have a valid DID registered on the DID Ledger.\n* Recipient DID is registered as a _Vendor_ on the SelfKeyMain. (i.e. `vendorStatus(did) -\u003e true`)\n* Affiliates are registered as such on the SelfKeyMain. (i.e. `affiliateStatus(did) -\u003e true`) and have a relationship to the sender DID (i.e. `affiliateConnections(senderDID) -\u003e true`)\n\n#### Payment method\n\nPayments are done by invoking the `makePayment` method with the following parameters:\n\n* `bytes32 senderDID`: DID of the sender. The contract checks that transaction sender has control over DID.\n* `bytes32 recipientDID`: DID of the recipient. The contract checks that DID is registered as a Vendor.\n* `uint256 amount`: amount of KEY tokens being sent.\n* `bytes32 purchaseInfo`: 32 byte string describing the product/service and any other relevant info.\n_NOTE: encoding scheme for purchase info hasn't been defined_\n* `uint256 affiliate1Split`: percentage for affiliate level 1.\n* `uint256 affiliate2Split`: percentage for affiliate level 2.\n\n**Note**: Affiliate splitting percentages are not to be defined by the user, but should be pulled from a particular service (e.g. Airtable) by the client, and the payment recipient must verify this setup to prevent users from tampering with these parameters.\n\n#### Example code\n\nThe following examples are using web3 1.0.x using async/await:\n\n**Role registration**\n\n```javascript\n// whitelistedAdmin adds whitelisted address\nawait main.methods.addWhitelisted(whitelisted1).send({ 'from': admin1 })\nconsole.log(await main.methods.isWhitelisted(whitelisted1).call()) // true\n\n// register a DID as a Vendor\nawait main.methods.registerVendor(vendorDID).send({ 'from': whitelisted1 })\nawait main.methods.vendorStatus(vendorDID).call())  // true\n```\n\n**DID creation**:\n\n```javascript\n// user address calls main contract to create DID\nlet tx = await main.methods.createDID(zero).send({ 'from': user1 })\nlet did = tx.events.CreatedSelfKeyDID.returnValues.id\n// verify newly created DID\nconsole.log(ledger.methods.getController(did).call() == user1) // true\n```\n\nIn the previous example, a 32-byte string of `zero` is passed as the _affiliateDID_, but can be used to link\nthe new DID to a valid (previously registered) affiliate:\n\n```javascript\n// create new DID for affiliate\nlet tx = await main.methods.createDID(zero).send({ 'from': affiliate1 })\nlet affiliate1DID = tx.events.CreatedSelfKeyDID.returnValues.id\n\n// previously whitelisted address registers affiliate\nawait main.methods.registerAffiliate(affiliate1DID).send({ 'from': whitelisted1 })\n\n// user creates new DID with affiliate connection\ntx = await main.methods.createDID(affiliate1DID).send({ 'from': user2 })\nlet user2DID = tx.events.CreatedSelfKeyDID.returnValues.id\nconsole.log(await main.methods.affiliateConnections(user2DID).call() == affiliate1DID) // true\n```\n\n**Payment**\n\n```javascript\n// approve payment contract to get amount of tokens from user address\nawait token.methods.approve(payments.address, 999999000000000000000000).send({ 'from': user1 })\nawait payments.methods.makePayment(\n  tokenAddress,\n  user1DID,     // bytes32 senderDID\n  vendorDID,    // bytes32 recipientDID\n  10000,        // uint256 amount\n  info,         // bytes32 purchaseInfo\n  0,            // uint256 affiliate1Split\n  0,            // uint256 affiliate2Split\n).send({ 'from': user1 })\n```\n\n## Development\n\nSmart contracts are implemented using Solidity version `0.5.4`.\n\n### Prerequisites\n\n* [NodeJS](htps://nodejs.org), version 9.5+\n* [truffle](http://truffleframework.com/), which is a comprehensive framework for Ethereum development. `npm install -g truffle` — this should install the latest truffle version.\n\n### Initialization\n\n    npm install\n\n### Testing\n\nTruffle testing requires a `ganache-cli` instance running. Some tests require more than 10 accounts, therefore\nthe number of accounts should be specified (e.g. run ganache with 12 generated accounts):\n\n    ganache-cli -a 12\n\n#### Standalone\n\n    npm test\n\nor with code coverage (doesn't require ganache)\n\n    npm run test:cov\n\n#### From within Truffle\n\nRun the `truffle` development environment\n\n    truffle develop\n\nthen from the prompt you can run\n\n    compile\n    migrate\n    test\n\nas well as other Truffle commands. See [truffleframework.com](http://truffleframework.com) for more.\n\n### Linting\n\nWe provide the following linting command for inspecting solidity contracts.\n\n* `npm run lint:sol` — to lint the Solidity files, and\n\n## Contributing\n\nPlease see the [contributing notes](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfkeyfoundation%2Fselfkey-main-contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselfkeyfoundation%2Fselfkey-main-contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselfkeyfoundation%2Fselfkey-main-contracts/lists"}