{"action":"created","comment":{"url":"https://api.github.com/repos/corda/corda/pulls/comments/173146561","pull_request_review_id":102278276,"id":173146561,"diff_hunk":"@@ -483,3 +500,205 @@ class AmountTransfer<T : Any, P : Any>(val quantityDelta: Long,\n     }\n }\n \n+/**\n+ * Balance represents an amount of some token (currency, asset, etc.), measured in quantity of the smallest\n+ * representable units. The [amount] of a [Balance] may be negative unlike the [quantity] of an [Amount]. In all other\n+ * regards [Balance] behaves like an [Amount]\n+ *\n+ * @property amount the number of tokens as a long value.\n+ * @property displayTokenSize the nominal display unit size of a single token, potentially with trailing decimal display\n+ * places if the scale parameter is non-zero.\n+ * @property token the type of token this is an amount of. This is usually a singleton.\n+ * @param T the type of the token, for example [Currency]. T should implement [TokenizableAssetInfo] if automatic conversion to/from a display format is required.\n+ */\n+@CordaSerializable\n+data class Balance<T : Any>(val amount: Long,","path":"core/src/main/kotlin/net/corda/core/contracts/Amount.kt","position":259,"original_position":259,"commit_id":"6270ba7fd4bfad7aafc651697bef0bf170769444","original_commit_id":"6270ba7fd4bfad7aafc651697bef0bf170769444","user":{"login":"mnesbit","id":20210228,"avatar_url":"https://avatars2.githubusercontent.com/u/20210228?v=4","gravatar_id":"","url":"https://api.github.com/users/mnesbit","html_url":"https://github.com/mnesbit","followers_url":"https://api.github.com/users/mnesbit/followers","following_url":"https://api.github.com/users/mnesbit/following{/other_user}","gists_url":"https://api.github.com/users/mnesbit/gists{/gist_id}","starred_url":"https://api.github.com/users/mnesbit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mnesbit/subscriptions","organizations_url":"https://api.github.com/users/mnesbit/orgs","repos_url":"https://api.github.com/users/mnesbit/repos","events_url":"https://api.github.com/users/mnesbit/events{/privacy}","received_events_url":"https://api.github.com/users/mnesbit/received_events","type":"User","site_admin":false},"body":"There are lots of reasons I did not allow negative Amounts. The main problems are:\r\n1. Negative from who's perspective? Usually a negative value means you owe money to someone else, but amount doesn't know about owners, lenders, etc. Balances are often perspective flipped according to context, which doesn't fit with the need for a single representation we can sign over.\r\n2. Negative quantities are usually asymmetric compared to positive quantities in terms of handling. i.e. we treat debt very differently to holding liquid assets and charge/pay different rates of interest, tax, etc. \r\n3. Amount is tied to tokenized assets in FungibleStates. Allowing people to create states with negative amounts completely breaks the issuer logic and thus even though the total amount is conserved now I can create the appearance of more cash using just Move commands that I sign. In real life this is only possible through loans, which we pay for and have credit risk controls and overdraft limits.\r\n4. The current cash selection and soft-locking code won't handle negative states correctly, so this isn't really usable on FungibleStates and essentially you might as well use your own Integers/Decimal values on your custom state rather than break the platform type.\r\n5. Rounding gets a lot more complicated when we allow negative amounts, so users of conversions to/from decimal  e.g in a payment text box will find it much much harder to not end up with the outputs summing to different amounts from the inputs.\r\n6. Proper representations of Credit and Debt really require inputs from things like interest rate and holiday calendar Oracles and thus need full smart contract and flow support. The Amount type is meant to be a simple building block. I would have been more supportive of a Balance ContractState type that holds Debt and Credit Obligations, but that is a higher order construct that should live in :finance not :core.","created_at":"2018-03-08T12:42:12Z","updated_at":"2018-03-08T12:43:26Z","html_url":"https://github.com/corda/corda/pull/2680#discussion_r173146561","pull_request_url":"https://api.github.com/repos/corda/corda/pulls/2680","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/corda/corda/pulls/comments/173146561"},"html":{"href":"https://github.com/corda/corda/pull/2680#discussion_r173146561"},"pull_request":{"href":"https://api.github.com/repos/corda/corda/pulls/2680"}}},"pull_request":{"url":"https://api.github.com/repos/corda/corda/pulls/2680","id":172061351,"html_url":"https://github.com/corda/corda/pull/2680","diff_url":"https://github.com/corda/corda/pull/2680.diff","patch_url":"https://github.com/corda/corda/pull/2680.patch","issue_url":"https://api.github.com/repos/corda/corda/issues/2680","number":2680,"state":"open","locked":false,"title":"Balance object for negative amounts","user":{"login":"amoothart","id":987236,"avatar_url":"https://avatars3.githubusercontent.com/u/987236?v=4","gravatar_id":"","url":"https://api.github.com/users/amoothart","html_url":"https://github.com/amoothart","followers_url":"https://api.github.com/users/amoothart/followers","following_url":"https://api.github.com/users/amoothart/following{/other_user}","gists_url":"https://api.github.com/users/amoothart/gists{/gist_id}","starred_url":"https://api.github.com/users/amoothart/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/amoothart/subscriptions","organizations_url":"https://api.github.com/users/amoothart/orgs","repos_url":"https://api.github.com/users/amoothart/repos","events_url":"https://api.github.com/users/amoothart/events{/privacy}","received_events_url":"https://api.github.com/users/amoothart/received_events","type":"User","site_admin":false},"body":"Added a `Balance` class similar to the `Amount` class but with support holding negative numbers.\r\n\r\nRefactored out common functionality of `Amount` into an `AbstractAmount` class which both `Amount` and `Balance` inherit from.\r\n\r\nUnit tests, integration tests and IRS sample were tested as part of this pull request.","created_at":"2018-02-28T20:18:45Z","updated_at":"2018-03-08T12:43:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6e0646555b61d929a4c42d5945c3f003faff001f","assignee":null,"assignees":[],"requested_reviewers":[{"login":"sollecitom","id":5455106,"avatar_url":"https://avatars0.githubusercontent.com/u/5455106?v=4","gravatar_id":"","url":"https://api.github.com/users/sollecitom","html_url":"https://github.com/sollecitom","followers_url":"https://api.github.com/users/sollecitom/followers","following_url":"https://api.github.com/users/sollecitom/following{/other_user}","gists_url":"https://api.github.com/users/sollecitom/gists{/gist_id}","starred_url":"https://api.github.com/users/sollecitom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sollecitom/subscriptions","organizations_url":"https://api.github.com/users/sollecitom/orgs","repos_url":"https://api.github.com/users/sollecitom/repos","events_url":"https://api.github.com/users/sollecitom/events{/privacy}","received_events_url":"https://api.github.com/users/sollecitom/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/corda/corda/pulls/2680/commits","review_comments_url":"https://api.github.com/repos/corda/corda/pulls/2680/comments","review_comment_url":"https://api.github.com/repos/corda/corda/pulls/comments{/number}","comments_url":"https://api.github.com/repos/corda/corda/issues/2680/comments","statuses_url":"https://api.github.com/repos/corda/corda/statuses/6270ba7fd4bfad7aafc651697bef0bf170769444","head":{"label":"corda:austin-balance","ref":"austin-balance","sha":"6270ba7fd4bfad7aafc651697bef0bf170769444","user":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"repo":{"id":70137417,"name":"corda","full_name":"corda/corda","owner":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/corda/corda","description":"Corda is a distributed ledger platform designed to record, manage and automate legal agreements between business partners. Designed by (and for) the world's largest financial institutions yet with applications in multiple industries.  It offers a unique response to the privacy and scalability challenges facing decentralised applications.","fork":false,"url":"https://api.github.com/repos/corda/corda","forks_url":"https://api.github.com/repos/corda/corda/forks","keys_url":"https://api.github.com/repos/corda/corda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/corda/corda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/corda/corda/teams","hooks_url":"https://api.github.com/repos/corda/corda/hooks","issue_events_url":"https://api.github.com/repos/corda/corda/issues/events{/number}","events_url":"https://api.github.com/repos/corda/corda/events","assignees_url":"https://api.github.com/repos/corda/corda/assignees{/user}","branches_url":"https://api.github.com/repos/corda/corda/branches{/branch}","tags_url":"https://api.github.com/repos/corda/corda/tags","blobs_url":"https://api.github.com/repos/corda/corda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/corda/corda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/corda/corda/git/refs{/sha}","trees_url":"https://api.github.com/repos/corda/corda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/corda/corda/statuses/{sha}","languages_url":"https://api.github.com/repos/corda/corda/languages","stargazers_url":"https://api.github.com/repos/corda/corda/stargazers","contributors_url":"https://api.github.com/repos/corda/corda/contributors","subscribers_url":"https://api.github.com/repos/corda/corda/subscribers","subscription_url":"https://api.github.com/repos/corda/corda/subscription","commits_url":"https://api.github.com/repos/corda/corda/commits{/sha}","git_commits_url":"https://api.github.com/repos/corda/corda/git/commits{/sha}","comments_url":"https://api.github.com/repos/corda/corda/comments{/number}","issue_comment_url":"https://api.github.com/repos/corda/corda/issues/comments{/number}","contents_url":"https://api.github.com/repos/corda/corda/contents/{+path}","compare_url":"https://api.github.com/repos/corda/corda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/corda/corda/merges","archive_url":"https://api.github.com/repos/corda/corda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/corda/corda/downloads","issues_url":"https://api.github.com/repos/corda/corda/issues{/number}","pulls_url":"https://api.github.com/repos/corda/corda/pulls{/number}","milestones_url":"https://api.github.com/repos/corda/corda/milestones{/number}","notifications_url":"https://api.github.com/repos/corda/corda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/corda/corda/labels{/name}","releases_url":"https://api.github.com/repos/corda/corda/releases{/id}","deployments_url":"https://api.github.com/repos/corda/corda/deployments","created_at":"2016-10-06T08:46:29Z","updated_at":"2018-03-08T08:24:03Z","pushed_at":"2018-03-08T12:42:29Z","git_url":"git://github.com/corda/corda.git","ssh_url":"git@github.com:corda/corda.git","clone_url":"https://github.com/corda/corda.git","svn_url":"https://github.com/corda/corda","homepage":"https://www.corda.net","size":109595,"stargazers_count":1546,"watchers_count":1546,"language":"Kotlin","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":416,"mirror_url":null,"archived":false,"open_issues_count":125,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":416,"open_issues":125,"watchers":1546,"default_branch":"master"}},"base":{"label":"corda:master","ref":"master","sha":"754b87d547c2a7f737a18ae84b64d41947f0d420","user":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"repo":{"id":70137417,"name":"corda","full_name":"corda/corda","owner":{"login":"corda","id":22600631,"avatar_url":"https://avatars1.githubusercontent.com/u/22600631?v=4","gravatar_id":"","url":"https://api.github.com/users/corda","html_url":"https://github.com/corda","followers_url":"https://api.github.com/users/corda/followers","following_url":"https://api.github.com/users/corda/following{/other_user}","gists_url":"https://api.github.com/users/corda/gists{/gist_id}","starred_url":"https://api.github.com/users/corda/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/corda/subscriptions","organizations_url":"https://api.github.com/users/corda/orgs","repos_url":"https://api.github.com/users/corda/repos","events_url":"https://api.github.com/users/corda/events{/privacy}","received_events_url":"https://api.github.com/users/corda/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/corda/corda","description":"Corda is a distributed ledger platform designed to record, manage and automate legal agreements between business partners. Designed by (and for) the world's largest financial institutions yet with applications in multiple industries.  It offers a unique response to the privacy and scalability challenges facing decentralised applications.","fork":false,"url":"https://api.github.com/repos/corda/corda","forks_url":"https://api.github.com/repos/corda/corda/forks","keys_url":"https://api.github.com/repos/corda/corda/keys{/key_id}","collaborators_url":"https://api.github.com/repos/corda/corda/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/corda/corda/teams","hooks_url":"https://api.github.com/repos/corda/corda/hooks","issue_events_url":"https://api.github.com/repos/corda/corda/issues/events{/number}","events_url":"https://api.github.com/repos/corda/corda/events","assignees_url":"https://api.github.com/repos/corda/corda/assignees{/user}","branches_url":"https://api.github.com/repos/corda/corda/branches{/branch}","tags_url":"https://api.github.com/repos/corda/corda/tags","blobs_url":"https://api.github.com/repos/corda/corda/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/corda/corda/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/corda/corda/git/refs{/sha}","trees_url":"https://api.github.com/repos/corda/corda/git/trees{/sha}","statuses_url":"https://api.github.com/repos/corda/corda/statuses/{sha}","languages_url":"https://api.github.com/repos/corda/corda/languages","stargazers_url":"https://api.github.com/repos/corda/corda/stargazers","contributors_url":"https://api.github.com/repos/corda/corda/contributors","subscribers_url":"https://api.github.com/repos/corda/corda/subscribers","subscription_url":"https://api.github.com/repos/corda/corda/subscription","commits_url":"https://api.github.com/repos/corda/corda/commits{/sha}","git_commits_url":"https://api.github.com/repos/corda/corda/git/commits{/sha}","comments_url":"https://api.github.com/repos/corda/corda/comments{/number}","issue_comment_url":"https://api.github.com/repos/corda/corda/issues/comments{/number}","contents_url":"https://api.github.com/repos/corda/corda/contents/{+path}","compare_url":"https://api.github.com/repos/corda/corda/compare/{base}...{head}","merges_url":"https://api.github.com/repos/corda/corda/merges","archive_url":"https://api.github.com/repos/corda/corda/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/corda/corda/downloads","issues_url":"https://api.github.com/repos/corda/corda/issues{/number}","pulls_url":"https://api.github.com/repos/corda/corda/pulls{/number}","milestones_url":"https://api.github.com/repos/corda/corda/milestones{/number}","notifications_url":"https://api.github.com/repos/corda/corda/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/corda/corda/labels{/name}","releases_url":"https://api.github.com/repos/corda/corda/releases{/id}","deployments_url":"https://api.github.com/repos/corda/corda/deployments","created_at":"2016-10-06T08:46:29Z","updated_at":"2018-03-08T08:24:03Z","pushed_at":"2018-03-08T12:42:29Z","git_url":"git://github.com/corda/corda.git","ssh_url":"git@github.com:corda/corda.git","clone_url":"https://github.com/corda/corda.git","svn_url":"https://github.com/corda/corda","homepage":"https://www.corda.net","size":109595,"stargazers_count":1546,"watchers_count":1546,"language":"Kotlin","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":416,"mirror_url":null,"archived":false,"open_issues_count":125,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":416,"open_issues":125,"watchers":1546,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/corda/corda/pulls/2680"},"html":{"href":"https://github.com/corda/corda/pull/2680"},"issue":{"href":"https://api.github.com/repos/corda/corda/issues/2680"},"comments":{"href":"https://api.github.com/repos/corda/corda/issues/2680/comments"},"review_comments":{"href":"https://api.github.com/repos/corda/corda/pulls/2680/comments"},"review_comment":{"href":"https://api.github.com/repos/corda/corda/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/corda/corda/pulls/2680/commits"},"statuses":{"href":"https://api.github.com/repos/corda/corda/statuses/6270ba7fd4bfad7aafc651697bef0bf170769444"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"mnesbit"}}