{"action":"created","comment":{"url":"https://api.github.com/repos/gnosis/safe-modules/pulls/comments/237822501","pull_request_review_id":180216025,"id":237822501,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzNzgyMjUwMQ==","diff_hunk":"@@ -0,0 +1,417 @@\n+pragma solidity 0.4.24;\n+\n+import \"../base/Module.sol\";\n+import \"../base/ModuleManager.sol\";\n+import \"../base/OwnerManager.sol\";\n+import \"../common/Enum.sol\";\n+import \"../common/SignatureDecoder.sol\";\n+import \"../common/SecuredTokenTransfer.sol\";\n+\n+import \"@gnosis.pm/dx-contracts/contracts/DutchExchange.sol\";\n+import \"@gnosis.pm/dx-contracts/contracts/Oracle/PriceOracleInterface.sol\";\n+import \"openzeppelin-solidity/contracts/math/SafeMath.sol\";\n+\n+\n+/// @title Transfer Limit Module - Allows to transfer limited amounts of ERC20 tokens and Ether.\n+contract TransferLimitModule is Module, SignatureDecoder, SecuredTokenTransfer {\n+    string public constant NAME = \"Transfer Limit Module\";\n+    string public constant VERSION = \"0.0.2\";\n+\n+    // transferLimits mapping maps token address to transfer limit settings.\n+    mapping (address => TransferLimit) public transferLimits;\n+\n+    // Time period for which the transfer limits apply, in seconds.\n+    uint256 public timePeriod;\n+\n+    // Start of the time period, during which the last transfer occured (common for all tokens).\n+    uint256 public lastStartTime;\n+\n+    // If true, the expenditure between [now - timePeriod, now] will be considered.\n+    bool public rolling;\n+\n+    // Global limit on all transfers, specified in Wei.\n+    uint256 public globalWeiCap;\n+\n+    // Total amount of Wei spent in current time period.\n+    uint256 public totalWeiSpent;\n+\n+    // Global limit on transfers, specified in usd (dai).\n+    uint256 public globalDaiCap;\n+\n+    // Total amount of dai spent in current time period.\n+    uint256 public totalDaiSpent;\n+\n+    // Number of required confirmations for a transfer.\n+    uint256 public threshold;\n+\n+    uint256 public nonce;\n+\n+    // Non-owner address who is allowed to perform transfers.\n+    address public delegate;\n+\n+    // DutchExchange contract used as price oracle.\n+    DutchExchange dutchx;\n+\n+    struct TransferLimit {\n+        uint256 transferLimit;\n+        uint256 spent;\n+    }\n+\n+    /// @dev Setup function sets initial storage of contract.\n+    /// @param tokens List of token addresses. Ether is represented with address 0x0.\n+    /// @param _transferLimits List of transfer limits in smalles units (e.g. Wei for Ether).\n+    /// @param _timePeriod Time period for which the transfer limits apply, in seconds, between [1 hour, 1 year).\n+    /// @param _rolling If true, the expenditure between [now - timePeriod, now] will be considered.\n+    /// @param _globalWeiCap Global limit on transfers, specified in Wei.\n+    /// @param _globalDaiCap Global limit on transfers, specified in dai.\n+    /// @param _threshold Number of required confirmations, within the range [1, safeThreshold - 1].\n+    /// @param _delegate A non-owner address who is allowed to perform transfers within limits (optional).\n+    /// @param _dutchxAddr Address of DutchX contract, which is used as price oracle.\n+    function setup(\n+        address[] tokens,\n+        uint256[] _transferLimits,\n+        uint256 _timePeriod,\n+        bool _rolling,\n+        uint256 _globalWeiCap,\n+        uint256 _globalDaiCap,\n+        uint256 _threshold,\n+        address _delegate,\n+        address _dutchxAddr\n+    )\n+        public\n+    {\n+        setManager();\n+\n+        // Greater than 1 hour and less than 1 year.\n+        require(isValidTimePeriod(_timePeriod), \"Invalid time period\");\n+        // In the range [1, safeThreshold - 1]\n+        require(isValidThreshold(_threshold), \"Invalid threshold\");\n+        require(_dutchxAddr != 0, \"Invalid dutchx address\");\n+\n+        timePeriod = _timePeriod;\n+        rolling = _rolling;\n+        globalWeiCap = _globalWeiCap;\n+        globalDaiCap = _globalDaiCap;\n+        threshold = _threshold;\n+        delegate = _delegate;\n+        dutchx = DutchExchange(_dutchxAddr);\n+\n+        for (uint256 i = 0; i < tokens.length; i++) {\n+            transferLimits[tokens[i]].transferLimit = _transferLimits[i];\n+        }\n+    }\n+\n+    /// @dev Allows to update the transfer limit for a specified token. This can only be done via a Safe transaction.\n+    /// @param token Token contract address.\n+    /// @param transferLimit Transfer limit in smallest token unit.\n+    function changeTransferLimit(address token, uint256 transferLimit)\n+        public\n+        authorized\n+    {\n+        transferLimits[token].transferLimit = transferLimit;\n+    }\n+\n+    /// @dev Updates the delegate. This can only be done via a Safe transaction.\n+    /// @param _delegate New delegate, who is a non-owner account also allowed to make transfers.\n+    function setDelegate(address _delegate)\n+        public\n+        authorized\n+    {\n+        delegate = _delegate;\n+    }\n+\n+    /// @dev Returns if Safe transaction is a valid transfer limit transaction.\n+    /// @param token Address of the token that should be transfered (0 for Ether)\n+    /// @param to Address to which the tokens should be transfered\n+    /// @param amount Amount of tokens (or Wei) that should be transfered\n+    /// @param safeTxGas Gas that should be used for the Safe transaction.\n+    /// @param dataGas Gas costs for data used to trigger the safe transaction and to pay the payment transfer\n+    /// @param gasPrice Gas price that should be used for the payment calculation.\n+    /// @param gasToken Token address (or 0 if ETH) that is used for the payment.\n+    /// @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin).\n+    /// @param signatures Packed signature data ({bytes32 r}{bytes32 s}{uint8 v})\n+    /// @return Returns if transaction can be executed.\n+    function executeTransferLimit(\n+        address token,\n+        address to,\n+        uint256 amount,\n+        uint256 safeTxGas,\n+        uint256 dataGas,\n+        uint256 gasPrice,\n+        address gasToken,\n+        address refundReceiver,\n+        bytes signatures\n+    )\n+        public\n+    {\n+        require(to != 0, \"Invalid to address provided\");\n+        require(amount > 0, \"Invalid amount provided\");\n+\n+        uint256 startGas = gasleft();\n+        bytes32 txHash = getTransactionHash(\n+            token, to, amount,\n+            safeTxGas, dataGas, gasPrice, gasToken, refundReceiver,\n+            nonce\n+        );\n+        require(checkSignatures(txHash, signatures), \"Invalid signatures provided\");\n+        // Increase nonce and execute transaction.\n+        nonce++;\n+        require(gasleft() >= safeTxGas, \"Not enough gas to execute safe transaction\");\n+\n+        // Validate that transfer is not exceeding transfer limit, and\n+        // update state to keep track of spent values.\n+        require(handleTransferLimits(token, amount), \"Transfer exceeds limits\");\n+\n+        // Perform transfer by invoking manager\n+        if (token == 0) {\n+            require(manager.execTransactionFromModule(to, amount, \"\", Enum.Operation.Call), \"Could not execute ether transfer\");","path":"contracts/TransferLimitModule.sol","position":167,"original_position":167,"commit_id":"78feb8c9e2812e98e7cb728e6f1b80c9ef4a03f5","original_commit_id":"78feb8c9e2812e98e7cb728e6f1b80c9ef4a03f5","user":{"login":"rmeissner","id":2896048,"node_id":"MDQ6VXNlcjI4OTYwNDg=","avatar_url":"https://avatars1.githubusercontent.com/u/2896048?v=4","gravatar_id":"","url":"https://api.github.com/users/rmeissner","html_url":"https://github.com/rmeissner","followers_url":"https://api.github.com/users/rmeissner/followers","following_url":"https://api.github.com/users/rmeissner/following{/other_user}","gists_url":"https://api.github.com/users/rmeissner/gists{/gist_id}","starred_url":"https://api.github.com/users/rmeissner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rmeissner/subscriptions","organizations_url":"https://api.github.com/users/rmeissner/orgs","repos_url":"https://api.github.com/users/rmeissner/repos","events_url":"https://api.github.com/users/rmeissner/events{/privacy}","received_events_url":"https://api.github.com/users/rmeissner/received_events","type":"User","site_admin":false},"body":"In the safe don't revert if the user transaction fails. Would be interesting if that makes sense here too (same for `handleTransferLimits`)\r\n\r\nLets assume somebody submits a transferlimit request but at the same time somebody else transfers out the last tokens from the Safe. Who should be held responsible and cover the gas costs?","created_at":"2018-11-30T10:59:52Z","updated_at":"2018-11-30T10:59:52Z","html_url":"https://github.com/gnosis/safe-modules/pull/2#discussion_r237822501","pull_request_url":"https://api.github.com/repos/gnosis/safe-modules/pulls/2","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/comments/237822501"},"html":{"href":"https://github.com/gnosis/safe-modules/pull/2#discussion_r237822501"},"pull_request":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/gnosis/safe-modules/pulls/2","id":233572776,"node_id":"MDExOlB1bGxSZXF1ZXN0MjMzNTcyNzc2","html_url":"https://github.com/gnosis/safe-modules/pull/2","diff_url":"https://github.com/gnosis/safe-modules/pull/2.diff","patch_url":"https://github.com/gnosis/safe-modules/pull/2.patch","issue_url":"https://api.github.com/repos/gnosis/safe-modules/issues/2","number":2,"state":"open","locked":false,"title":"Transfer limit module","user":{"login":"s1na","id":1591639,"node_id":"MDQ6VXNlcjE1OTE2Mzk=","avatar_url":"https://avatars3.githubusercontent.com/u/1591639?v=4","gravatar_id":"","url":"https://api.github.com/users/s1na","html_url":"https://github.com/s1na","followers_url":"https://api.github.com/users/s1na/followers","following_url":"https://api.github.com/users/s1na/following{/other_user}","gists_url":"https://api.github.com/users/s1na/gists{/gist_id}","starred_url":"https://api.github.com/users/s1na/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/s1na/subscriptions","organizations_url":"https://api.github.com/users/s1na/orgs","repos_url":"https://api.github.com/users/s1na/repos","events_url":"https://api.github.com/users/s1na/events{/privacy}","received_events_url":"https://api.github.com/users/s1na/received_events","type":"User","site_admin":false},"body":"This PR  implements the [TransferLimitModule](https://github.com/GnosisEcosystemFund/Gnosis-Bounties-/issues/1).\r\n\r\nNote: I thought it doesn't make sense to repeat all the common code between this PR and #1 (configs, `Imports.sol`, etc.), as it'd result in merge conflicts. When that one is merged, I'll pull the changes and fix this PR.","created_at":"2018-11-26T14:17:09Z","updated_at":"2018-11-30T10:59:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1d171d86db549657dac1676b4cdee49cc6a3e41e","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/gnosis/safe-modules/pulls/2/commits","review_comments_url":"https://api.github.com/repos/gnosis/safe-modules/pulls/2/comments","review_comment_url":"https://api.github.com/repos/gnosis/safe-modules/pulls/comments{/number}","comments_url":"https://api.github.com/repos/gnosis/safe-modules/issues/2/comments","statuses_url":"https://api.github.com/repos/gnosis/safe-modules/statuses/78feb8c9e2812e98e7cb728e6f1b80c9ef4a03f5","head":{"label":"s1na:master","ref":"master","sha":"78feb8c9e2812e98e7cb728e6f1b80c9ef4a03f5","user":{"login":"s1na","id":1591639,"node_id":"MDQ6VXNlcjE1OTE2Mzk=","avatar_url":"https://avatars3.githubusercontent.com/u/1591639?v=4","gravatar_id":"","url":"https://api.github.com/users/s1na","html_url":"https://github.com/s1na","followers_url":"https://api.github.com/users/s1na/followers","following_url":"https://api.github.com/users/s1na/following{/other_user}","gists_url":"https://api.github.com/users/s1na/gists{/gist_id}","starred_url":"https://api.github.com/users/s1na/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/s1na/subscriptions","organizations_url":"https://api.github.com/users/s1na/orgs","repos_url":"https://api.github.com/users/s1na/repos","events_url":"https://api.github.com/users/s1na/events{/privacy}","received_events_url":"https://api.github.com/users/s1na/received_events","type":"User","site_admin":false},"repo":{"id":156691249,"node_id":"MDEwOlJlcG9zaXRvcnkxNTY2OTEyNDk=","name":"safe-modules","full_name":"s1na/safe-modules","private":false,"owner":{"login":"s1na","id":1591639,"node_id":"MDQ6VXNlcjE1OTE2Mzk=","avatar_url":"https://avatars3.githubusercontent.com/u/1591639?v=4","gravatar_id":"","url":"https://api.github.com/users/s1na","html_url":"https://github.com/s1na","followers_url":"https://api.github.com/users/s1na/followers","following_url":"https://api.github.com/users/s1na/following{/other_user}","gists_url":"https://api.github.com/users/s1na/gists{/gist_id}","starred_url":"https://api.github.com/users/s1na/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/s1na/subscriptions","organizations_url":"https://api.github.com/users/s1na/orgs","repos_url":"https://api.github.com/users/s1na/repos","events_url":"https://api.github.com/users/s1na/events{/privacy}","received_events_url":"https://api.github.com/users/s1na/received_events","type":"User","site_admin":false},"html_url":"https://github.com/s1na/safe-modules","description":"A collection of modules that can be used with the Safe contract","fork":true,"url":"https://api.github.com/repos/s1na/safe-modules","forks_url":"https://api.github.com/repos/s1na/safe-modules/forks","keys_url":"https://api.github.com/repos/s1na/safe-modules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/s1na/safe-modules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/s1na/safe-modules/teams","hooks_url":"https://api.github.com/repos/s1na/safe-modules/hooks","issue_events_url":"https://api.github.com/repos/s1na/safe-modules/issues/events{/number}","events_url":"https://api.github.com/repos/s1na/safe-modules/events","assignees_url":"https://api.github.com/repos/s1na/safe-modules/assignees{/user}","branches_url":"https://api.github.com/repos/s1na/safe-modules/branches{/branch}","tags_url":"https://api.github.com/repos/s1na/safe-modules/tags","blobs_url":"https://api.github.com/repos/s1na/safe-modules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/s1na/safe-modules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/s1na/safe-modules/git/refs{/sha}","trees_url":"https://api.github.com/repos/s1na/safe-modules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/s1na/safe-modules/statuses/{sha}","languages_url":"https://api.github.com/repos/s1na/safe-modules/languages","stargazers_url":"https://api.github.com/repos/s1na/safe-modules/stargazers","contributors_url":"https://api.github.com/repos/s1na/safe-modules/contributors","subscribers_url":"https://api.github.com/repos/s1na/safe-modules/subscribers","subscription_url":"https://api.github.com/repos/s1na/safe-modules/subscription","commits_url":"https://api.github.com/repos/s1na/safe-modules/commits{/sha}","git_commits_url":"https://api.github.com/repos/s1na/safe-modules/git/commits{/sha}","comments_url":"https://api.github.com/repos/s1na/safe-modules/comments{/number}","issue_comment_url":"https://api.github.com/repos/s1na/safe-modules/issues/comments{/number}","contents_url":"https://api.github.com/repos/s1na/safe-modules/contents/{+path}","compare_url":"https://api.github.com/repos/s1na/safe-modules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/s1na/safe-modules/merges","archive_url":"https://api.github.com/repos/s1na/safe-modules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/s1na/safe-modules/downloads","issues_url":"https://api.github.com/repos/s1na/safe-modules/issues{/number}","pulls_url":"https://api.github.com/repos/s1na/safe-modules/pulls{/number}","milestones_url":"https://api.github.com/repos/s1na/safe-modules/milestones{/number}","notifications_url":"https://api.github.com/repos/s1na/safe-modules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/s1na/safe-modules/labels{/name}","releases_url":"https://api.github.com/repos/s1na/safe-modules/releases{/id}","deployments_url":"https://api.github.com/repos/s1na/safe-modules/deployments","created_at":"2018-11-08T10:41:41Z","updated_at":"2018-11-26T14:07:37Z","pushed_at":"2018-11-26T14:07:36Z","git_url":"git://github.com/s1na/safe-modules.git","ssh_url":"git@github.com:s1na/safe-modules.git","clone_url":"https://github.com/s1na/safe-modules.git","svn_url":"https://github.com/s1na/safe-modules","homepage":null,"size":81,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"lgpl-3.0","name":"GNU Lesser General Public License v3.0","spdx_id":"LGPL-3.0","url":"https://api.github.com/licenses/lgpl-3.0","node_id":"MDc6TGljZW5zZTEy"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"gnosis:master","ref":"master","sha":"354bb66dc4e1d8ebdb000cd9e477a9631276020c","user":{"login":"gnosis","id":24954468,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI0OTU0NDY4","avatar_url":"https://avatars1.githubusercontent.com/u/24954468?v=4","gravatar_id":"","url":"https://api.github.com/users/gnosis","html_url":"https://github.com/gnosis","followers_url":"https://api.github.com/users/gnosis/followers","following_url":"https://api.github.com/users/gnosis/following{/other_user}","gists_url":"https://api.github.com/users/gnosis/gists{/gist_id}","starred_url":"https://api.github.com/users/gnosis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnosis/subscriptions","organizations_url":"https://api.github.com/users/gnosis/orgs","repos_url":"https://api.github.com/users/gnosis/repos","events_url":"https://api.github.com/users/gnosis/events{/privacy}","received_events_url":"https://api.github.com/users/gnosis/received_events","type":"Organization","site_admin":false},"repo":{"id":156675250,"node_id":"MDEwOlJlcG9zaXRvcnkxNTY2NzUyNTA=","name":"safe-modules","full_name":"gnosis/safe-modules","private":false,"owner":{"login":"gnosis","id":24954468,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI0OTU0NDY4","avatar_url":"https://avatars1.githubusercontent.com/u/24954468?v=4","gravatar_id":"","url":"https://api.github.com/users/gnosis","html_url":"https://github.com/gnosis","followers_url":"https://api.github.com/users/gnosis/followers","following_url":"https://api.github.com/users/gnosis/following{/other_user}","gists_url":"https://api.github.com/users/gnosis/gists{/gist_id}","starred_url":"https://api.github.com/users/gnosis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnosis/subscriptions","organizations_url":"https://api.github.com/users/gnosis/orgs","repos_url":"https://api.github.com/users/gnosis/repos","events_url":"https://api.github.com/users/gnosis/events{/privacy}","received_events_url":"https://api.github.com/users/gnosis/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/gnosis/safe-modules","description":"A collection of modules that can be used with the Safe contract","fork":false,"url":"https://api.github.com/repos/gnosis/safe-modules","forks_url":"https://api.github.com/repos/gnosis/safe-modules/forks","keys_url":"https://api.github.com/repos/gnosis/safe-modules/keys{/key_id}","collaborators_url":"https://api.github.com/repos/gnosis/safe-modules/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/gnosis/safe-modules/teams","hooks_url":"https://api.github.com/repos/gnosis/safe-modules/hooks","issue_events_url":"https://api.github.com/repos/gnosis/safe-modules/issues/events{/number}","events_url":"https://api.github.com/repos/gnosis/safe-modules/events","assignees_url":"https://api.github.com/repos/gnosis/safe-modules/assignees{/user}","branches_url":"https://api.github.com/repos/gnosis/safe-modules/branches{/branch}","tags_url":"https://api.github.com/repos/gnosis/safe-modules/tags","blobs_url":"https://api.github.com/repos/gnosis/safe-modules/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/gnosis/safe-modules/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/gnosis/safe-modules/git/refs{/sha}","trees_url":"https://api.github.com/repos/gnosis/safe-modules/git/trees{/sha}","statuses_url":"https://api.github.com/repos/gnosis/safe-modules/statuses/{sha}","languages_url":"https://api.github.com/repos/gnosis/safe-modules/languages","stargazers_url":"https://api.github.com/repos/gnosis/safe-modules/stargazers","contributors_url":"https://api.github.com/repos/gnosis/safe-modules/contributors","subscribers_url":"https://api.github.com/repos/gnosis/safe-modules/subscribers","subscription_url":"https://api.github.com/repos/gnosis/safe-modules/subscription","commits_url":"https://api.github.com/repos/gnosis/safe-modules/commits{/sha}","git_commits_url":"https://api.github.com/repos/gnosis/safe-modules/git/commits{/sha}","comments_url":"https://api.github.com/repos/gnosis/safe-modules/comments{/number}","issue_comment_url":"https://api.github.com/repos/gnosis/safe-modules/issues/comments{/number}","contents_url":"https://api.github.com/repos/gnosis/safe-modules/contents/{+path}","compare_url":"https://api.github.com/repos/gnosis/safe-modules/compare/{base}...{head}","merges_url":"https://api.github.com/repos/gnosis/safe-modules/merges","archive_url":"https://api.github.com/repos/gnosis/safe-modules/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/gnosis/safe-modules/downloads","issues_url":"https://api.github.com/repos/gnosis/safe-modules/issues{/number}","pulls_url":"https://api.github.com/repos/gnosis/safe-modules/pulls{/number}","milestones_url":"https://api.github.com/repos/gnosis/safe-modules/milestones{/number}","notifications_url":"https://api.github.com/repos/gnosis/safe-modules/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/gnosis/safe-modules/labels{/name}","releases_url":"https://api.github.com/repos/gnosis/safe-modules/releases{/id}","deployments_url":"https://api.github.com/repos/gnosis/safe-modules/deployments","created_at":"2018-11-08T08:35:08Z","updated_at":"2018-11-08T09:05:49Z","pushed_at":"2018-11-29T03:16:45Z","git_url":"git://github.com/gnosis/safe-modules.git","ssh_url":"git@github.com:gnosis/safe-modules.git","clone_url":"https://github.com/gnosis/safe-modules.git","svn_url":"https://github.com/gnosis/safe-modules","homepage":null,"size":74,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2,"mirror_url":null,"archived":false,"open_issues_count":2,"license":{"key":"lgpl-3.0","name":"GNU Lesser General Public License v3.0","spdx_id":"LGPL-3.0","url":"https://api.github.com/licenses/lgpl-3.0","node_id":"MDc6TGljZW5zZTEy"},"forks":2,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/2"},"html":{"href":"https://github.com/gnosis/safe-modules/pull/2"},"issue":{"href":"https://api.github.com/repos/gnosis/safe-modules/issues/2"},"comments":{"href":"https://api.github.com/repos/gnosis/safe-modules/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/gnosis/safe-modules/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/gnosis/safe-modules/statuses/78feb8c9e2812e98e7cb728e6f1b80c9ef4a03f5"}},"author_association":"NONE"}}
{"actor":{"display_login":"rmeissner"}}