diff --git a/artifacts/json/BooleanDecisionEngine.json b/artifacts/json/BooleanDecisionEngine.json new file mode 100644 index 00000000..644fcea5 --- /dev/null +++ b/artifacts/json/BooleanDecisionEngine.json @@ -0,0 +1,235 @@ +{ + "contractName": "BooleanDecisionEngine", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "result", + "type": "bool" + } + ], + "name": "evaluate", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b60b48061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063474e7563146044575b600080fd5b3415604e57600080fd5b606460048080351515906020019091905050607e565b604051808215151515815260200191505060405180910390f35b60008190509190505600a165627a7a723058200d3ae4e28f9bcd4e4f88bc00fa5f9279deb639955e2280adfe27f3970a5ca1f40029", + "deployedBytecode": "0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063474e7563146044575b600080fd5b3415604e57600080fd5b606460048080351515906020019091905050607e565b604051808215151515815260200191505060405180910390f35b60008190509190505600a165627a7a723058200d3ae4e28f9bcd4e4f88bc00fa5f9279deb639955e2280adfe27f3970a5ca1f40029", + "sourceMap": "145:152:22:-;;;;;;;;;;;;;;;;;", + "deployedSourceMap": "145:152:22:-;;;;;;;;;;;;;;;;;;;;;;;;212:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;259:4;282:6;275:13;;212:83;;;:::o", + "source": "import \"zeppelin-solidity/contracts/math/SafeMath.sol\";\n\n\n/**\n * A decision engine that returns true or false, depending on the value given.\n */\ncontract BooleanDecisionEngine {\n using SafeMath for uint;\n\n function evaluate(bool result) public returns (bool) {\n return result;\n }\n}\n", + "sourcePath": "/Users/graemeboy/Dharma/charta/contracts/test/decision_engines/BooleanDecisionEngine.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/graemeboy/Dharma/charta/contracts/test/decision_engines/BooleanDecisionEngine.sol", + "exportedSymbols": { + "BooleanDecisionEngine": [ + 10099 + ] + } + }, + "children": [ + { + "attributes": { + "SourceUnit": 14203, + "absolutePath": "zeppelin-solidity/contracts/math/SafeMath.sol", + "file": "zeppelin-solidity/contracts/math/SafeMath.sol", + "scope": 10100, + "symbolAliases": [ + null + ], + "unitAlias": "" + }, + "id": 10085, + "name": "ImportDirective", + "src": "0:55:22" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "contract", + "documentation": "A decision engine that returns true or false, depending on the value given.", + "fullyImplemented": true, + "linearizedBaseContracts": [ + 10099 + ], + "name": "BooleanDecisionEngine", + "scope": 10100 + }, + "children": [ + { + "children": [ + { + "attributes": { + "contractScope": null, + "name": "SafeMath", + "referencedDeclaration": 14202, + "type": "library SafeMath" + }, + "id": 10086, + "name": "UserDefinedTypeName", + "src": "188:8:22" + }, + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 10087, + "name": "ElementaryTypeName", + "src": "201:4:22" + } + ], + "id": 10088, + "name": "UsingForDirective", + "src": "182:24:22" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "evaluate", + "payable": false, + "scope": 10099, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "result", + "scope": 10098, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 10089, + "name": "ElementaryTypeName", + "src": "230:4:22" + } + ], + "id": 10090, + "name": "VariableDeclaration", + "src": "230:11:22" + } + ], + "id": 10091, + "name": "ParameterList", + "src": "229:13:22" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 10098, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 10092, + "name": "ElementaryTypeName", + "src": "259:4:22" + } + ], + "id": 10093, + "name": "VariableDeclaration", + "src": "259:4:22" + } + ], + "id": 10094, + "name": "ParameterList", + "src": "258:6:22" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 10094 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 10090, + "type": "bool", + "value": "result" + }, + "id": 10095, + "name": "Identifier", + "src": "282:6:22" + } + ], + "id": 10096, + "name": "Return", + "src": "275:13:22" + } + ], + "id": 10097, + "name": "Block", + "src": "265:30:22" + } + ], + "id": 10098, + "name": "FunctionDefinition", + "src": "212:83:22" + } + ], + "id": 10099, + "name": "ContractDefinition", + "src": "145:152:22" + } + ], + "id": 10100, + "name": "SourceUnit", + "src": "0:298:22" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "1.0.1", + "updatedAt": "2018-09-28T20:51:14.888Z" +} \ No newline at end of file diff --git a/artifacts/json/LTVDecisionEngine.json b/artifacts/json/LTVDecisionEngine.json new file mode 100644 index 00000000..4a7b83da --- /dev/null +++ b/artifacts/json/LTVDecisionEngine.json @@ -0,0 +1,1328 @@ +{ + "contractName": "LTVDecisionEngine", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "principalTokenPrice", + "type": "uint256" + }, + { + "name": "collateralTokenPrice", + "type": "uint256" + }, + { + "name": "principalAmount", + "type": "uint256" + }, + { + "name": "collateralAmount", + "type": "uint256" + } + ], + "name": "computeLTV", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "priceFeedOperator", + "type": "address" + }, + { + "name": "creditor", + "type": "address" + }, + { + "name": "principalTokenPrice", + "type": "uint256" + }, + { + "name": "collateralTokenPrice", + "type": "uint256" + }, + { + "name": "principalAmount", + "type": "uint256" + }, + { + "name": "collateralAmount", + "type": "uint256" + }, + { + "name": "maxLTV", + "type": "uint256" + }, + { + "name": "creditorSignature", + "type": "bytes32" + }, + { + "name": "expirationTimestamp", + "type": "uint256" + } + ], + "name": "evaluate", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "errorIndex", + "type": "uint8" + } + ], + "name": "LogError", + "type": "event" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b61021b8061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c2c8c7b514610051578063e62df66c146100a3575b600080fd5b341561005c57600080fd5b61008d6004808035906020019091908035906020019091908035906020019091908035906020019091905050610156565b6040518082815260200191505060405180910390f35b34156100ae57600080fd5b61013c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001909190803590602001909190803590602001909190803560001916906020019091908035906020019091905050610172565b604051808215151515815260200191505060405180910390f35b6000828583860281151561016657fe5b04029050949350505050565b60008061018189898989610156565b9050848111156101dc577f0489f2369368f4688acd012107ac5a7d98ca739b913449d852f35d871e433cc36004808111156101b857fe5b604051808260ff1660ff16815260200191505060405180910390a1600091506101e1565b600191505b5099985050505050505050505600a165627a7a72305820db9c9d87b7059f0bf4c2a9dbd7d8d0190c4c56332c3ed010c860e52f07a2a9790029", + "deployedBytecode": "0x60606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c2c8c7b514610051578063e62df66c146100a3575b600080fd5b341561005c57600080fd5b61008d6004808035906020019091908035906020019091908035906020019091908035906020019091905050610156565b6040518082815260200191505060405180910390f35b34156100ae57600080fd5b61013c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001909190803590602001909190803590602001909190803560001916906020019091908035906020019091905050610172565b604051808215151515815260200191505060405180910390f35b6000828583860281151561016657fe5b04029050949350505050565b60008061018189898989610156565b9050848111156101dc577f0489f2369368f4688acd012107ac5a7d98ca739b913449d852f35d871e433cc36004808111156101b857fe5b604051808260ff1660ff16815260200191505060405180910390a1600091506101e1565b600191505b5099985050505050505050505600a165627a7a72305820db9c9d87b7059f0bf4c2a9dbd7d8d0190c4c56332c3ed010c860e52f07a2a9790029", + "sourceMap": "329:2474:14:-;;;700:46;;;;;;;;329:2474;;;;;;", + "deployedSourceMap": "329:2474:14:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2527:274;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1407:1114;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2527:274;2692:4;2779:15;2757:19;2738:16;2715:20;:39;:61;;;;;;;;:79;2708:86;;2527:274;;;;;;:::o;1407:1114::-;1744:4;2207:13;2223:146;2247:19;2280:20;2314:15;2343:16;2223:10;:146::i;:::-;2207:162;;2395:6;2384:8;:17;2380:113;;;2417:39;2432:22;2426:29;;;;;;;;2417:39;;;;;;;;;;;;;;;;;;;;;;2477:5;2470:12;;;;2380:113;2510:4;2503:11;;1407:1114;;;;;;;;;;;;;:::o", + "source": "import \"zeppelin-solidity/contracts/math/SafeMath.sol\";\n\n/**\n * A decision engine for creditor-driven loans, that can evaluate whether or not a creditor\n * should fill a loan, depending on the loan-to-value ratio of the principal and collateral amounts.\n * These amounts are defined by prices that are signed by the relayer.\n */\ncontract LTVDecisionEngine {\n using SafeMath for uint;\n\n enum Errors {\n INVALID_CREDITOR_SIGNATURE,\n INVALID_PRINCIPAL_PRICE_SIGNATURE,\n INVALID_COLLATERAL_PRICE_SIGNATURE,\n AGREEMENT_EXPIRED,\n LTV_EXCEEDS_MAX\n }\n\n event LogError(\n // Corresponds to the Errors enum listed above.\n uint8 errorIndex\n );\n\n function LTVDecisionEngine()\n public {}\n\n // Required params:\n // Creditor address\n // LTV ratio\n // Price feed operator address\n // Price of principal token\n // price of collateral token\n // Signature and date for principal token price\n // Signature and date for collateral token price\n // Expiration date\n // Decision engine address\n // Signature for creditor on:\n // LTV ratio\n // Price feed operator\n // Principal token\n // Collateral token\n // Principal amount\n // Expiration date\n // Decision engine address\n // NOTE: Decision engine address is used in the CreditorProxy, but signature is validated here.\n function evaluate(\n address priceFeedOperator,\n address creditor,\n uint principalTokenPrice,\n uint collateralTokenPrice,\n uint principalAmount,\n uint collateralAmount,\n uint maxLTV,\n bytes32 creditorSignature,\n uint expirationTimestamp\n )\n public\n returns (bool) {\n // CHECK SIGNATURES\n // Get the address of the price feed operator.\n // Check that the price feed operator has signed the principal token price, recently enough.\n // Check that the price feed operator has signed the collateral token price, recently enough.\n // Get the creditor address.\n // Check that the creditor signed the hash of relevant parameters (outlined above.)\n\n // CHECK EXPIRATIONAl\n\n uint givenLTV = computeLTV(\n principalTokenPrice,\n collateralTokenPrice,\n principalAmount,\n collateralAmount\n );\n\n if (givenLTV > maxLTV) {\n LogError(uint8(Errors.LTV_EXCEEDS_MAX));\n return false;\n }\n\n return true;\n }\n\n function computeLTV(\n uint principalTokenPrice,\n uint collateralTokenPrice,\n uint principalAmount,\n uint collateralAmount\n ) returns (uint) {\n return collateralTokenPrice * collateralAmount / principalTokenPrice * principalAmount;\n }\n}\n", + "sourcePath": "/Users/graemeboy/Dharma/charta/contracts/decision_engines/LTVDecisionEngine.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/graemeboy/Dharma/charta/contracts/decision_engines/LTVDecisionEngine.sol", + "exportedSymbols": { + "LTVDecisionEngine": [ + 5297 + ] + } + }, + "children": [ + { + "attributes": { + "SourceUnit": 14203, + "absolutePath": "zeppelin-solidity/contracts/math/SafeMath.sol", + "file": "zeppelin-solidity/contracts/math/SafeMath.sol", + "scope": 5298, + "symbolAliases": [ + null + ], + "unitAlias": "" + }, + "id": 5208, + "name": "ImportDirective", + "src": "0:55:14" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "contract", + "documentation": "A decision engine for creditor-driven loans, that can evaluate whether or not a creditor\nshould fill a loan, depending on the loan-to-value ratio of the principal and collateral amounts.\nThese amounts are defined by prices that are signed by the relayer.", + "fullyImplemented": true, + "linearizedBaseContracts": [ + 5297 + ], + "name": "LTVDecisionEngine", + "scope": 5298 + }, + "children": [ + { + "children": [ + { + "attributes": { + "contractScope": null, + "name": "SafeMath", + "referencedDeclaration": 14202, + "type": "library SafeMath" + }, + "id": 5209, + "name": "UserDefinedTypeName", + "src": "368:8:14" + }, + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5210, + "name": "ElementaryTypeName", + "src": "381:4:14" + } + ], + "id": 5211, + "name": "UsingForDirective", + "src": "362:24:14" + }, + { + "attributes": { + "canonicalName": "LTVDecisionEngine.Errors", + "name": "Errors" + }, + "children": [ + { + "attributes": { + "name": "INVALID_CREDITOR_SIGNATURE" + }, + "id": 5212, + "name": "EnumValue", + "src": "414:26:14" + }, + { + "attributes": { + "name": "INVALID_PRINCIPAL_PRICE_SIGNATURE" + }, + "id": 5213, + "name": "EnumValue", + "src": "450:33:14" + }, + { + "attributes": { + "name": "INVALID_COLLATERAL_PRICE_SIGNATURE" + }, + "id": 5214, + "name": "EnumValue", + "src": "493:34:14" + }, + { + "attributes": { + "name": "AGREEMENT_EXPIRED" + }, + "id": 5215, + "name": "EnumValue", + "src": "537:17:14" + }, + { + "attributes": { + "name": "LTV_EXCEEDS_MAX" + }, + "id": 5216, + "name": "EnumValue", + "src": "564:15:14" + } + ], + "id": 5217, + "name": "EnumDefinition", + "src": "392:193:14" + }, + { + "attributes": { + "anonymous": false, + "name": "LogError" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "indexed": false, + "name": "errorIndex", + "scope": 5221, + "stateVariable": false, + "storageLocation": "default", + "type": "uint8", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint8", + "type": "uint8" + }, + "id": 5218, + "name": "ElementaryTypeName", + "src": "671:5:14" + } + ], + "id": 5219, + "name": "VariableDeclaration", + "src": "671:16:14" + } + ], + "id": 5220, + "name": "ParameterList", + "src": "605:88:14" + } + ], + "id": 5221, + "name": "EventDefinition", + "src": "591:103:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": true, + "modifiers": [ + null + ], + "name": "LTVDecisionEngine", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 5222, + "name": "ParameterList", + "src": "726:2:14" + }, + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 5223, + "name": "ParameterList", + "src": "744:0:14" + }, + { + "attributes": { + "statements": [ + null + ] + }, + "children": [], + "id": 5224, + "name": "Block", + "src": "744:2:14" + } + ], + "id": 5225, + "name": "FunctionDefinition", + "src": "700:46:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "evaluate", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "priceFeedOperator", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 5226, + "name": "ElementaryTypeName", + "src": "1434:7:14" + } + ], + "id": 5227, + "name": "VariableDeclaration", + "src": "1434:25:14" + }, + { + "attributes": { + "constant": false, + "name": "creditor", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 5228, + "name": "ElementaryTypeName", + "src": "1469:7:14" + } + ], + "id": 5229, + "name": "VariableDeclaration", + "src": "1469:16:14" + }, + { + "attributes": { + "constant": false, + "name": "principalTokenPrice", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5230, + "name": "ElementaryTypeName", + "src": "1495:4:14" + } + ], + "id": 5231, + "name": "VariableDeclaration", + "src": "1495:24:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralTokenPrice", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5232, + "name": "ElementaryTypeName", + "src": "1529:4:14" + } + ], + "id": 5233, + "name": "VariableDeclaration", + "src": "1529:25:14" + }, + { + "attributes": { + "constant": false, + "name": "principalAmount", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5234, + "name": "ElementaryTypeName", + "src": "1564:4:14" + } + ], + "id": 5235, + "name": "VariableDeclaration", + "src": "1564:20:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralAmount", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5236, + "name": "ElementaryTypeName", + "src": "1594:4:14" + } + ], + "id": 5237, + "name": "VariableDeclaration", + "src": "1594:21:14" + }, + { + "attributes": { + "constant": false, + "name": "maxLTV", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5238, + "name": "ElementaryTypeName", + "src": "1625:4:14" + } + ], + "id": 5239, + "name": "VariableDeclaration", + "src": "1625:11:14" + }, + { + "attributes": { + "constant": false, + "name": "creditorSignature", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "bytes32", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bytes32", + "type": "bytes32" + }, + "id": 5240, + "name": "ElementaryTypeName", + "src": "1646:7:14" + } + ], + "id": 5241, + "name": "VariableDeclaration", + "src": "1646:25:14" + }, + { + "attributes": { + "constant": false, + "name": "expirationTimestamp", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5242, + "name": "ElementaryTypeName", + "src": "1681:4:14" + } + ], + "id": 5243, + "name": "VariableDeclaration", + "src": "1681:24:14" + } + ], + "id": 5244, + "name": "ParameterList", + "src": "1424:287:14" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 5245, + "name": "ElementaryTypeName", + "src": "1744:4:14" + } + ], + "id": 5246, + "name": "VariableDeclaration", + "src": "1744:4:14" + } + ], + "id": 5247, + "name": "ParameterList", + "src": "1743:6:14" + }, + { + "children": [ + { + "attributes": { + "assignments": [ + 5249 + ] + }, + "children": [ + { + "attributes": { + "constant": false, + "name": "givenLTV", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5248, + "name": "ElementaryTypeName", + "src": "2207:4:14" + } + ], + "id": 5249, + "name": "VariableDeclaration", + "src": "2207:13:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint256", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5296, + "type": "function (uint256,uint256,uint256,uint256) returns (uint256)", + "value": "computeLTV" + }, + "id": 5250, + "name": "Identifier", + "src": "2223:10:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5231, + "type": "uint256", + "value": "principalTokenPrice" + }, + "id": 5251, + "name": "Identifier", + "src": "2247:19:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5233, + "type": "uint256", + "value": "collateralTokenPrice" + }, + "id": 5252, + "name": "Identifier", + "src": "2280:20:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5235, + "type": "uint256", + "value": "principalAmount" + }, + "id": 5253, + "name": "Identifier", + "src": "2314:15:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5237, + "type": "uint256", + "value": "collateralAmount" + }, + "id": 5254, + "name": "Identifier", + "src": "2343:16:14" + } + ], + "id": 5255, + "name": "FunctionCall", + "src": "2223:146:14" + } + ], + "id": 5256, + "name": "VariableDeclarationStatement", + "src": "2207:162:14" + }, + { + "attributes": { + "falseBody": null + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": ">", + "type": "bool" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5249, + "type": "uint256", + "value": "givenLTV" + }, + "id": 5257, + "name": "Identifier", + "src": "2384:8:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5239, + "type": "uint256", + "value": "maxLTV" + }, + "id": 5258, + "name": "Identifier", + "src": "2395:6:14" + } + ], + "id": 5259, + "name": "BinaryOperation", + "src": "2384:17:14" + }, + { + "children": [ + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "tuple()", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint8", + "typeString": "uint8" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5221, + "type": "function (uint8)", + "value": "LogError" + }, + "id": 5260, + "name": "Identifier", + "src": "2417:8:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": true, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint8", + "type_conversion": true + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_enum$_Errors_$5217", + "typeString": "enum LTVDecisionEngine.Errors" + } + ], + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "type": "type(uint8)", + "value": "uint8" + }, + "id": 5261, + "name": "ElementaryTypeNameExpression", + "src": "2426:5:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "member_name": "LTV_EXCEEDS_MAX", + "referencedDeclaration": null, + "type": "enum LTVDecisionEngine.Errors" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5217, + "type": "type(enum LTVDecisionEngine.Errors)", + "value": "Errors" + }, + "id": 5262, + "name": "Identifier", + "src": "2432:6:14" + } + ], + "id": 5263, + "name": "MemberAccess", + "src": "2432:22:14" + } + ], + "id": 5264, + "name": "FunctionCall", + "src": "2426:29:14" + } + ], + "id": 5265, + "name": "FunctionCall", + "src": "2417:39:14" + } + ], + "id": 5266, + "name": "ExpressionStatement", + "src": "2417:39:14" + }, + { + "attributes": { + "functionReturnParameters": 5247 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "66616c7365", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "false" + }, + "id": 5267, + "name": "Literal", + "src": "2477:5:14" + } + ], + "id": 5268, + "name": "Return", + "src": "2470:12:14" + } + ], + "id": 5269, + "name": "Block", + "src": "2403:90:14" + } + ], + "id": 5270, + "name": "IfStatement", + "src": "2380:113:14" + }, + { + "attributes": { + "functionReturnParameters": 5247 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "74727565", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "true" + }, + "id": 5271, + "name": "Literal", + "src": "2510:4:14" + } + ], + "id": 5272, + "name": "Return", + "src": "2503:11:14" + } + ], + "id": 5273, + "name": "Block", + "src": "1750:771:14" + } + ], + "id": 5274, + "name": "FunctionDefinition", + "src": "1407:1114:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "computeLTV", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "principalTokenPrice", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5275, + "name": "ElementaryTypeName", + "src": "2556:4:14" + } + ], + "id": 5276, + "name": "VariableDeclaration", + "src": "2556:24:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralTokenPrice", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5277, + "name": "ElementaryTypeName", + "src": "2590:4:14" + } + ], + "id": 5278, + "name": "VariableDeclaration", + "src": "2590:25:14" + }, + { + "attributes": { + "constant": false, + "name": "principalAmount", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5279, + "name": "ElementaryTypeName", + "src": "2625:4:14" + } + ], + "id": 5280, + "name": "VariableDeclaration", + "src": "2625:20:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralAmount", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5281, + "name": "ElementaryTypeName", + "src": "2655:4:14" + } + ], + "id": 5282, + "name": "VariableDeclaration", + "src": "2655:21:14" + } + ], + "id": 5283, + "name": "ParameterList", + "src": "2546:136:14" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5284, + "name": "ElementaryTypeName", + "src": "2692:4:14" + } + ], + "id": 5285, + "name": "VariableDeclaration", + "src": "2692:4:14" + } + ], + "id": 5286, + "name": "ParameterList", + "src": "2691:6:14" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 5286 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "*", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "/", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "*", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5278, + "type": "uint256", + "value": "collateralTokenPrice" + }, + "id": 5287, + "name": "Identifier", + "src": "2715:20:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5282, + "type": "uint256", + "value": "collateralAmount" + }, + "id": 5288, + "name": "Identifier", + "src": "2738:16:14" + } + ], + "id": 5289, + "name": "BinaryOperation", + "src": "2715:39:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5276, + "type": "uint256", + "value": "principalTokenPrice" + }, + "id": 5290, + "name": "Identifier", + "src": "2757:19:14" + } + ], + "id": 5291, + "name": "BinaryOperation", + "src": "2715:61:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5280, + "type": "uint256", + "value": "principalAmount" + }, + "id": 5292, + "name": "Identifier", + "src": "2779:15:14" + } + ], + "id": 5293, + "name": "BinaryOperation", + "src": "2715:79:14" + } + ], + "id": 5294, + "name": "Return", + "src": "2708:86:14" + } + ], + "id": 5295, + "name": "Block", + "src": "2698:103:14" + } + ], + "id": 5296, + "name": "FunctionDefinition", + "src": "2527:274:14" + } + ], + "id": 5297, + "name": "ContractDefinition", + "src": "329:2474:14" + } + ], + "id": 5298, + "name": "SourceUnit", + "src": "0:2804:14" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "1.0.1", + "updatedAt": "2018-09-28T20:51:14.517Z" +} \ No newline at end of file diff --git a/artifacts/ts/BooleanDecisionEngine.ts b/artifacts/ts/BooleanDecisionEngine.ts new file mode 100644 index 00000000..847953b6 --- /dev/null +++ b/artifacts/ts/BooleanDecisionEngine.ts @@ -0,0 +1,236 @@ +export const BooleanDecisionEngine = +{ + "contractName": "BooleanDecisionEngine", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "result", + "type": "bool" + } + ], + "name": "evaluate", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b60b48061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063474e7563146044575b600080fd5b3415604e57600080fd5b606460048080351515906020019091905050607e565b604051808215151515815260200191505060405180910390f35b60008190509190505600a165627a7a723058200d3ae4e28f9bcd4e4f88bc00fa5f9279deb639955e2280adfe27f3970a5ca1f40029", + "deployedBytecode": "0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063474e7563146044575b600080fd5b3415604e57600080fd5b606460048080351515906020019091905050607e565b604051808215151515815260200191505060405180910390f35b60008190509190505600a165627a7a723058200d3ae4e28f9bcd4e4f88bc00fa5f9279deb639955e2280adfe27f3970a5ca1f40029", + "sourceMap": "145:152:22:-;;;;;;;;;;;;;;;;;", + "deployedSourceMap": "145:152:22:-;;;;;;;;;;;;;;;;;;;;;;;;212:83;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;259:4;282:6;275:13;;212:83;;;:::o", + "source": "import \"zeppelin-solidity/contracts/math/SafeMath.sol\";\n\n\n/**\n * A decision engine that returns true or false, depending on the value given.\n */\ncontract BooleanDecisionEngine {\n using SafeMath for uint;\n\n function evaluate(bool result) public returns (bool) {\n return result;\n }\n}\n", + "sourcePath": "/Users/graemeboy/Dharma/charta/contracts/test/decision_engines/BooleanDecisionEngine.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/graemeboy/Dharma/charta/contracts/test/decision_engines/BooleanDecisionEngine.sol", + "exportedSymbols": { + "BooleanDecisionEngine": [ + 10099 + ] + } + }, + "children": [ + { + "attributes": { + "SourceUnit": 14203, + "absolutePath": "zeppelin-solidity/contracts/math/SafeMath.sol", + "file": "zeppelin-solidity/contracts/math/SafeMath.sol", + "scope": 10100, + "symbolAliases": [ + null + ], + "unitAlias": "" + }, + "id": 10085, + "name": "ImportDirective", + "src": "0:55:22" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "contract", + "documentation": "A decision engine that returns true or false, depending on the value given.", + "fullyImplemented": true, + "linearizedBaseContracts": [ + 10099 + ], + "name": "BooleanDecisionEngine", + "scope": 10100 + }, + "children": [ + { + "children": [ + { + "attributes": { + "contractScope": null, + "name": "SafeMath", + "referencedDeclaration": 14202, + "type": "library SafeMath" + }, + "id": 10086, + "name": "UserDefinedTypeName", + "src": "188:8:22" + }, + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 10087, + "name": "ElementaryTypeName", + "src": "201:4:22" + } + ], + "id": 10088, + "name": "UsingForDirective", + "src": "182:24:22" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "evaluate", + "payable": false, + "scope": 10099, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "result", + "scope": 10098, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 10089, + "name": "ElementaryTypeName", + "src": "230:4:22" + } + ], + "id": 10090, + "name": "VariableDeclaration", + "src": "230:11:22" + } + ], + "id": 10091, + "name": "ParameterList", + "src": "229:13:22" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 10098, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 10092, + "name": "ElementaryTypeName", + "src": "259:4:22" + } + ], + "id": 10093, + "name": "VariableDeclaration", + "src": "259:4:22" + } + ], + "id": 10094, + "name": "ParameterList", + "src": "258:6:22" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 10094 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 10090, + "type": "bool", + "value": "result" + }, + "id": 10095, + "name": "Identifier", + "src": "282:6:22" + } + ], + "id": 10096, + "name": "Return", + "src": "275:13:22" + } + ], + "id": 10097, + "name": "Block", + "src": "265:30:22" + } + ], + "id": 10098, + "name": "FunctionDefinition", + "src": "212:83:22" + } + ], + "id": 10099, + "name": "ContractDefinition", + "src": "145:152:22" + } + ], + "id": 10100, + "name": "SourceUnit", + "src": "0:298:22" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "1.0.1", + "updatedAt": "2018-09-28T20:51:14.888Z" +} \ No newline at end of file diff --git a/artifacts/ts/LTVDecisionEngine.ts b/artifacts/ts/LTVDecisionEngine.ts new file mode 100644 index 00000000..8a42b2f7 --- /dev/null +++ b/artifacts/ts/LTVDecisionEngine.ts @@ -0,0 +1,1329 @@ +export const LTVDecisionEngine = +{ + "contractName": "LTVDecisionEngine", + "abi": [ + { + "constant": false, + "inputs": [ + { + "name": "principalTokenPrice", + "type": "uint256" + }, + { + "name": "collateralTokenPrice", + "type": "uint256" + }, + { + "name": "principalAmount", + "type": "uint256" + }, + { + "name": "collateralAmount", + "type": "uint256" + } + ], + "name": "computeLTV", + "outputs": [ + { + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "constant": false, + "inputs": [ + { + "name": "priceFeedOperator", + "type": "address" + }, + { + "name": "creditor", + "type": "address" + }, + { + "name": "principalTokenPrice", + "type": "uint256" + }, + { + "name": "collateralTokenPrice", + "type": "uint256" + }, + { + "name": "principalAmount", + "type": "uint256" + }, + { + "name": "collateralAmount", + "type": "uint256" + }, + { + "name": "maxLTV", + "type": "uint256" + }, + { + "name": "creditorSignature", + "type": "bytes32" + }, + { + "name": "expirationTimestamp", + "type": "uint256" + } + ], + "name": "evaluate", + "outputs": [ + { + "name": "", + "type": "bool" + } + ], + "payable": false, + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "payable": false, + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "name": "errorIndex", + "type": "uint8" + } + ], + "name": "LogError", + "type": "event" + } + ], + "bytecode": "0x6060604052341561000f57600080fd5b61021b8061001e6000396000f30060606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c2c8c7b514610051578063e62df66c146100a3575b600080fd5b341561005c57600080fd5b61008d6004808035906020019091908035906020019091908035906020019091908035906020019091905050610156565b6040518082815260200191505060405180910390f35b34156100ae57600080fd5b61013c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001909190803590602001909190803590602001909190803560001916906020019091908035906020019091905050610172565b604051808215151515815260200191505060405180910390f35b6000828583860281151561016657fe5b04029050949350505050565b60008061018189898989610156565b9050848111156101dc577f0489f2369368f4688acd012107ac5a7d98ca739b913449d852f35d871e433cc36004808111156101b857fe5b604051808260ff1660ff16815260200191505060405180910390a1600091506101e1565b600191505b5099985050505050505050505600a165627a7a72305820db9c9d87b7059f0bf4c2a9dbd7d8d0190c4c56332c3ed010c860e52f07a2a9790029", + "deployedBytecode": "0x60606040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c2c8c7b514610051578063e62df66c146100a3575b600080fd5b341561005c57600080fd5b61008d6004808035906020019091908035906020019091908035906020019091908035906020019091905050610156565b6040518082815260200191505060405180910390f35b34156100ae57600080fd5b61013c600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803573ffffffffffffffffffffffffffffffffffffffff1690602001909190803590602001909190803590602001909190803590602001909190803590602001909190803590602001909190803560001916906020019091908035906020019091905050610172565b604051808215151515815260200191505060405180910390f35b6000828583860281151561016657fe5b04029050949350505050565b60008061018189898989610156565b9050848111156101dc577f0489f2369368f4688acd012107ac5a7d98ca739b913449d852f35d871e433cc36004808111156101b857fe5b604051808260ff1660ff16815260200191505060405180910390a1600091506101e1565b600191505b5099985050505050505050505600a165627a7a72305820db9c9d87b7059f0bf4c2a9dbd7d8d0190c4c56332c3ed010c860e52f07a2a9790029", + "sourceMap": "329:2474:14:-;;;700:46;;;;;;;;329:2474;;;;;;", + "deployedSourceMap": "329:2474:14:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2527:274;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1407:1114;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2527:274;2692:4;2779:15;2757:19;2738:16;2715:20;:39;:61;;;;;;;;:79;2708:86;;2527:274;;;;;;:::o;1407:1114::-;1744:4;2207:13;2223:146;2247:19;2280:20;2314:15;2343:16;2223:10;:146::i;:::-;2207:162;;2395:6;2384:8;:17;2380:113;;;2417:39;2432:22;2426:29;;;;;;;;2417:39;;;;;;;;;;;;;;;;;;;;;;2477:5;2470:12;;;;2380:113;2510:4;2503:11;;1407:1114;;;;;;;;;;;;;:::o", + "source": "import \"zeppelin-solidity/contracts/math/SafeMath.sol\";\n\n/**\n * A decision engine for creditor-driven loans, that can evaluate whether or not a creditor\n * should fill a loan, depending on the loan-to-value ratio of the principal and collateral amounts.\n * These amounts are defined by prices that are signed by the relayer.\n */\ncontract LTVDecisionEngine {\n using SafeMath for uint;\n\n enum Errors {\n INVALID_CREDITOR_SIGNATURE,\n INVALID_PRINCIPAL_PRICE_SIGNATURE,\n INVALID_COLLATERAL_PRICE_SIGNATURE,\n AGREEMENT_EXPIRED,\n LTV_EXCEEDS_MAX\n }\n\n event LogError(\n // Corresponds to the Errors enum listed above.\n uint8 errorIndex\n );\n\n function LTVDecisionEngine()\n public {}\n\n // Required params:\n // Creditor address\n // LTV ratio\n // Price feed operator address\n // Price of principal token\n // price of collateral token\n // Signature and date for principal token price\n // Signature and date for collateral token price\n // Expiration date\n // Decision engine address\n // Signature for creditor on:\n // LTV ratio\n // Price feed operator\n // Principal token\n // Collateral token\n // Principal amount\n // Expiration date\n // Decision engine address\n // NOTE: Decision engine address is used in the CreditorProxy, but signature is validated here.\n function evaluate(\n address priceFeedOperator,\n address creditor,\n uint principalTokenPrice,\n uint collateralTokenPrice,\n uint principalAmount,\n uint collateralAmount,\n uint maxLTV,\n bytes32 creditorSignature,\n uint expirationTimestamp\n )\n public\n returns (bool) {\n // CHECK SIGNATURES\n // Get the address of the price feed operator.\n // Check that the price feed operator has signed the principal token price, recently enough.\n // Check that the price feed operator has signed the collateral token price, recently enough.\n // Get the creditor address.\n // Check that the creditor signed the hash of relevant parameters (outlined above.)\n\n // CHECK EXPIRATIONAl\n\n uint givenLTV = computeLTV(\n principalTokenPrice,\n collateralTokenPrice,\n principalAmount,\n collateralAmount\n );\n\n if (givenLTV > maxLTV) {\n LogError(uint8(Errors.LTV_EXCEEDS_MAX));\n return false;\n }\n\n return true;\n }\n\n function computeLTV(\n uint principalTokenPrice,\n uint collateralTokenPrice,\n uint principalAmount,\n uint collateralAmount\n ) returns (uint) {\n return collateralTokenPrice * collateralAmount / principalTokenPrice * principalAmount;\n }\n}\n", + "sourcePath": "/Users/graemeboy/Dharma/charta/contracts/decision_engines/LTVDecisionEngine.sol", + "ast": { + "attributes": { + "absolutePath": "/Users/graemeboy/Dharma/charta/contracts/decision_engines/LTVDecisionEngine.sol", + "exportedSymbols": { + "LTVDecisionEngine": [ + 5297 + ] + } + }, + "children": [ + { + "attributes": { + "SourceUnit": 14203, + "absolutePath": "zeppelin-solidity/contracts/math/SafeMath.sol", + "file": "zeppelin-solidity/contracts/math/SafeMath.sol", + "scope": 5298, + "symbolAliases": [ + null + ], + "unitAlias": "" + }, + "id": 5208, + "name": "ImportDirective", + "src": "0:55:14" + }, + { + "attributes": { + "baseContracts": [ + null + ], + "contractDependencies": [ + null + ], + "contractKind": "contract", + "documentation": "A decision engine for creditor-driven loans, that can evaluate whether or not a creditor\nshould fill a loan, depending on the loan-to-value ratio of the principal and collateral amounts.\nThese amounts are defined by prices that are signed by the relayer.", + "fullyImplemented": true, + "linearizedBaseContracts": [ + 5297 + ], + "name": "LTVDecisionEngine", + "scope": 5298 + }, + "children": [ + { + "children": [ + { + "attributes": { + "contractScope": null, + "name": "SafeMath", + "referencedDeclaration": 14202, + "type": "library SafeMath" + }, + "id": 5209, + "name": "UserDefinedTypeName", + "src": "368:8:14" + }, + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5210, + "name": "ElementaryTypeName", + "src": "381:4:14" + } + ], + "id": 5211, + "name": "UsingForDirective", + "src": "362:24:14" + }, + { + "attributes": { + "canonicalName": "LTVDecisionEngine.Errors", + "name": "Errors" + }, + "children": [ + { + "attributes": { + "name": "INVALID_CREDITOR_SIGNATURE" + }, + "id": 5212, + "name": "EnumValue", + "src": "414:26:14" + }, + { + "attributes": { + "name": "INVALID_PRINCIPAL_PRICE_SIGNATURE" + }, + "id": 5213, + "name": "EnumValue", + "src": "450:33:14" + }, + { + "attributes": { + "name": "INVALID_COLLATERAL_PRICE_SIGNATURE" + }, + "id": 5214, + "name": "EnumValue", + "src": "493:34:14" + }, + { + "attributes": { + "name": "AGREEMENT_EXPIRED" + }, + "id": 5215, + "name": "EnumValue", + "src": "537:17:14" + }, + { + "attributes": { + "name": "LTV_EXCEEDS_MAX" + }, + "id": 5216, + "name": "EnumValue", + "src": "564:15:14" + } + ], + "id": 5217, + "name": "EnumDefinition", + "src": "392:193:14" + }, + { + "attributes": { + "anonymous": false, + "name": "LogError" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "indexed": false, + "name": "errorIndex", + "scope": 5221, + "stateVariable": false, + "storageLocation": "default", + "type": "uint8", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint8", + "type": "uint8" + }, + "id": 5218, + "name": "ElementaryTypeName", + "src": "671:5:14" + } + ], + "id": 5219, + "name": "VariableDeclaration", + "src": "671:16:14" + } + ], + "id": 5220, + "name": "ParameterList", + "src": "605:88:14" + } + ], + "id": 5221, + "name": "EventDefinition", + "src": "591:103:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": true, + "modifiers": [ + null + ], + "name": "LTVDecisionEngine", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 5222, + "name": "ParameterList", + "src": "726:2:14" + }, + { + "attributes": { + "parameters": [ + null + ] + }, + "children": [], + "id": 5223, + "name": "ParameterList", + "src": "744:0:14" + }, + { + "attributes": { + "statements": [ + null + ] + }, + "children": [], + "id": 5224, + "name": "Block", + "src": "744:2:14" + } + ], + "id": 5225, + "name": "FunctionDefinition", + "src": "700:46:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "evaluate", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "priceFeedOperator", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 5226, + "name": "ElementaryTypeName", + "src": "1434:7:14" + } + ], + "id": 5227, + "name": "VariableDeclaration", + "src": "1434:25:14" + }, + { + "attributes": { + "constant": false, + "name": "creditor", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "address", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "address", + "type": "address" + }, + "id": 5228, + "name": "ElementaryTypeName", + "src": "1469:7:14" + } + ], + "id": 5229, + "name": "VariableDeclaration", + "src": "1469:16:14" + }, + { + "attributes": { + "constant": false, + "name": "principalTokenPrice", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5230, + "name": "ElementaryTypeName", + "src": "1495:4:14" + } + ], + "id": 5231, + "name": "VariableDeclaration", + "src": "1495:24:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralTokenPrice", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5232, + "name": "ElementaryTypeName", + "src": "1529:4:14" + } + ], + "id": 5233, + "name": "VariableDeclaration", + "src": "1529:25:14" + }, + { + "attributes": { + "constant": false, + "name": "principalAmount", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5234, + "name": "ElementaryTypeName", + "src": "1564:4:14" + } + ], + "id": 5235, + "name": "VariableDeclaration", + "src": "1564:20:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralAmount", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5236, + "name": "ElementaryTypeName", + "src": "1594:4:14" + } + ], + "id": 5237, + "name": "VariableDeclaration", + "src": "1594:21:14" + }, + { + "attributes": { + "constant": false, + "name": "maxLTV", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5238, + "name": "ElementaryTypeName", + "src": "1625:4:14" + } + ], + "id": 5239, + "name": "VariableDeclaration", + "src": "1625:11:14" + }, + { + "attributes": { + "constant": false, + "name": "creditorSignature", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "bytes32", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bytes32", + "type": "bytes32" + }, + "id": 5240, + "name": "ElementaryTypeName", + "src": "1646:7:14" + } + ], + "id": 5241, + "name": "VariableDeclaration", + "src": "1646:25:14" + }, + { + "attributes": { + "constant": false, + "name": "expirationTimestamp", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5242, + "name": "ElementaryTypeName", + "src": "1681:4:14" + } + ], + "id": 5243, + "name": "VariableDeclaration", + "src": "1681:24:14" + } + ], + "id": 5244, + "name": "ParameterList", + "src": "1424:287:14" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "bool", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "bool", + "type": "bool" + }, + "id": 5245, + "name": "ElementaryTypeName", + "src": "1744:4:14" + } + ], + "id": 5246, + "name": "VariableDeclaration", + "src": "1744:4:14" + } + ], + "id": 5247, + "name": "ParameterList", + "src": "1743:6:14" + }, + { + "children": [ + { + "attributes": { + "assignments": [ + 5249 + ] + }, + "children": [ + { + "attributes": { + "constant": false, + "name": "givenLTV", + "scope": 5274, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5248, + "name": "ElementaryTypeName", + "src": "2207:4:14" + } + ], + "id": 5249, + "name": "VariableDeclaration", + "src": "2207:13:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint256", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5296, + "type": "function (uint256,uint256,uint256,uint256) returns (uint256)", + "value": "computeLTV" + }, + "id": 5250, + "name": "Identifier", + "src": "2223:10:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5231, + "type": "uint256", + "value": "principalTokenPrice" + }, + "id": 5251, + "name": "Identifier", + "src": "2247:19:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5233, + "type": "uint256", + "value": "collateralTokenPrice" + }, + "id": 5252, + "name": "Identifier", + "src": "2280:20:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5235, + "type": "uint256", + "value": "principalAmount" + }, + "id": 5253, + "name": "Identifier", + "src": "2314:15:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5237, + "type": "uint256", + "value": "collateralAmount" + }, + "id": 5254, + "name": "Identifier", + "src": "2343:16:14" + } + ], + "id": 5255, + "name": "FunctionCall", + "src": "2223:146:14" + } + ], + "id": 5256, + "name": "VariableDeclarationStatement", + "src": "2207:162:14" + }, + { + "attributes": { + "falseBody": null + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": ">", + "type": "bool" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5249, + "type": "uint256", + "value": "givenLTV" + }, + "id": 5257, + "name": "Identifier", + "src": "2384:8:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5239, + "type": "uint256", + "value": "maxLTV" + }, + "id": 5258, + "name": "Identifier", + "src": "2395:6:14" + } + ], + "id": 5259, + "name": "BinaryOperation", + "src": "2384:17:14" + }, + { + "children": [ + { + "children": [ + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": false, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "tuple()", + "type_conversion": false + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_uint8", + "typeString": "uint8" + } + ], + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5221, + "type": "function (uint8)", + "value": "LogError" + }, + "id": 5260, + "name": "Identifier", + "src": "2417:8:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": true, + "isStructConstructorCall": false, + "lValueRequested": false, + "names": [ + null + ], + "type": "uint8", + "type_conversion": true + }, + "children": [ + { + "attributes": { + "argumentTypes": [ + { + "typeIdentifier": "t_enum$_Errors_$5217", + "typeString": "enum LTVDecisionEngine.Errors" + } + ], + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "type": "type(uint8)", + "value": "uint8" + }, + "id": 5261, + "name": "ElementaryTypeNameExpression", + "src": "2426:5:14" + }, + { + "attributes": { + "argumentTypes": null, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "member_name": "LTV_EXCEEDS_MAX", + "referencedDeclaration": null, + "type": "enum LTVDecisionEngine.Errors" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5217, + "type": "type(enum LTVDecisionEngine.Errors)", + "value": "Errors" + }, + "id": 5262, + "name": "Identifier", + "src": "2432:6:14" + } + ], + "id": 5263, + "name": "MemberAccess", + "src": "2432:22:14" + } + ], + "id": 5264, + "name": "FunctionCall", + "src": "2426:29:14" + } + ], + "id": 5265, + "name": "FunctionCall", + "src": "2417:39:14" + } + ], + "id": 5266, + "name": "ExpressionStatement", + "src": "2417:39:14" + }, + { + "attributes": { + "functionReturnParameters": 5247 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "66616c7365", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "false" + }, + "id": 5267, + "name": "Literal", + "src": "2477:5:14" + } + ], + "id": 5268, + "name": "Return", + "src": "2470:12:14" + } + ], + "id": 5269, + "name": "Block", + "src": "2403:90:14" + } + ], + "id": 5270, + "name": "IfStatement", + "src": "2380:113:14" + }, + { + "attributes": { + "functionReturnParameters": 5247 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "hexvalue": "74727565", + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "subdenomination": null, + "token": "bool", + "type": "bool", + "value": "true" + }, + "id": 5271, + "name": "Literal", + "src": "2510:4:14" + } + ], + "id": 5272, + "name": "Return", + "src": "2503:11:14" + } + ], + "id": 5273, + "name": "Block", + "src": "1750:771:14" + } + ], + "id": 5274, + "name": "FunctionDefinition", + "src": "1407:1114:14" + }, + { + "attributes": { + "constant": false, + "implemented": true, + "isConstructor": false, + "modifiers": [ + null + ], + "name": "computeLTV", + "payable": false, + "scope": 5297, + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "children": [ + { + "children": [ + { + "attributes": { + "constant": false, + "name": "principalTokenPrice", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5275, + "name": "ElementaryTypeName", + "src": "2556:4:14" + } + ], + "id": 5276, + "name": "VariableDeclaration", + "src": "2556:24:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralTokenPrice", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5277, + "name": "ElementaryTypeName", + "src": "2590:4:14" + } + ], + "id": 5278, + "name": "VariableDeclaration", + "src": "2590:25:14" + }, + { + "attributes": { + "constant": false, + "name": "principalAmount", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5279, + "name": "ElementaryTypeName", + "src": "2625:4:14" + } + ], + "id": 5280, + "name": "VariableDeclaration", + "src": "2625:20:14" + }, + { + "attributes": { + "constant": false, + "name": "collateralAmount", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5281, + "name": "ElementaryTypeName", + "src": "2655:4:14" + } + ], + "id": 5282, + "name": "VariableDeclaration", + "src": "2655:21:14" + } + ], + "id": 5283, + "name": "ParameterList", + "src": "2546:136:14" + }, + { + "children": [ + { + "attributes": { + "constant": false, + "name": "", + "scope": 5296, + "stateVariable": false, + "storageLocation": "default", + "type": "uint256", + "value": null, + "visibility": "internal" + }, + "children": [ + { + "attributes": { + "name": "uint", + "type": "uint256" + }, + "id": 5284, + "name": "ElementaryTypeName", + "src": "2692:4:14" + } + ], + "id": 5285, + "name": "VariableDeclaration", + "src": "2692:4:14" + } + ], + "id": 5286, + "name": "ParameterList", + "src": "2691:6:14" + }, + { + "children": [ + { + "attributes": { + "functionReturnParameters": 5286 + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "*", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "/", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "commonType": { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "operator": "*", + "type": "uint256" + }, + "children": [ + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5278, + "type": "uint256", + "value": "collateralTokenPrice" + }, + "id": 5287, + "name": "Identifier", + "src": "2715:20:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5282, + "type": "uint256", + "value": "collateralAmount" + }, + "id": 5288, + "name": "Identifier", + "src": "2738:16:14" + } + ], + "id": 5289, + "name": "BinaryOperation", + "src": "2715:39:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5276, + "type": "uint256", + "value": "principalTokenPrice" + }, + "id": 5290, + "name": "Identifier", + "src": "2757:19:14" + } + ], + "id": 5291, + "name": "BinaryOperation", + "src": "2715:61:14" + }, + { + "attributes": { + "argumentTypes": null, + "overloadedDeclarations": [ + null + ], + "referencedDeclaration": 5280, + "type": "uint256", + "value": "principalAmount" + }, + "id": 5292, + "name": "Identifier", + "src": "2779:15:14" + } + ], + "id": 5293, + "name": "BinaryOperation", + "src": "2715:79:14" + } + ], + "id": 5294, + "name": "Return", + "src": "2708:86:14" + } + ], + "id": 5295, + "name": "Block", + "src": "2698:103:14" + } + ], + "id": 5296, + "name": "FunctionDefinition", + "src": "2527:274:14" + } + ], + "id": 5297, + "name": "ContractDefinition", + "src": "329:2474:14" + } + ], + "id": 5298, + "name": "SourceUnit", + "src": "0:2804:14" + }, + "compiler": { + "name": "solc", + "version": "0.4.18+commit.9cf6e910.Emscripten.clang" + }, + "networks": {}, + "schemaVersion": "1.0.1", + "updatedAt": "2018-09-28T20:51:14.517Z" +} \ No newline at end of file diff --git a/contracts/decision_engines/LTVDecisionEngine.sol b/contracts/decision_engines/LTVDecisionEngine.sol new file mode 100644 index 00000000..c164835f --- /dev/null +++ b/contracts/decision_engines/LTVDecisionEngine.sol @@ -0,0 +1,164 @@ +pragma solidity 0.4.18; + +import "zeppelin-solidity/contracts/math/SafeMath.sol"; + +/** + * A decision engine for creditor-driven loans, that can evaluate whether or not a creditor + * should fill a loan, depending on the loan-to-value ratio of the principal and collateral amounts. + * These amounts are defined by prices that are signed by the relayer. + */ +contract LTVDecisionEngine { + using SafeMath for uint; + + uint public constant PRECISION = 4; + + enum Errors { + INVALID_CREDITOR_SIGNATURE, + INVALID_PRINCIPAL_PRICE_SIGNATURE, + INVALID_COLLATERAL_PRICE_SIGNATURE, + AGREEMENT_EXPIRED, + LTV_EXCEEDS_MAX + } + + event LogError( + uint8 indexed _errorId + ); + + function LTVDecisionEngine() + public {} + + /** + * Verifies that the correct signatures and data have been passed in. + */ + function verify( + // Creditor commitment. + address creditor, + bytes32 creditorCommitmentHash, + // Price feed operator data. + address priceFeedOperator, + bytes32 principalTokenPriceDataHash, + bytes32 collateralTokenPriceDataHash, + // Signatures + uint8[3] signaturesV, + bytes32[3] signaturesR, + bytes32[3] signaturesS + ) + public + view + returns (bool) + { + // Ensure creditor signature is valid. + if (!isValidSignature( + creditor, + creditorCommitmentHash, + signaturesV[0], + signaturesR[0], + signaturesS[0])) { + LogError(uint8(Errors.INVALID_CREDITOR_SIGNATURE)); + + return false; + } + + // Ensure price feed operator has signed off on the principal token's price. + if (!isValidSignature( + priceFeedOperator, + principalTokenPriceDataHash, + signaturesV[1], + signaturesR[1], + signaturesS[1])) { + LogError(uint8(Errors.INVALID_PRINCIPAL_PRICE_SIGNATURE)); + + return false; + } + + // Ensure price feed operator has signed off on the collateral token's price. + if (!isValidSignature( + priceFeedOperator, + collateralTokenPriceDataHash, + signaturesV[2], + signaturesR[2], + signaturesS[2])) { + LogError(uint8(Errors.INVALID_COLLATERAL_PRICE_SIGNATURE)); + + return false; + } + + return true; + } + + function evaluate( + uint principalTokenPrice, + uint collateralTokenPrice, + uint principalAmount, + uint collateralAmount, + uint maxLTV, + uint expirationTimestampInSec + ) + public + view + returns (bool) { + // Ensure agreement has not expired. + if (isExpired(expirationTimestampInSec)) { + LogError(uint8(Errors.AGREEMENT_EXPIRED)); + + return false; + } + + uint computedLTV = computeLTV( + principalTokenPrice, + collateralTokenPrice, + principalAmount, + collateralAmount + ); + + uint maxLTVWithPrecision = maxLTV.mul(10 ** (PRECISION.sub(2))); + + if (computedLTV > maxLTVWithPrecision) { + LogError(uint8(Errors.LTV_EXCEEDS_MAX)); + + return false; + } + + return true; + } + + function isExpired(uint expirationTimestampInSec) public view returns (bool expired) { + return expirationTimestampInSec < block.timestamp; + } + + function computeLTV( + uint principalTokenPrice, + uint collateralTokenPrice, + uint principalAmount, + uint collateralAmount + ) + public + constant + returns (uint) { + uint principalValue = principalTokenPrice.mul(principalAmount).mul(10 ** PRECISION); + uint collateralValue = collateralTokenPrice.mul(collateralAmount); + + return principalValue.div(collateralValue); + } + + /** + * Given a hashed message, a signer's address, and a signature, + * returns whether the signature is valid. + */ + function isValidSignature( + address signer, + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) + public + pure + returns (bool valid) + { + bytes memory prefix = "\x19Ethereum Signed Message:\n32"; + bytes32 prefixedHash = keccak256(prefix, hash); + return ecrecover(prefixedHash, v, r, s) == signer; + } + +} diff --git a/contracts/test/decision_engines/BooleanDecisionEngine.sol b/contracts/test/decision_engines/BooleanDecisionEngine.sol new file mode 100644 index 00000000..c2283c7b --- /dev/null +++ b/contracts/test/decision_engines/BooleanDecisionEngine.sol @@ -0,0 +1,13 @@ +import "zeppelin-solidity/contracts/math/SafeMath.sol"; + + +/** + * A decision engine that returns true or false, depending on the value given. + */ +contract BooleanDecisionEngine { + using SafeMath for uint; + + function evaluate(bool result) public returns (bool) { + return result; + } +} diff --git a/migrations/9_deploy_ltv_decision_engine.js b/migrations/9_deploy_ltv_decision_engine.js new file mode 100644 index 00000000..91b80c13 --- /dev/null +++ b/migrations/9_deploy_ltv_decision_engine.js @@ -0,0 +1,7 @@ +module.exports = (deployer, network, accounts) => { + const LTVDecisionEngine = artifacts.require("LTVDecisionEngine"); + + return deployer.then(async () => { + await deployer.deploy(LTVDecisionEngine); + }); +}; diff --git a/package-lock.json b/package-lock.json index 28cda1f4..fb4d3fb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "charta", + "name": "@dharmaprotocol/contracts", "version": "0.1.20", "lockfileVersion": 1, "requires": true, @@ -94,8 +94,7 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "2.2.1", @@ -157,6 +156,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, "requires": { "core-js": "2.5.3", "regenerator-runtime": "0.11.1" @@ -216,14 +216,12 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "1.0.0", "concat-map": "0.0.1" @@ -232,8 +230,7 @@ "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, "caller-path": { "version": "0.1.0", @@ -300,7 +297,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, "requires": { "string-width": "1.0.2", "strip-ansi": "3.0.1", @@ -311,7 +307,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -329,8 +324,7 @@ "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { "version": "1.9.1", @@ -350,8 +344,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.0", @@ -367,7 +360,8 @@ "core-js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -410,8 +404,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "deep-is": { "version": "0.1.3", @@ -491,7 +484,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, "requires": { "is-arrayish": "0.2.1" } @@ -781,8 +773,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "functional-red-black-tree": { "version": "1.0.1", @@ -793,8 +784,7 @@ "get-caller-file": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "dev": true + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" }, "get-stream": { "version": "3.0.0", @@ -806,7 +796,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -839,8 +828,7 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "has-ansi": { "version": "2.0.0", @@ -860,8 +848,7 @@ "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" }, "iconv-lite": { "version": "0.4.19", @@ -971,7 +958,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -980,8 +966,7 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "inquirer": { "version": "3.3.0", @@ -1069,20 +1054,17 @@ "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, "requires": { "builtin-modules": "1.1.1" } @@ -1097,7 +1079,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, "requires": { "number-is-nan": "1.0.1" } @@ -1144,6 +1125,11 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1184,11 +1170,26 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "jsonfile": { + "version": "2.4.0", + "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "requires": { + "graceful-fs": "4.1.11" + } + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, "requires": { "invert-kv": "1.0.0" } @@ -1242,6 +1243,11 @@ "path-exists": "3.0.0" } }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -1270,6 +1276,11 @@ "mimic-fn": "1.2.0" } }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -1280,7 +1291,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "1.1.11" } @@ -1322,7 +1332,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, "requires": { "hosted-git-info": "2.5.0", "is-builtin-module": "1.0.0", @@ -1342,8 +1351,7 @@ "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", @@ -1355,7 +1363,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1.0.2" } @@ -1448,8 +1455,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -1487,14 +1493,12 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, "requires": { "pinkie": "2.0.4" } @@ -1585,13 +1589,13 @@ "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-from-string": { "version": "2.0.1", @@ -1602,8 +1606,7 @@ "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "require-uncached": { "version": "1.0.3", @@ -1652,7 +1655,6 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, "requires": { "glob": "7.1.2" } @@ -1690,14 +1692,12 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "shebang-command": { "version": "1.2.0", @@ -1743,11 +1743,178 @@ } } }, + "solc": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.18.tgz", + "integrity": "sha512-Kq+O3PNF9Pfq7fB+lDYAuoqRdghLmZyfngsg0h1Hj38NKAeVHeGPOGeZasn5KqdPeCzbMFvaGyTySxzGv6aXCg==", + "requires": { + "fs-extra": "0.30.0", + "memorystream": "0.3.1", + "require-from-string": "1.2.1", + "semver": "5.5.0", + "yargs": "4.8.1" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "1.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "yargs": { + "version": "4.8.1", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "requires": { + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + } + } + } + }, "spdx-correct": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-2.0.4.tgz", "integrity": "sha512-c+4gPpt9YDhz7cHlz5UrsHzxxRi4ksclxnEEKsuGT9JdwSC+ZNmsGbYRzzgxyZaBYpcWnlu+4lPcdLKx4DOCmA==", - "dev": true, "requires": { "spdx-expression-parse": "2.0.2", "spdx-license-ids": "2.0.1" @@ -1757,7 +1924,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-2.0.2.tgz", "integrity": "sha512-oFxOkWCfFS0ltNp0H66gXlU4NF6bxg7RkoTYR0413t+yTY9zyj+AIWsjtN8dcVp6703ijDYBWBIARlJ7DkyP9Q==", - "dev": true, "requires": { "spdx-exceptions": "2.1.0", "spdx-license-ids": "2.0.1" @@ -1768,14 +1934,12 @@ "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, "requires": { "spdx-exceptions": "2.1.0", "spdx-license-ids": "3.0.0" @@ -1784,16 +1948,14 @@ "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" } } }, "spdx-license-ids": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-2.0.1.tgz", - "integrity": "sha1-AgF7zDU07k/+9tWNIOfT6aHDyOw=", - "dev": true + "integrity": "sha1-AgF7zDU07k/+9tWNIOfT6aHDyOw=" }, "sprintf-js": { "version": "1.0.3", @@ -1847,7 +2009,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, "requires": { "ansi-regex": "2.1.1" } @@ -1954,6 +2115,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/tiny-promisify/-/tiny-promisify-1.0.0.tgz", "integrity": "sha1-MkrrlO1/eKjbNAi5dmaMRv3rwRg=", + "dev": true, "requires": { "babel-runtime": "6.26.0" } @@ -2022,7 +2184,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.2.tgz", "integrity": "sha512-8zlGw3EZDpC7iUDKy4yHCSqFwkBTeAK4h1QqDC3ST6rT7dzvu2ZuclExZN7zuXNEhQ3+2UBQgdca5eNNL06sBg==", - "dev": true, "requires": { "spdx-correct": "2.0.4", "spdx-expression-parse": "3.0.0" @@ -2043,6 +2204,11 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=" + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -2053,7 +2219,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, "requires": { "string-width": "1.0.2", "strip-ansi": "3.0.1" @@ -2063,7 +2228,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -2075,8 +2239,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", @@ -2090,8 +2253,7 @@ "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", - "dev": true + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index ae8f4725..443703e3 100644 --- a/package.json +++ b/package.json @@ -20,16 +20,16 @@ "deploy:kovan": "bash scripts/deploy_kovan.sh", "deploy:mainnet": "bash scripts/deploy_mainnet.sh", "dist": "bash scripts/prepare_dist.sh", - "generate-typings": "abi-gen --abis './build/contracts/*.json' --out './types/generated' --template './types/contract_templates/contract.mustache' --partials './types/contract_templates/partials/*.mustache'", + "generate-typings": "abi-gen --abis './build/contracts/LTVDecisionEngine.json' --out './types/generated' --template './types/contract_templates/contract.mustache' --partials './types/contract_templates/partials/*.mustache'", "transpile": "rm -rf ./transpiled; copyfiles ./build/**/* ./transpiled; tsc", "lint-ts": "tslint migrations/*.ts test/**/*.ts", "lint-sol": "solhint contracts/*.sol contracts/libraries/*.sol contracts/examples/*.sol contracts/test/**/.sol", "lint": "npm run lint-ts; npm run lint-sol", - "compile": "truffle compile --all", - "migrate": "truffle migrate --reset", + "compile": "truffle compile", + "migrate": "truffle migrate --reset -f 9 -to- 9", "prettify": "prettier --write test/ts/**/*.ts types/**/*.ts types/*.ts artifacts/*.ts", "prepublishOnly": "npm run dist", - "test": "npm run compile; npm run generate-typings; npm run transpile; npm run migrate; truffle test", + "test": "npm run compile; npm run generate-typings; npm run transpile; npm run migrate; truffle test transpiled/test/ts/unit/decision_engines/ltv_decision_engine.js", "chain": "ganache-cli --networkId 70 --accounts 20", "validate": "npm ls" }, @@ -41,6 +41,7 @@ "lint" ], "dependencies": { + "solc": "^0.4.18", "zeppelin-solidity": "1.8.0" }, "devDependencies": { diff --git a/test/ts/integration/decision_engines/creditor_proxy_with_bool.ts b/test/ts/integration/decision_engines/creditor_proxy_with_bool.ts new file mode 100644 index 00000000..e1152245 --- /dev/null +++ b/test/ts/integration/decision_engines/creditor_proxy_with_bool.ts @@ -0,0 +1,177 @@ +// External Libraries +import * as ABIDecoder from "abi-decoder"; +import * as Web3 from "web3"; +import * as _ from "lodash"; +import * as chai from "chai"; +import * as moment from "moment"; +import { BigNumber } from "bignumber.js"; + +// Test Utils +import * as Units from "../../test_utils/units"; +import { + multiSigExecuteAfterTimelock, + multiSigExecutePauseImmediately, +} from "../../test_utils/multisig"; +import ChaiSetup from "../../test_utils/chai_setup"; +import { BigNumberSetup } from "../../test_utils/bignumber_setup"; +import { Web3Utils } from "../../../../utils/web3_utils"; + +// Types +import { SignedDebtOffer } from "../../../../types/proxy/debt_offer"; + +// Logs +import { LogApproval, LogTransfer } from "../../logs/debt_token"; +import { LogInsertEntry, LogModifyEntryBeneficiary } from "../../logs/debt_registry"; +import { LogDebtOrderFilled } from "../../logs/debt_kernel"; +import { LogDebtOfferFilled, LogError } from "../../logs/creditor_proxy"; + +// Factories +import { SimpleInterestParameters } from "../../factories/terms_contract_parameters"; +import { DebtOfferFactory } from "../../factories/debt_offer_factory"; + +// Wrappers +import { CreditorProxyContract } from "../../../../types/generated/creditor_proxy"; +import { ContractRegistryContract } from "../../../../types/generated/contract_registry"; +import { CreditorProxyErrorCodes } from "../../../../types/errors"; +import { DebtKernelContract } from "../../../../types/generated/debt_kernel"; +import { DebtRegistryContract } from "../../../../types/generated/debt_registry"; +import { DebtRegistryEntry } from "../../../../types/registry/entry"; +import { DebtTokenContract } from "../../../../types/generated/debt_token"; +import { DummyTokenContract } from "../../../../types/generated/dummy_token"; +import { RepaymentRouterContract } from "../../../../types/generated/repayment_router"; +import { SimpleInterestTermsContractContract } from "../../../../types/generated/simple_interest_terms_contract"; +import { TokenRegistryContract } from "../../../../types/generated/token_registry"; +import { TokenTransferProxyContract } from "../../../../types/generated/token_transfer_proxy"; +import { DharmaMultiSigWalletContract } from "../../../../types/generated/dharma_multi_sig_wallet"; + +// Constants +import { REVERT_ERROR } from "../../test_utils/constants"; + +// Configure BigNumber exponentiation +BigNumberSetup.configure(); + +// Set up Chai +ChaiSetup.configure(); +const expect = chai.expect; + +// Set up utils +const web3Utils = new Web3Utils(web3); + +const creditorProxyArtifacts = artifacts.require("CreditorProxy"); +const debtTokenArtifacts = artifacts.require("DebtToken"); +const debtKernelArtifacts = artifacts.require("DebtKernel"); + +contract("Creditor Proxy with Boolean Decision Engine", async (ACCOUNTS) => { + let creditorProxy: CreditorProxyContract; + let contractRegistry: ContractRegistryContract; + let kernel: DebtKernelContract; + let repaymentRouter: RepaymentRouterContract; + let simpleInterestTermsContract: SimpleInterestTermsContractContract; + let tokenTransferProxy: TokenTransferProxyContract; + let debtTokenContract: DebtTokenContract; + let debtRegistryContract: DebtRegistryContract; + + let dummyREPToken: DummyTokenContract; + + let defaultOfferParams: { [key: string]: any }; + let offerFactory: DebtOfferFactory; + + let multiSig: DharmaMultiSigWalletContract; + + const CONTRACT_OWNER = ACCOUNTS[0]; + const ATTACKER = ACCOUNTS[1]; + const DEBTOR_1 = ACCOUNTS[2]; + const CREDITOR_1 = ACCOUNTS[3]; + const CREDITOR_2 = ACCOUNTS[5]; + const UNDERWRITER = ACCOUNTS[4]; + const RELAYER = ACCOUNTS[6]; + const MALICIOUS_TERMS_CONTRACTS = ACCOUNTS[7]; + const ALTERNATIVE_TOKEN_ADDRESS = ACCOUNTS[8]; + + const NULL_ADDRESS = "0x0000000000000000000000000000000000000000"; + + const TX_DEFAULTS = { from: CONTRACT_OWNER, gas: 4712388 }; + + const reset = async () => { + const dummyTokenRegistryContract = await TokenRegistryContract.deployed(web3, TX_DEFAULTS); + const dummyREPTokenAddress = await dummyTokenRegistryContract.getTokenAddressBySymbol.callAsync( + "REP", + ); + dummyREPToken = await DummyTokenContract.at(dummyREPTokenAddress, web3, TX_DEFAULTS); + + debtTokenContract = await DebtTokenContract.deployed(web3, TX_DEFAULTS); + debtRegistryContract = await DebtRegistryContract.deployed(web3, TX_DEFAULTS); + tokenTransferProxy = await TokenTransferProxyContract.deployed(web3, TX_DEFAULTS); + creditorProxy = await CreditorProxyContract.deployed(web3, TX_DEFAULTS); + contractRegistry = await ContractRegistryContract.deployed(web3, TX_DEFAULTS); + kernel = await DebtKernelContract.deployed(web3, TX_DEFAULTS); + multiSig = await DharmaMultiSigWalletContract.deployed(web3, TX_DEFAULTS); + repaymentRouter = await RepaymentRouterContract.deployed(web3, TX_DEFAULTS); + simpleInterestTermsContract = await SimpleInterestTermsContractContract.deployed( + web3, + TX_DEFAULTS, + ); + + const termsContractParameters = SimpleInterestParameters.pack({ + principalTokenIndex: new BigNumber(0), // Our migrations set REP up to be at index 0 of the registry + principalAmount: Units.ether(1), // principal of 1 ether + interestRateFixedPoint: Units.interestRateFixedPoint(2.5), // interest rate of 2.5% + amortizationUnitType: new BigNumber(1), // The amortization unit type (weekly) + termLengthUnits: new BigNumber(4), // Term length in amortization units. + }); + + const latestBlockTime = await web3Utils.getLatestBlockTime(); + + defaultOfferParams = { + kernelVersion: kernel.address, + creditor: CREDITOR_1, + repaymentRouterVersion: repaymentRouter.address, + debtor: DEBTOR_1, + underwriter: UNDERWRITER, + termsContract: simpleInterestTermsContract.address, + principalToken: dummyREPToken.address, + relayer: RELAYER, + underwriterRiskRating: Units.underwriterRiskRatingFixedPoint(1.35), + principalAmount: Units.ether(1), + underwriterFee: Units.ether(0.0015), + relayerFee: Units.ether(0.0015), + creditorFee: Units.ether(0.002), + debtorFee: Units.ether(0.001), + expirationTimestampInSec: new BigNumber( + moment + .unix(latestBlockTime) + .add(30, "days") + .unix(), + ), + termsContractParameters, + offerSignatories: { debtor: DEBTOR_1, creditor: CREDITOR_1, underwriter: UNDERWRITER }, + }; + + offerFactory = new DebtOfferFactory(defaultOfferParams); + + // Setup ABI decoder in order to decode logs + ABIDecoder.addABI(creditorProxyArtifacts.abi); + ABIDecoder.addABI(debtTokenArtifacts.abi); + ABIDecoder.addABI(debtRegistryContract.abi); + ABIDecoder.addABI(debtKernelArtifacts.abi); + }; + + before(reset); + + after(() => { + // Tear down ABIDecoder before next set of tests + ABIDecoder.removeABI(creditorProxyArtifacts.abi); + }); + + describe("#fillDebtOffer when the decision engine returns true", () => { + it("fills the debt order", () => { + // STUB. + }); + }); + + describe("#fillDebtOffer when the decision engine returns false", () => { + it("does not fill the debt order", () => { + // STUB. + }); + }); +}); diff --git a/test/ts/migrations/9_ltv_decision_engine.ts b/test/ts/migrations/9_ltv_decision_engine.ts new file mode 100644 index 00000000..ee72b00b --- /dev/null +++ b/test/ts/migrations/9_ltv_decision_engine.ts @@ -0,0 +1,39 @@ +import * as chai from "chai"; +import * as Units from "../test_utils/units"; +import { BigNumber } from "bignumber.js"; +import * as Web3 from "web3"; +import * as _ from "lodash"; +import { Web3Utils } from "../../../utils/web3_utils"; + +import { BigNumberSetup } from "../test_utils/bignumber_setup"; +import ChaiSetup from "../test_utils/chai_setup"; + +// Set up Chai +ChaiSetup.configure(); +const expect = chai.expect; + +const web3Utils = new Web3Utils(web3); + +// Configure BigNumber exponentiation +BigNumberSetup.configure(); + +// Dharma Contracts +import { LTVDecisionEngineContract } from "../../../types/generated/l_t_v_decision_engine"; + +contract("Migration #8: Deploy Creditor Proxy", async (ACCOUNTS) => { + const CONTRACT_OWNER = ACCOUNTS[0]; + const TX_DEFAULTS = { from: CONTRACT_OWNER, gas: 4000000 }; + + let decisionEngine: LTVDecisionEngineContract; + + before(async () => { + decisionEngine = await LTVDecisionEngineContract.deployed(web3, TX_DEFAULTS); + }); + + describe("Deployment", () => { + it("should deploy the `LTVDecisionEngine` contract to the current network", async () => { + await expect(web3Utils.doesContractExistAtAddressAsync(decisionEngine.address)).to + .eventually.be.true; + }); + }); +}); diff --git a/test/ts/unit/decision_engines/ltv_creditor_commitment_params.ts b/test/ts/unit/decision_engines/ltv_creditor_commitment_params.ts new file mode 100644 index 00000000..15987018 --- /dev/null +++ b/test/ts/unit/decision_engines/ltv_creditor_commitment_params.ts @@ -0,0 +1,25 @@ +import { BigNumber } from "bignumber.js"; + +import { ECDSASignature } from "../../../../types/kernel/signable_message"; + +import { Bytes32, TxData } from "../../../../types/common"; + +export interface LTVCreditorCommitmentParams { + maxLTV: BigNumber; + priceFeedOperator: string; + decisionEngine: string; + collateralToken: string; + principalToken: string; + principalAmount: BigNumber; + expirationTimestamp: BigNumber; +} + +export interface LTVScenario extends LTVCreditorCommitmentParams { + creditor: string; + principalTokenPrice: BigNumber; + collateralTokenPrice: BigNumber; + collateralAmount: BigNumber; + creditorSignature: ECDSASignature; + txData: TxData; + creditorCommitmentHash: Bytes32; +} diff --git a/test/ts/unit/decision_engines/ltv_decision_engine.ts b/test/ts/unit/decision_engines/ltv_decision_engine.ts new file mode 100644 index 00000000..de71fbdf --- /dev/null +++ b/test/ts/unit/decision_engines/ltv_decision_engine.ts @@ -0,0 +1,367 @@ +// External Libraries +import * as chai from "chai"; +import * as moment from "moment"; +import * as _ from "lodash"; +// Test Utils +import ChaiSetup from "../../test_utils/chai_setup"; +import { BigNumberSetup } from "../../test_utils/bignumber_setup"; +import { Web3Utils } from "../../../../utils/web3_utils"; +import { LTVDecisionEngineContract } from "../../../../types/generated/l_t_v_decision_engine"; +import { BigNumber } from "bignumber.js"; + +import { SignableCreditorCommitment } from "./signable_creditor_commitment"; + +import { PriceScenario, SignablePrice, TimestampedPrice } from "./signable_price"; + +import { LTVCreditorCommitmentParams, LTVScenario } from "./ltv_creditor_commitment_params"; + +// Types +// Logs +// Factories +// Wrappers +// Constants + +// Configure BigNumber exponentiation +BigNumberSetup.configure(); + +// Set up Chai +ChaiSetup.configure(); +const expect = chai.expect; + +// Set up utils +const web3Utils = new Web3Utils(web3); + +async function generateTimestamp(daysInFuture = 30) { + const latestBlockTime = await web3Utils.getLatestBlockTime(); + + return new BigNumber( + moment + .unix(latestBlockTime) + .add(daysInFuture, "days") + .unix(), + ); +} + +contract("LTV Decision Engine (unit)", async (ACCOUNTS) => { + const CONTRACT_OWNER = ACCOUNTS[0]; + const PRICE_FEED_OPERATOR = ACCOUNTS[1]; + const DEBTOR = ACCOUNTS[2]; + const CREDITOR = ACCOUNTS[3]; + + const PRINCIPAL_TOKEN = ACCOUNTS[4]; + const COLLATERAL_TOKEN = ACCOUNTS[5]; + + const TX_DEFAULTS = { from: CONTRACT_OWNER, gas: 4000000 }; + + let decisionEngine: LTVDecisionEngineContract; + + before(async () => { + decisionEngine = await LTVDecisionEngineContract.deployed(web3, TX_DEFAULTS); + }); + + describe("#isExpired", () => { + describe("when given a date in the future", () => { + it("returns false", async () => { + const result = await decisionEngine.isExpired.callAsync( + await generateTimestamp(), + ); + + expect(result).to.eq(false); + }); + }); + + describe("when given a date in the past", () => { + it("returns true", async () => { + const result = await decisionEngine.isExpired.callAsync( + await generateTimestamp(-10), + ); + + expect(result).to.eq(true); + }); + }); + }); + + describe("#isValidSignature", () => { + let validParams: LTVCreditorCommitmentParams; + + before(async () => { + validParams = { + maxLTV: new BigNumber(88), + priceFeedOperator: PRICE_FEED_OPERATOR, + decisionEngine: decisionEngine.address, + collateralToken: COLLATERAL_TOKEN, + principalToken: PRINCIPAL_TOKEN, + principalAmount: new BigNumber(1), + expirationTimestamp: await generateTimestamp(), + }; + }); + + describe("when given a valid signature", () => { + it("returns true", async () => { + const hash = SignableCreditorCommitment.getHashForParams(validParams); + + const commitment = new SignableCreditorCommitment(hash); + + const signature = await commitment.getSignature(web3, CREDITOR); + + const isValid = await decisionEngine.isValidSignature.callAsync( + CREDITOR, + hash, + signature.v, + signature.r, + signature.s, + ); + + expect(isValid).to.eq(true); + }); + }); + + describe("when given an invalid signature", () => { + it("returns false", async () => { + // We will sign these parameters, and pass the signature to #isValidSignature. + const hashForSignedParams = SignableCreditorCommitment.getHashForParams(validParams); + // We will pass this hash to #isValidSignature. + const unsignedParams = _.extend(validParams, { maxLTV: 87 }); + const hashForUnsignedParams = SignableCreditorCommitment.getHashForParams(unsignedParams); + + const commitmentForSignedParams = new SignableCreditorCommitment(hashForSignedParams); + const signature = await commitmentForSignedParams.getSignature(web3, CREDITOR); + + // The incorrect signature is used + const isValid = await decisionEngine.isValidSignature.callAsync( + CREDITOR, + hashForUnsignedParams, + signature.v, + signature.r, + signature.s, + ); + + expect(isValid).to.eq(false); + }); + }); + }); + + describe("#verify", () => { + let scenario: PriceScenario; + + const principalPrice: TimestampedPrice = { + timestamp: new BigNumber( + moment().unix(), + ), + price: new BigNumber(9.15), + }; + + const collateralPrice: TimestampedPrice = { + timestamp: new BigNumber( + moment().unix(), + ), + price: new BigNumber(11.29), + }; + + const signablePrincipalPrice = new SignablePrice(principalPrice); + const signableCollateralPrice = new SignablePrice(collateralPrice); + + before(async () => { + const validParams: LTVCreditorCommitmentParams = { + maxLTV: new BigNumber(88), + priceFeedOperator: PRICE_FEED_OPERATOR, + decisionEngine: decisionEngine.address, + collateralToken: COLLATERAL_TOKEN, + principalToken: PRINCIPAL_TOKEN, + principalAmount: new BigNumber(1), + expirationTimestamp: await generateTimestamp(), + }; + + const creditorCommitmentHash = SignableCreditorCommitment.getHashForParams(validParams); + + const commitment = new SignableCreditorCommitment(creditorCommitmentHash); + + const creditorSignature = await commitment.getSignature(web3, CREDITOR); + const principalSignature = await signablePrincipalPrice.getSignature(web3, PRICE_FEED_OPERATOR); + const collateralSignature = await signableCollateralPrice.getSignature(web3, PRICE_FEED_OPERATOR); + + scenario = { + creditor: CREDITOR, + creditorCommitmentHash, + priceFeedOperator: PRICE_FEED_OPERATOR, + principalTokenPriceDataHash: signablePrincipalPrice.getHash(), + collateralTokenPriceDataHash: signableCollateralPrice.getHash(), + signaturesV: [creditorSignature.v, principalSignature.v, collateralSignature.v], + signaturesR: [creditorSignature.r, principalSignature.r, collateralSignature.r], + signaturesS: [creditorSignature.s, principalSignature.s, collateralSignature.s], + }; + }); + + describe("when given valid signatures", () => { + it("returns true", async () => { + const isVerified = await decisionEngine.verify.callAsync( + scenario.creditor, + scenario.creditorCommitmentHash, + scenario.priceFeedOperator, + scenario.principalTokenPriceDataHash, + scenario.collateralTokenPriceDataHash, + scenario.signaturesV, + scenario.signaturesR, + scenario.signaturesS, + ); + + expect(isVerified).to.eq(true); + }); + }); + }); + + describe("#computeLTV", () => { + describe("when given a principal price of 13 and collateral price of 15", () => { + describe("when given an principal amount of 1 and a collateral price of 1", () => { + it("returns 8666", async () => { + const args = { + principalTokenPrice: new BigNumber(13), + collateralTokenPrice: new BigNumber(15), + principalAmount: new BigNumber(1), + collateralAmount: new BigNumber(1), + }; + + const result = await decisionEngine.computeLTV.callAsync( + args.principalTokenPrice, + args.collateralTokenPrice, + args.principalAmount, + args.collateralAmount, + ); + + expect(result.toString()).to.eq("8666"); + }); + }); + }); + }); + + describe("#evaluate", () => { + let evaluateScenario: LTVScenario; + let defaultCommitmentParams: LTVCreditorCommitmentParams; + + before(async () => { + const timestamp = await generateTimestamp(); + + defaultCommitmentParams = { + priceFeedOperator: PRICE_FEED_OPERATOR, + collateralToken: COLLATERAL_TOKEN, + principalToken: PRINCIPAL_TOKEN, + principalAmount: new BigNumber(1), + maxLTV: new BigNumber(88), + decisionEngine: decisionEngine.address, + expirationTimestamp: timestamp, + }; + }); + + describe("when given a ratio that is lower than the specified LTV", () => { + before(async () => { + const hash = SignableCreditorCommitment.getHashForParams( + defaultCommitmentParams, + ); + + const commitment = new SignableCreditorCommitment(hash); + + const signature = await commitment.getSignature(web3, CREDITOR); + + evaluateScenario = { + ...defaultCommitmentParams, + creditor: CREDITOR, + principalTokenPrice: new BigNumber(13), + collateralTokenPrice: new BigNumber(15), + principalAmount: new BigNumber(1), + collateralAmount: new BigNumber(1), + creditorCommitmentHash: hash, + creditorSignature: signature, + txData: TX_DEFAULTS, + }; + }); + + it("returns true", async () => { + const result = await decisionEngine.evaluate.callAsync( + evaluateScenario.principalTokenPrice, + evaluateScenario.collateralTokenPrice, + evaluateScenario.principalAmount, + evaluateScenario.collateralAmount, + evaluateScenario.maxLTV, + evaluateScenario.expirationTimestamp, + ); + + expect(result).to.eq(true); + }); + }); + + describe("when given a ratio that is higher than the specified LTV", () => { + before(async () => { + const timestamp = await generateTimestamp(); + + const commitmentParams = { + ...defaultCommitmentParams, + maxLTV: new BigNumber(86), + }; + + const hash = SignableCreditorCommitment.getHashForParams( + commitmentParams, + ); + + const commitment = new SignableCreditorCommitment(hash); + + const signature = await commitment.getSignature(web3, CREDITOR); + + evaluateScenario = { + ...commitmentParams, + creditor: CREDITOR, + principalTokenPrice: new BigNumber(13), + collateralTokenPrice: new BigNumber(15), + principalAmount: new BigNumber(1), + collateralAmount: new BigNumber(1), + expirationTimestamp: timestamp, + creditorCommitmentHash: hash, + creditorSignature: signature, + txData: TX_DEFAULTS, + }; + }); + + it("returns false", async () => { + const result = await decisionEngine.evaluate.callAsync( + evaluateScenario.principalTokenPrice, + evaluateScenario.collateralTokenPrice, + evaluateScenario.principalAmount, + evaluateScenario.collateralAmount, + evaluateScenario.maxLTV, + evaluateScenario.expirationTimestamp, + ); + + expect(result).to.eq(false); + }); + }); + + describe("when given a creditor signature that is invalid", () => { + it("returns false", () => { + // STUB. + }); + + it("logs an error that the creditor signature is invalid", () => { + // STUB + }); + }); + + describe("when given a collateral price that is not signed by the price feed operator", () => { + it("reverts", () => { + // STUB. + }); + + it("logs and error that the price was not signed", () => { + // STUB. + }); + }); + + describe("when given a principal price that is not signed by the price feed operator", () => { + it("reverts the transaction", () => { + // STUB + }); + + it("throws an error that the price was not signed", () => { + // STUB. + }); + }); + }); +}); diff --git a/test/ts/unit/decision_engines/signable_creditor_commitment.ts b/test/ts/unit/decision_engines/signable_creditor_commitment.ts new file mode 100644 index 00000000..e89f5757 --- /dev/null +++ b/test/ts/unit/decision_engines/signable_creditor_commitment.ts @@ -0,0 +1,33 @@ +import { Bytes32 } from "../../../../types/common"; + +import { SignableMessage } from "../../../../types/kernel/signable_message"; + +import { LTVCreditorCommitmentParams } from "./ltv_creditor_commitment_params"; + +import * as solidity from "../../../../utils/solidity"; + +import ethUtil = require("ethereumjs-util"); + +export class SignableCreditorCommitment extends SignableMessage { + + public static getHashForParams(params: LTVCreditorCommitmentParams): Bytes32 { + const hash = solidity.SHA3([ + params.maxLTV, + params.priceFeedOperator, + params.principalToken, + params.collateralToken, + params.principalAmount, + params.expirationTimestamp, + params.decisionEngine, + ]); + return ethUtil.bufferToHex(hash); + } + + constructor(private readonly hash: Bytes32) { + super(); + } + + public getHash(): Bytes32 { + return this.hash; + } +} diff --git a/test/ts/unit/decision_engines/signable_price.ts b/test/ts/unit/decision_engines/signable_price.ts new file mode 100644 index 00000000..f0094a28 --- /dev/null +++ b/test/ts/unit/decision_engines/signable_price.ts @@ -0,0 +1,45 @@ +import { BigNumber } from "bignumber.js"; + +import { Bytes32 } from "../../../../types/common"; + +import { SignableMessage } from "../../../../types/kernel/signable_message"; + +import * as solidity from "../../../../utils/solidity"; + +import ethUtil = require("ethereumjs-util"); + +export interface TimestampedPrice { + timestamp: BigNumber; + price: BigNumber; +} + +export interface PriceScenario { + creditor: string; + creditorCommitmentHash: Bytes32; + priceFeedOperator: string; + principalTokenPriceDataHash: Bytes32; + collateralTokenPriceDataHash: Bytes32; + signaturesV: number[]; + signaturesR: Bytes32[]; + signaturesS: Bytes32[]; +} + +export class SignablePrice extends SignableMessage { + + private readonly hash: Bytes32; + + constructor(private readonly params: TimestampedPrice) { + super(); + + const hash = solidity.SHA3([ + params.price, + params.timestamp, + ]); + + this.hash = ethUtil.bufferToHex(hash); + } + + public getHash(): Bytes32 { + return this.hash; + } +} diff --git a/types/kernel/signable_message.ts b/types/kernel/signable_message.ts index 746501d0..ae40c854 100644 --- a/types/kernel/signable_message.ts +++ b/types/kernel/signable_message.ts @@ -12,7 +12,7 @@ export interface ECDSASignature { export abstract class SignableMessage { public abstract getHash(): Bytes32; - protected async getSignature( + public async getSignature( web3: Web3, signer: Address, hash?: Bytes32, diff --git a/yarn.lock b/yarn.lock index 7e30f86c..d3478d0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4589,6 +4589,16 @@ solc@0.4.18: semver "^5.3.0" yargs "^4.7.1" +solc@^0.4.18: + version "0.4.25" + resolved "https://registry.yarnpkg.com/solc/-/solc-0.4.25.tgz#06b8321f7112d95b4b903639b1138a4d292f5faa" + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + solhint@^1.1.8: version "1.1.9" resolved "https://registry.yarnpkg.com/solhint/-/solhint-1.1.9.tgz#d4cf04a72db36ea1536a1f68c8837925f15f827d"